0% ont trouvé ce document utile (0 vote)
2 vues45 pages

Mbds Big Data Hadoop 2019 2020 Cours 2

Transféré par

tiyafa9950
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
2 vues45 pages

Mbds Big Data Hadoop 2019 2020 Cours 2

Transféré par

tiyafa9950
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Hadoop / Big Data

Benjamin Renaut <[Link]@[Link]>

MBDS 2019 - 2020


6 map/reduce et Hadoop: exemples plus avancés
Exemple: parcours de graphe
6-1

● On cherche à déterminer la profondeur maximale de tous les nœuds


d'un graphe à partir d'un nœud de départ (via breadth-first search,
parcours en largeur).

● Le graphe:
Exemple: parcours de graphe
6-2

● Données d'entrée:

(1;"2,5|GRIS|0")
(1;"2,5|GRIS|0")
(2;"3,4|BLANC|-1")
(2;"3,4|BLANC|-1")
(3;"6|BLANC|-1")
(3;"6|BLANC|-1")
(4;"|BLANC|-1")
(4;"|BLANC|-1")
(5;"6|BLANC|-1")
(5;"6|BLANC|-1")
(6;"|BLANC|-1")
(6;"|BLANC|-1")

… avec valeur sur le modèle « NOEUDS_FILS|COULEUR|PROFONDEUR ».

● Et couleur ayant pour valeur « BLANC » pour un nœud non parcouru, « GRIS »
pour un nœud en cours de parcours, et « NOIR » pour un nœud déjà parcouru.
Dans nos données d'entrée, l'unique nœud GRIS indique le nœud de départ.
Exemple: parcours de graphe
6-3

● map: si le nœud du couple (clef;valeur) d'entrée est GRIS, alors:


● Pour chacun de ses fils, retourner (ID_FILS;"|GRIS|PROFONDEUR+1), où

PROFONDEUR est la profondeur du nœud courant.


● Retourner également le couple (clef;valeur) courant, avec couleur=NOIR.

● Sinon: retourner le couple (clef;valeur) d'entrée.

● Pseudo code:

SI
SI [Link]=="GRIS":
[Link]=="GRIS":
POUR
POUR CHAQUE
CHAQUE FILS
FILS DANS
DANS [Link]:
[Link]:
[Link]="GRIS"
[Link]="GRIS"
[Link]=[Link]+1
[Link]=[Link]+1
RENVOYER
RENVOYER ([Link];FILS)
([Link];FILS)
[Link]="NOIR"
[Link]="NOIR"
RENVOYER
RENVOYER ([Link];NODE)
([Link];NODE)
Exemple: parcours de graphe
6-4
● reduce: parcourir chacune des valeurs associées à la clef
unique (après shuffle). Renvoyer un couple (clef;NOEUD)
avec un nœud dont:

● La profondeur est la plus haute rencontrée parmi les


valeurs associées à cette clef unique (l'identifiant du nœud).
● La couleur est la plus « forte » parmi ces mêmes valeurs.
● La liste des nœuds enfants est la plus longue parmi ces
valeurs.

… et pour clef la clef unique en question.


Exemple: parcours de graphe
6-5
● Pseudo H_CHILDREN="";
H_CHILDREN=""; H_PROF=-1;
H_PROF=-1; H_COULEUR="BLANC";
H_COULEUR="BLANC";
code:
POUR
POUR CHAQUE
CHAQUE VALEUR:
VALEUR:
SI
SI [Link]()>H_CHILDREN.LENGTH():
[Link]()>H_CHILDREN.LENGTH():
H_CHILDREN=[Link]
H_CHILDREN=[Link]
SI
SI [Link]>H_PROF:
[Link]>H_PROF:
H_PROF=[Link]
H_PROF=[Link]
SI
SI [Link]>H_COULEUR:
[Link]>H_COULEUR:
H_COULEUR=[Link]
H_COULEUR=[Link]

NODE=NOUVEAU
NODE=NOUVEAU NOEUD
NOEUD
[Link]=H_COULEUR
[Link]=H_COULEUR
[Link]=H_CHILDREN
[Link]=H_CHILDREN
[Link]=H_PROF
[Link]=H_PROF
RENVOYER(CLEF;NODE)
RENVOYER(CLEF;NODE)
Exemple: parcours de graphe
6-6

● On exécute le programme map/reduce plusieurs fois,


jusqu'à ce que tous les nœuds de la liste aient pour
couleur la valeur « NOIR » <=> jusqu'à ce que tous les
nœuds aient été parcourus.

● Ce type de logique s'implémente très facilement au


sein d'un framework map/reduce (Hadoop).
Exemple: parcours de graphe
6-7

● Premier lancement:
Graphe:
Données
d'entrée:
(1;"2,5|GRIS|0")
(1;"2,5|GRIS|0")
(2;"3,4|BLANC|-1")
(2;"3,4|BLANC|-1")
(3;"6|BLANC|-1")
(3;"6|BLANC|-1")
(4;"|BLANC|-1")
(4;"|BLANC|-1")
(5;"6|BLANC|-1")
(5;"6|BLANC|-1")
(6;"|BLANC|-1")
(6;"|BLANC|-1")
Exemple: parcours de graphe
6-8

● Pour ce premier lancement: Aprés shuffle:


Sortie de map: 1:
1: ("2,5|NOIR|0")
("2,5|NOIR|0")
2:
2: ("|GRIS|1"),("3,4|BLANC|-1")
("|GRIS|1"),("3,4|BLANC|-1")
(1;"2,5|NOIR|0")
(1;"2,5|NOIR|0") 3:
3: ("6|BLANC|-1")
("6|BLANC|-1")
(2;"|GRIS|1")
(2;"|GRIS|1") 4:
4: ("|BLANC|-1")
("|BLANC|-1")
(5;"|GRIS|1")
(5;"|GRIS|1") 5:
5: ("|GRIS|1"),("6|BLANC|-1")
("|GRIS|1"),("6|BLANC|-1")
(2;"3,4|BLANC|-1")
(2;"3,4|BLANC|-1") 6:
6: ("|BLANC|-1")
("|BLANC|-1")
(3;"6|BLANC|-1")
(3;"6|BLANC|-1")
(4;"|BLANC|-1")
(4;"|BLANC|-1")
(5;"6|BLANC|-1")
(5;"6|BLANC|-1") (1;"2,5|NOIR|0")
(1;"2,5|NOIR|0")
(6;"|BLANC|-1")
(6;"|BLANC|-1") (2;"3,4|GRIS|1")
(2;"3,4|GRIS|1")
(3;"6|BLANC|-1")
(3;"6|BLANC|-1")
Sortie de (4;"|BLANC|-1")
(4;"|BLANC|-1")
reduce: (5;"6|GRIS|1")
(5;"6|GRIS|1")
(6;"|BLANC|-1")
(6;"|BLANC|-1")
Exemple: parcours de graphe
6-9

● Lancement 2:
Graphe:
Données:
(1;"2,5|NOIR|0")
(1;"2,5|NOIR|0")
(2;"3,4|GRIS|1")
(2;"3,4|GRIS|1")
(3;"6|BLANC|-1")
(3;"6|BLANC|-1")
(4;"|BLANC|-1")
(4;"|BLANC|-1")
(5;"6|GRIS|1")
(5;"6|GRIS|1")
(6;"|BLANC|-1")
(6;"|BLANC|-1")
Exemple: parcours de graphe
6-10

● Lancement 3:
Graphe:
Données:
(1;"2,5|NOIR|0")
(1;"2,5|NOIR|0")
(2;"3,4|NOIR|1")
(2;"3,4|NOIR|1")
(3;"6|GRIS|2")
(3;"6|GRIS|2")
(4;"|GRIS|2")
(4;"|GRIS|2")
(5;"6|NOIR|1")
(5;"6|NOIR|1")
(6;"|GRIS|2")
(6;"|GRIS|2")
Exemple: parcours de graphe
6-11

● Après le lancement 3:
Graphe:
Données de sortie:
(1;"2,5|NOIR|0")
(1;"2,5|NOIR|0")
(2;"3,4|NOIR|1")
(2;"3,4|NOIR|1")
(3;"6|NOIR|2")
(3;"6|NOIR|2")
(4;"|NOIR|2")
(4;"|NOIR|2")
(5;"6|NOIR|1")
(5;"6|NOIR|1")
(6;"|NOIR|3")
(6;"|NOIR|3")
Exemple: parcours de graphe
6-12

● Tous les nœuds ont tous désormais pour couleur la


valeur « NOIR » ; le programme en charge de lancer la
tâche map/reduce à répétition sur les données
s’arrête.

● On a ainsi effectué un parcours en largeur sur le


graphe, parallélisable (parallel breadth-first search). A
chaque étape de profondeur dans le parcours
correspond l'exécution d'une tâche map/reduce –
avec une fonction map executée pour chaque nœud à
chaque étape.
Conclusion
6-13
● Applications courantes de map/reduce et Hadoop:

● Analyse de logs et données en général, validation de données,


recoupements, filtrage, etc. => traitements sur des volumes de données
massifs.
● Exécution de tâches intensives en CPU de manière distribuée
(simulations scientifiques, encodage vidéo, etc.).

… et bien souvent les deux: tâches intensives en CPU sur des volumes de
données massifs (entraînement de modèles en machine learning, etc.)

● Plus complexe, voire contre-productif à appliquer sur tout problème où la


fragmentation des données d'entrée pose problème (en fait sur tout
problème où la stratégie du diviser pour régner n'est pas viable).
7 map/reduce et Hadoop: développement plus avancé
Les InputFormats Hadoop
7-1

● Lors de l'exemple du compteur d'occurence de mots vu


précédemment, Hadoop ouvre le fichier d'entrée (le poème) sur HDFS
et le découpe automatiquement; en générant un fragment par ligne.

● Cette logique provient du fait que par défaut, c'est le comportement


appliqué par Hadoop: l'entrée est au format texte, et chaque ligne
dénote un fragment distinct; et Hadoop émet en entrée de map des
couples (clef;valeur) pour lesquels la clef est le numéro de la ligne
dans le fichier, et la valeur le contenu de la ligne elle-même.

● Ce comportement de lecture des données d'entrée peut être influencé


par le biais de classes implémentant un comportement différent: les
InputFormats.
Les InputFormats Hadoop
7-2

● Un InputFormat a deux principales responsabilités:

● S'assurer du découpage cohérent des données situées dans un


fichier d'entrée.

● Fournir une logique d'interprétation des données d'entrée pour


générer des couples (clef;valeur) cohérents.

● La classe InputFormat utilisée par défaut est TextInputFormat.

● Il est possible d'en sélectionner une autre lors de la configuration de la


tâche, et même de créer son propre InputFormat spécifique.
Selection d'un InputFormat
7-3

● Pour sélectionner une classe InputFormat différente, on utilisera la


méthode:

[Link](class)

(de l'objet job désignant la tâche à exécuter dans la classe driver)

● Par exemple:

[Link]([Link]);

… pour spécifier la classe InputFormat KeyValueTextInputFormat.


Quelques InputFormats
7-4

● Quelques exemples d'InputFormats Hadoop alternatifs standards:

● KeyValueTextInputFormat
Découpe le ou les fichiers d'entrée par ligne; mais contrairement au
TextInputFormat utilisé par défaut, cette classe s'attend à trouver des
couples (clef;valeur) au sein de chacune des lignes, sur un format constitué
d'une clef, puis d'une tabulation, puis du reste de la ligne comme valeur. Ces
couples (clef;valeur) seront émis à la fonction map en conséquence.

● FixedLengthInputFormat
Découpe le ou les fichiers d'entrée selon une taille fixe indiquée à la classe.
Les couples (clef;valeur) émis ont le numéro du fragment dans le fichier
pour clef, et le fragment lui-même comme valeur. Particulièrement adapté à
des données binaires où une série de « blocs » de taille égale se suivent.
Quelques InputFormats
7-5

● NLineInputFormat
Découpe le ou les fichiers d'entrée par groupes de N lignes; la clef
transmise à la fonction map représente le numéro du bloc de N
lignes, et la valeur le contenu des lignes.

● SequenceFileInputFormat
Un InputFormat adapté aux Sequence Files; il s'agit d'un format de
données binaire communément utilisé dans Hadoop, des outils
associés à Hadoop, et d'une manière générale dans des logiciels Big
Data. Le format est adapté à une lecture rapide, et est souvent
préféré aux fichiers texte dans des applications de production.
Configurer un InputFormat
7-6

● La plupart des InputFormat Hadoop supportent des paramètres de


configuration pour influer sur leur fonctionnement. Ces paramètres sont
généralement ajustables par le biais d'un appel à des méthodes:

[Link]() / [Link]() / [Link]() / ...


(de l'objet Configuration associé à la tâche au sein de la classe driver)

● Par exemple:

[Link]("[Link].s
eparator", ":");

Pour indiquer à l'InputFormat KeyValueInputFormat que le séparateur entre


la clef et la valeur dans les données d'entrée n'est pas une tabulation mais un
caractère « : ».
Configurer un InputFormat
7-7

● Un autre exemple:

[Link](FixedLengthInputFormat.FIXED_RECORD_LENGTH, 12);

Pour indiquer à l'InputFormat FixedLengthInputFormat que la taille de


chacun des blocs fixes de données à lire est de 12 octets.

● Certains InputFormat sont configurables / doivent être configurés par le biais


d'une méthode statique sur la classe InputFormat plutôt que d'un appel à une
des méthodes set de l'objet Configuration.

● Remarque: la configuration doit être effectuée avant l'instanciation de l'objet


Job (qui récupère la configuration passée en paramètre).
Créer son propre InputFormat
7-8

● Tous les InputFormats vus précédemment héritent d'une classe


« FileInputFormat », qui défini un InputFormat lisant des données depuis un
ou des fichiers sur HDFS.

● Il en existe d'autres: DBInputFormat pour lire des données depuis une base
de données, CompositeInputFormat pour lire des données depuis plusieurs
sources à la fois, etc. certains exemples de ces InputFormat seront vus plus
loin dans le cours; c'est entre autres leur existence qui permet d'intégrer
Hadoop à d'autres logiciels (par exemple une base de données NoSQL en
entrée d'un programme map/reduce, sans passer par HDFS).

● Il est également possible de créer son propre InputFormat; par exemple pour
lire des données dans un format propriétaire de manière cohérente depuis
HDFS, ou encore pour obtenir des couples (clef;valeur) depuis une API tierce
propres à un développement spécifique, etc.
Créer son propre InputFormat
7-9

● Pour créer son propre FileInputFormat, par exemple, on suivra la procédure


suivante:

● Créer une classe qui hérite de FileInputFormat, en paramétrisant cette


classe avec deux types: les types de clef et valeur susceptibles d'être lus via
cet InputFormat.

● Créer une classe héritant de RecordReader, paramétrisée de la même


manière, et qui aura pour tâche de lire les différents couples (clef;valeur) au
sein de chacun des fichiers d'entrée.

● Implémenter plusieurs méthodes au sein de ces deux classes afin de créer la


logique de lecture des fichiers d'entrée.
Créer son propre InputFormat - Exemple
7-10

● Imaginons qu'on souhaite lire des fichiers source correspondant à l'exemple


des « amis en commun » du réseau social vu précédemment.

● Ces fichiers respectent le format suivant:

A => B, C, D
B => A, C, D, E
C => A, B, D, E
D => A, B, C, E
E => B, C, D

On devra donc implémenter un FileInputFormat capable d'interpréter chacune


de ces lignes pour séparer la clef (l'utilisateur concerné) de la valeur (la liste
d'amis), en identifiant le séparateur (les caractères « => »).
Créer son propre InputFormat - Exemple
7-11

● Le code de la classe InputFormat:


package
package [Link];
[Link];

import
import ……

//
// Notre
Notre InputFormat
InputFormat spécifique.
spécifique.
public
public class
class FriendsInputFormat
FriendsInputFormat extends
extends FileInputFormat<Text,
FileInputFormat<Text, Text>
Text> {{

//
// La
La méthode
méthode de
de création
création d'un
d'un RecordReader,
RecordReader, àà implémenter.
implémenter.
public
public RecordReader<Text,
RecordReader<Text, Text>
Text> createRecordReader(InputSplit
createRecordReader(InputSplit split,
split,
TaskAttemptContext
TaskAttemptContext context)
context) throws
throws IOException,
IOException, InterruptedException
InterruptedException {{
//
// Renvoie
Renvoie simplement
simplement une
une instance
instance de
de notre
notre RecordReader
RecordReader
//
// spécifique.
spécifique.
return
return new
new FriendsRecordReader();
FriendsRecordReader();
}}
}}
Créer son propre InputFormat - Exemple
7-12
● Le code de la classe RecordReader:
package
package [Link];
[Link];

import
import ……

//
// Notre
Notre RecordReader
RecordReader spécifique.
spécifique.
public
public class
class FriendsRecordReader
FriendsRecordReader extends
extends RecordReader<Text,
RecordReader<Text, Text>
Text> {{
private
private LineRecordReader
LineRecordReader lineRecordReader=null;
lineRecordReader=null;
private
private Text
Text key=null;
key=null;
private
private Text
Text value=null;
value=null;

//
// Fermeture
Fermeture du
du reader.
reader.
public
public void
void close()
close() throws
throws IOException
IOException {{
if(lineRecordReader!=null)
if(lineRecordReader!=null)
{{
[Link]();
[Link]();
lineRecordReader=null;
lineRecordReader=null;
Créer son propre InputFormat - Exemple
7-13
}}
key=null;
key=null;
value=null;
value=null;
}}

public
public Text
Text getCurrentKey()
getCurrentKey() throws
throws IOException,
IOException, InterruptedException
InterruptedException {{
return
return key;
key;
}}

public
public Text
Text getCurrentValue()
getCurrentValue() throws
throws IOException,
IOException, InterruptedException
InterruptedException {{
return
return value;
value;
}}

//
// Pour
Pour renvoyer
renvoyer la
la progression
progression actuelle
actuelle de
de la
la lecture.
lecture.
public
public float
float getProgress()
getProgress() throws
throws IOException,
IOException, InterruptedException
InterruptedException {{
return
return [Link]();
[Link]();
}}
Créer son propre InputFormat - Exemple
7-14

//
// Initialisation.
Initialisation.
public
public void
void initialize(InputSplit
initialize(InputSplit split,
split, TaskAttemptContext
TaskAttemptContext context)
context)
throws
throws IOException,
IOException, InterruptedException
InterruptedException {{
close();
close();
lineRecordReader=new
lineRecordReader=new LineRecordReader();
LineRecordReader();
[Link](split,
[Link](split, context);
context);
}}

//
// Fonction
Fonction principale
principale qui
qui aa la
la charge
charge de
de la
la lecture
lecture du
du couple
couple
//
// (clef;valeur)
(clef;valeur) suivant
suivant au
au sein
sein du
du flux.
flux.
public
public boolean
boolean nextKeyValue()
nextKeyValue() throws
throws IOException,
IOException, InterruptedException
InterruptedException
if(![Link]())
if(![Link]()) {{
key
key == null;
null;
value
value == null;
null;
return
return false;
false;
}}
Créer son propre InputFormat - Exemple
7-15
//
// Logique
Logique dede lecture.
lecture.
//
// On
On récupère
récupère simplement
simplement la
la ligne
ligne lue
lue depuis
depuis le
le fichier
fichier par
par
//
// le
le LineRecordReader;
LineRecordReader; et et on
on sépare
sépare clef
clef et
et valeur.
valeur.
//
// Les
Les clef
clef et
et valeur
valeur ne
ne sont
sont pas
pas retournées
retournées ici,
ici, mais
mais simplement
simplement
// lues et stockées.
// lues et stockées.
Text
Text line=[Link]();
line=[Link]();
String
String str=[Link]();
str=[Link]();
String[]
String[] arr=[Link]("=>");
arr=[Link]("=>");
key=new Text(arr[0]);
key=new Text(arr[0]);
value=new
value=new Text(arr[1]);
Text(arr[1]);
return
return true;
true;
}}
}}
Créer son propre InputFormat
7-16

● Il ne s'agit là que d'un rapide tour d'horizon de l'implémentation d'un


InputFormat spécifique; il va de soit que des possibilités plus
complexes sont disponibles.

● Pour plus d'informations, se référer à la documentation et aux


exemples Hadoop:

[Link]
Les OutputFormats Hadoop
7-17

● De la même manière que pour les InputFormats, on peut également


influencer la façon dont Hadoop va écrire les résultats finaux, c'est à
dire les couples (clef;valeur) issus de l'opération Reduce, sur HDFS.

● Pour ce faire, on procède de la même manière, mais à l'aide d'un autre


type de classes: les OutputFormats.

● La méthode permettant d'indiquer à Hadoop qu'on souhaite utiliser un


OutputFormat spécifique est la suivante:

[Link](class)

(de l'objet Job désignant la tâche à effectuer dans la classe driver)


Les OutputFormats Hadoop
7-18

● L'OutputFormat par défaut de Hadoop est la classe


TextOutputFormat. Elle produit un format similaire au format d'entrée
de KeyValueInputFormat, c'est à dire:

● Un couple (clef;valeur) par ligne.


● Une tabulation entre la clef et la valeur.

● C'est pour cette raison que lors de l'exécution des programmes en TP,
les fichiers de résultat contenaient nos couples (clef;valeur) finals
sous ce format.

● Comme pour les InputFormats, Hadoop propose plusieurs


OutputFormat standards.
Quelques OutputFormats
7-19
● Quelques exemples d'OutputFormats Hadoop alternatifs standards:

● SequenceFileOutputFormat
Écrit les couples (clef;valeur) sur HDFS sous la forme d'un Sequence
File – le même format binaire que celui qui est utilisé avec la classe
SequenceFileInputFormat.

● MultipleOutputFormat
Écrit les couples (clef;valeur) vers plusieurs destination; cette classe
est le pendant de l'InputFormat MultipleInputFormat et permet par
exemple d'écrire les couples (clef;valeur) à plusieurs endroits
différents sur HDFS.
Les OutputFormats Hadoop
7-20

● Comme pour les InputFormats, ces classes sont issues d'une classe mère
FileOutputFormat; et là aussi, il en existe des variantes, par exemple
DBOutputFormat pour écrire les couples (clef;valeur) vers des bases de
données.

● Là aussi, le comportement des OutputFormats est configurable. Par exemple,


en utilisant:

[Link]("[Link]", ";");
// ...
[Link]([Link]);

… on indiquera qu'on souhaite utiliser le séparateur « : » plutôt qu'une


tabulation, pour l'OutputFormat TextOutputFormat.
Les OutputFormats Hadoop
7-21
● Enfin, il est évidemment possible de créer ses propres OutputFormats,
tout comme pour les InputFormats.

● Cela se fait de manière similaire:

● En créant une classe héritant de la classe FileOutputFormat (ou


DBOutputFormat, etc.), paramétrisée avec un type de clef et un type
de liste de valeurs (par exemple List<Text>).

● En créant une classe héritant de la classe RecordWriter,


paramétrisée de la même manière. Il s'agit du pendant de la classe
RecordReader vue précédemment, pour les OutputFormats.
Les types Writable spécifiques
7-22
● Jusqu'ici, on a toujours utilisé des types « simples » pour les clefs et
valeurs utilisées dans les programmes d'exemple: par exemple Text,
ou encore IntWritable.

● Hadoop permet également de définir ses propres types spécifiques,


pour la clef ou pour la valeur. On pourrait ainsi avoir un objet passé en
temps que valeur d'un programme map/reduce.

● Il suffit pour ce faire de créer une nouvelle classe implémentant une


interface Hadoop.

● Les types vus précédemment: IntWritable, Text, LongWritable,


etc. sont justement des types Hadoop implémentant cette interface
autour des types Java standards (Int, String, Long, etc.).
Les types Writable spécifiques
7-23
● Pour créer un type Writable spécifique, on doit implémenter l'interface
Hadoop WritableComparable.

● Il faut, au sein de la classe, implémenter au minimum les fonctions


suivantes:

● write
Pour écrire les données de la classe sur HDFS (et en interne pour
Hadoop).

● readFields
Pour lire les données de la classe depuis HDFS (idem)
Les types Writable spécifiques
7-24
● compareTo
Pour comparer l'objet courant à une autre instance du même type; la
fonction doit renvoyer -1, 0 ou 1 si l'objet a une « valeur » respectivement
inférieure, égale ou supérieure à la « valeur » de l'objet passé en argument.
Cette méthode est avant tout nécessaire pour les clefs; elle a peu
d'importances pour les types utilisés comme des valeurs.

● hashcode
Doit générer un hash décrivant l'objet; ce hash permet à Hadoop d'identifier
à quels reduceurs il doit envoyer quels couples (clef;valeur) lors du shuffle,
entre l'opération map et reduce. Ce hash doit être identique pour une
« valeur » donnée d'un objet; et il ne doit pas varier entre deux exécutions
du programmes (ou d'une machine virtuelle Java à une autre). Cela signifie
qu'utiliser la fonction Java standard hashcode sur l'objet ne fonctionnera
possiblement pas; il est préférable d'implémenter sa propre fonction. Là
aussi, cette méthode est nécessaire pour les clefs.
Les types Writable spécifiques
7-25
● A noter que si on souhaite créer un type spécifique uniquement pour
les valeurs, on peut implémenter à la place l'interface Writable; qui ne
nécessitera pas d'implémentation des méthodes compareTo et
hashcode.

● Ce type ne sera alors cependant pas utilisable en tant que clef dans un
programme map/reduce Hadoop.

● A moins que cela n'ait pas de sens, on considère généralement qu'il


est plus « propre » de créer un type spécifique de telle sorte qu'il soit à
la fois « writable » et « comparable », et puisse donc être utiliser
comme une valeur ou comme une clef.
Les types Writable spécifiques - Exemple
7-26
● On souhaite créer un type spécifique pour stocker nos valeurs dans
l'exemple du réseau social / des « amis en commun ».

● La classe s'appellera « FriendsListWritable » et stockera la liste


des amis liés à un utilisateur du réseau.

● On va donc implémenter notre propre type Writable.

● Comme on souhaite s'en servir uniquement comme valeur, les


méthodes compareTo() et hashcode() ont moins d'importance.
Les types Writable spécifiques - Exemple
7-27
● Le code:
package
package [Link];
[Link];

import
import ……

public
public class
class FriendsListWritable
FriendsListWritable implements
implements
WritableComparable<FriendsListWritable>
WritableComparable<FriendsListWritable> {{
private
private ArrayList<String>
ArrayList<String> friends=new
friends=new ArrayList<String>();
ArrayList<String>();

public
public void
void write(DataOutput
write(DataOutput out)
out) throws
throws IOException
IOException {{
Iterator<String>
Iterator<String> iterator=[Link]();
iterator=[Link]();
String
String line="";
line="";
while([Link]()){
while([Link]()){
String
String element=[Link]();
element=[Link]();
if(![Link](""))
if(![Link](""))
line+=",";
line+=",";
line+=element;
line+=element;
Les types Writable spécifiques - Exemple
7-28
}}
[Link](line);
[Link](line);
}}

public
public void
void readFields(DataInput
readFields(DataInput in)
in) throws
throws IOException
IOException {{
String
String line=[Link]();
line=[Link]();
String[]
String[] elems=[Link](",");
elems=[Link](",");
friends=new
friends=new ArrayList<String>([Link](elems));
ArrayList<String>([Link](elems));
}}

public
public int
int getsize()
getsize()
{{
return([Link]());
return([Link]());
}}

public
public int
int compareTo(FriendsListWritable
compareTo(FriendsListWritable o)
o) {{
Les types Writable spécifiques - Exemple
7-29
int
int mysize=[Link]();
mysize=[Link]();
int
int theirsize=[Link]();
theirsize=[Link]();
return
return (mysize
(mysize << theirsize
theirsize ?? -1
-1 :: (mysize==theirsize
(mysize==theirsize ?? 00 :: 1));
1));
}}

public
public int
int hashCode()
hashCode() {{
return
return [Link]();
[Link]();
}}
}}

Vous aimerez peut-être aussi