MapReduce - Combineurs

Un combineur, également connu sous le nom de semi-reducer, est une classe facultative qui fonctionne en acceptant les entrées de la classe Map et en passant ensuite les paires clé-valeur de sortie à la classe Reducer.

La fonction principale d'un combinateur est de résumer les enregistrements de sortie de carte avec la même clé. La sortie (collection clé-valeur) du combineur sera envoyée sur le réseau à la tâche réelle du réducteur en tant qu'entrée.

Combiner

La classe Combiner est utilisée entre la classe Map et la classe Reduce pour réduire le volume de transfert de données entre Map et Reduce. En général, la sortie de la tâche cartographique est volumineuse et les données transférées vers la tâche de réduction sont élevées.

Le diagramme de tâches MapReduce suivant montre la PHASE DU COMBINER.

Comment fonctionne Combiner?

Voici un bref résumé du fonctionnement de MapReduce Combiner -

  • Un combineur n'a pas d'interface prédéfinie et il doit implémenter la méthode reduction () de l'interface Reducer.

  • Un combineur opère sur chaque clé de sortie de carte. Elle doit avoir les mêmes types de valeur-clé en sortie que la classe Reducer.

  • Un combineur peut produire des informations récapitulatives à partir d'un ensemble de données volumineux car il remplace la sortie Map d'origine.

Bien que Combiner soit facultatif, il permet de séparer les données en plusieurs groupes pour la phase de réduction, ce qui facilite le traitement.

Implémentation de MapReduce Combiner

L'exemple suivant fournit une idée théorique sur les combineurs. Supposons que nous ayons le fichier texte d'entrée suivant nomméinput.txt pour MapReduce.

What do you mean by Object
What do you know about Java
What is Java Virtual Machine
How Java enabled High Performance

Les phases importantes du programme MapReduce avec Combiner sont décrites ci-dessous.

Lecteur d'enregistrement

Il s'agit de la première phase de MapReduce où le lecteur d'enregistrement lit chaque ligne du fichier texte d'entrée sous forme de texte et génère la sortie sous forme de paires clé-valeur.

Input - Texte ligne par ligne du fichier d'entrée.

Output- Forme les paires clé-valeur. Voici l'ensemble des paires clé-valeur attendues.

<1, What do you mean by Object>
<2, What do you know about Java>
<3, What is Java Virtual Machine>
<4, How Java enabled High Performance>

Phase de la carte

La phase de mappage prend l'entrée du lecteur d'enregistrement, la traite et produit la sortie sous la forme d'un autre ensemble de paires clé-valeur.

Input - La paire clé-valeur suivante est l'entrée provenant du lecteur d'enregistrement.

<1, What do you mean by Object>
<2, What do you know about Java>
<3, What is Java Virtual Machine>
<4, How Java enabled High Performance>

La phase de mappage lit chaque paire clé-valeur, divise chaque mot de la valeur à l'aide de StringTokenizer, traite chaque mot comme clé et le nombre de ce mot comme valeur. L'extrait de code suivant montre la classe Mapper et la fonction de carte.

public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>
{
   private final static IntWritable one = new IntWritable(1);
   private Text word = new Text();
   
   public void map(Object key, Text value, Context context) throws IOException, InterruptedException 
   {
      StringTokenizer itr = new StringTokenizer(value.toString());
      while (itr.hasMoreTokens()) 
      {
         word.set(itr.nextToken());
         context.write(word, one);
      }
   }
}

Output - Le résultat attendu est le suivant -

<What,1> <do,1> <you,1> <mean,1> <by,1> <Object,1>
<What,1> <do,1> <you,1> <know,1> <about,1> <Java,1>
<What,1> <is,1> <Java,1> <Virtual,1> <Machine,1>
<How,1> <Java,1> <enabled,1> <High,1> <Performance,1>

Phase de combinaison

La phase Combiner prend chaque paire clé-valeur de la phase Map, la traite et produit la sortie comme key-value collection paires.

Input - La paire clé-valeur suivante est l'entrée extraite de la phase Map.

<What,1> <do,1> <you,1> <mean,1> <by,1> <Object,1>
<What,1> <do,1> <you,1> <know,1> <about,1> <Java,1>
<What,1> <is,1> <Java,1> <Virtual,1> <Machine,1>
<How,1> <Java,1> <enabled,1> <High,1> <Performance,1>

La phase Combiner lit chaque paire clé-valeur, combine les mots communs en tant que clé et les valeurs en tant que collection. Habituellement, le code et le fonctionnement d'un combineur sont similaires à ceux d'un réducteur. Voici l'extrait de code pour la déclaration de classe Mapper, Combiner et Reducer.

job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);

Output - Le résultat attendu est le suivant -

<What,1,1,1> <do,1,1> <you,1,1> <mean,1> <by,1> <Object,1>
<know,1> <about,1> <Java,1,1,1>
<is,1> <Virtual,1> <Machine,1>
<How,1> <enabled,1> <High,1> <Performance,1>

Phase de réduction

La phase de réduction prend chaque paire de collection clé-valeur de la phase de combinaison, la traite et transmet la sortie sous forme de paires clé-valeur. Notez que la fonctionnalité Combiner est la même que le Réducteur.

Input - La paire clé-valeur suivante est l'entrée extraite de la phase Combiner.

<What,1,1,1> <do,1,1> <you,1,1> <mean,1> <by,1> <Object,1>
<know,1> <about,1> <Java,1,1,1>
<is,1> <Virtual,1> <Machine,1>
<How,1> <enabled,1> <High,1> <Performance,1>

La phase de réduction lit chaque paire clé-valeur. Voici l'extrait de code du combineur.

public static class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable> 
{
   private IntWritable result = new IntWritable();
   
   public void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException 
   {
      int sum = 0;
      for (IntWritable val : values) 
      {
         sum += val.get();
      }
      result.set(sum);
      context.write(key, result);
   }
}

Output - La sortie attendue de la phase Réducteur est la suivante -

<What,3> <do,2> <you,2> <mean,1> <by,1> <Object,1>
<know,1> <about,1> <Java,3>
<is,1> <Virtual,1> <Machine,1>
<How,1> <enabled,1> <High,1> <Performance,1>

Record Writer

Il s'agit de la dernière phase de MapReduce où le Record Writer écrit chaque paire clé-valeur de la phase Reducer et envoie la sortie sous forme de texte.

Input - Chaque paire clé-valeur de la phase de réduction avec le format de sortie.

Output- Il vous donne les paires clé-valeur au format texte. Voici le résultat attendu.

What           3
do             2
you            2
mean           1
by             1
Object         1
know           1
about          1
Java           3
is             1
Virtual        1
Machine        1
How            1
enabled        1
High           1
Performance    1

Exemple de programme

Le bloc de code suivant compte le nombre de mots dans un programme.

import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordCount {
   public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>
   {
      private final static IntWritable one = new IntWritable(1);
      private Text word = new Text();
      
      public void map(Object key, Text value, Context context) throws IOException, InterruptedException 
      {
         StringTokenizer itr = new StringTokenizer(value.toString());
         while (itr.hasMoreTokens()) 
         {
            word.set(itr.nextToken());
            context.write(word, one);
         }
      }
   }
   
   public static class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable> 
   {
      private IntWritable result = new IntWritable();
      public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException 
      {
         int sum = 0;
         for (IntWritable val : values) 
         {
            sum += val.get();
         }
         result.set(sum);
         context.write(key, result);
      }
   }
   
   public static void main(String[] args) throws Exception 
   {
      Configuration conf = new Configuration();
      Job job = Job.getInstance(conf, "word count");
		
      job.setJarByClass(WordCount.class);
      job.setMapperClass(TokenizerMapper.class);
      job.setCombinerClass(IntSumReducer.class);
      job.setReducerClass(IntSumReducer.class);
		
      job.setOutputKeyClass(Text.class);
      job.setOutputValueClass(IntWritable.class);
		
      FileInputFormat.addInputPath(job, new Path(args[0]));
      FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
      System.exit(job.waitForCompletion(true) ? 0 : 1);
   }
}

Enregistrez le programme ci-dessus sous WordCount.java. La compilation et l'exécution du programme sont données ci-dessous.

Compilation et exécution

Supposons que nous soyons dans le répertoire personnel de l'utilisateur Hadoop (par exemple, / home / hadoop).

Suivez les étapes ci-dessous pour compiler et exécuter le programme ci-dessus.

Step 1 - Utilisez la commande suivante pour créer un répertoire pour stocker les classes java compilées.

$ mkdir units

Step 2- Téléchargez Hadoop-core-1.2.1.jar, qui est utilisé pour compiler et exécuter le programme MapReduce. Vous pouvez télécharger le fichier jar sur mvnrepository.com .

Supposons que le dossier téléchargé est / home / hadoop /.

Step 3 - Utilisez les commandes suivantes pour compiler le WordCount.java programme et pour créer un fichier jar pour le programme.

$ javac -classpath hadoop-core-1.2.1.jar -d units WordCount.java
$ jar -cvf units.jar -C units/ .

Step 4 - Utilisez la commande suivante pour créer un répertoire d'entrée dans HDFS.

$HADOOP_HOME/bin/hadoop fs -mkdir input_dir

Step 5 - Utilisez la commande suivante pour copier le fichier d'entrée nommé input.txt dans le répertoire d'entrée de HDFS.

$HADOOP_HOME/bin/hadoop fs -put /home/hadoop/input.txt input_dir

Step 6 - Utilisez la commande suivante pour vérifier les fichiers dans le répertoire d'entrée.

$HADOOP_HOME/bin/hadoop fs -ls input_dir/

Step 7 - Utilisez la commande suivante pour exécuter l'application de comptage de mots en prenant les fichiers d'entrée dans le répertoire d'entrée.

$HADOOP_HOME/bin/hadoop jar units.jar hadoop.ProcessUnits input_dir output_dir

Attendez un moment jusqu'à ce que le fichier soit exécuté. Après l'exécution, la sortie contient un certain nombre de fractionnements d'entrée, de tâches de mappage et de tâches de réduction.

Step 8 - Utilisez la commande suivante pour vérifier les fichiers résultants dans le dossier de sortie.

$HADOOP_HOME/bin/hadoop fs -ls output_dir/

Step 9 - Utilisez la commande suivante pour voir la sortie dans Part-00000fichier. Ce fichier est généré par HDFS.

$HADOOP_HOME/bin/hadoop fs -cat output_dir/part-00000

Voici la sortie générée par le programme MapReduce.

What           3
do             2
you            2
mean           1
by             1
Object         1
know           1
about          1
Java           3
is             1
Virtual        1
Machine        1
How            1
enabled        1
High           1
Performance    1