Les secrets mystérieux du tri Hadoop

HadoopBeginner
Pratiquer maintenant

Introduction

Dans un marché nocturne mystérieux, une figure captivante vêtue d'un masque magnifique se déplace gracieusement parmi la foule bondée. Ce danseur de masque énigmatique semble posséder un pouvoir secret, triant sans effort les étals chaotiques en un arrangement ordonné avec chaque tour et balancement. Votre objectif est de dévoiler le mystère derrière ce talent remarquable en maîtrisant l'art de Hadoop Shuffle Comparable.

Implémentez le Mappeur

Dans cette étape, nous allons créer une classe Mapper personnalisée pour traiter les données d'entrée et émettre des paires clé-valeur. La clé sera une clé composite composée de deux champs : le premier caractère de chaque mot et la longueur du mot. La valeur sera le mot lui-même.

Tout d'abord, changez l'utilisateur en hadoop puis accédez au répertoire racine de l'utilisateur hadoop :

su - hadoop

Ensuite, créez un fichier Java pour la classe Mapper :

touch /home/hadoop/WordLengthMapper.java

Ajoutez le code suivant au fichier WordLengthMapper.java :

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

public class WordLengthMapper extends Mapper<LongWritable, Text, CompositeKey, Text> {

    private CompositeKey compositeKey = new CompositeKey();

    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString();
        String[] words = line.split("\\s+");

        for (String word : words) {
            compositeKey.setFirstChar(word.charAt(0));
            compositeKey.setLength(word.length());
            context.write(compositeKey, new Text(word));
        }
    }
}

Dans le code ci-dessus, nous créons une classe WordLengthMapper qui hérite de la classe Mapper de l'API Hadoop MapReduce. La méthode map prend une clé LongWritable (représentant le décalage en octets de la ligne d'entrée) et une valeur Text (la ligne d'entrée elle-même). Elle divise ensuite la ligne d'entrée en mots individuels, crée un objet CompositeKey pour chaque mot (contenant le premier caractère et la longueur du mot), et émet la CompositeKey comme clé et le mot comme valeur.

Implémentez la Clé Composite

Dans cette étape, nous allons créer une classe CompositeKey personnalisée qui implémente l'interface WritableComparable de l'API Hadoop MapReduce. Cette classe sera utilisée comme clé dans notre travail MapReduce, nous permettant de trier et de regrouper les données en fonction du premier caractère et de la longueur de chaque mot.

Tout d'abord, créez un fichier Java pour la classe CompositeKey :

touch /home/hadoop/CompositeKey.java

Ensuite, ajoutez le code suivant au fichier CompositeKey.java :

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;

public class CompositeKey implements WritableComparable<CompositeKey> {

    private char firstChar;
    private int length;

    public CompositeKey() {
    }

    public void setFirstChar(char firstChar) {
        this.firstChar = firstChar;
    }

    public char getFirstChar() {
        return firstChar;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getLength() {
        return length;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeChar(firstChar);
        out.writeInt(length);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        firstChar = in.readChar();
        length = in.readInt();
    }

    @Override
    public int compareTo(CompositeKey other) {
        int cmp = Character.compare(firstChar, other.firstChar);
        if (cmp!= 0) {
            return cmp;
        }
        return Integer.compare(length, other.length);
    }

    @Override
    public int hashCode() {
        return firstChar + length;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof CompositeKey) {
            CompositeKey other = (CompositeKey) obj;
            return firstChar == other.firstChar && length == other.length;
        }
        return false;
    }

    @Override
    public String toString() {
        return firstChar + ":" + length;
    }
}

Dans le code ci-dessus, nous créons une classe CompositeKey qui implémente l'interface WritableComparable. Elle a deux champs : firstChar (le premier caractère d'un mot) et length (la longueur du mot). La classe fournit des méthodes d'accès et de modification pour ces champs, ainsi que des implémentations des méthodes write, readFields, compareTo, hashCode, equals et toString requises par l'interface WritableComparable.

La méthode compareTo est particulièrement importante, car elle définit comment les clés seront triées dans le travail MapReduce. Dans notre implémentation, nous comparons d'abord les champs firstChar des deux clés. Si ils sont différents, nous retournons le résultat de cette comparaison. Si les champs firstChar sont les mêmes, nous comparons ensuite les champs length.

Implémentez le Réducteur

Dans cette étape, nous allons créer une classe Réducteur personnalisée pour traiter les paires clé-valeur émises par le Mappeur et générer la sortie finale.

Tout d'abord, créez un fichier Java pour la classe Réducteur :

touch /home/hadoop/WordLengthReducer.java

Ensuite, ajoutez le code suivant au fichier WordLengthReducer.java :

import java.io.IOException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class WordLengthReducer extends Reducer<CompositeKey, Text, CompositeKey, Text> {

    public void reduce(CompositeKey key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        StringBuilder sb = new StringBuilder();
        for (Text value : values) {
            sb.append(value.toString()).append(", ");
        }
        sb.setLength(sb.length() - 2);
        context.write(key, new Text(sb.toString()));
    }
}

Dans le code ci-dessus, nous créons une classe WordLengthReducer qui hérite de la classe Reducer de l'API Hadoop MapReduce. La méthode reduce prend une clé CompositeKey (contenant le premier caractère et la longueur d'un mot) et un Iterable de valeurs Text (les mots qui correspondent à la clé).

Dans la méthode reduce, nous concaténons tous les mots qui correspondent à la clé en une chaîne séparée par des virgules. Nous utilisons un StringBuilder pour construire efficacement la chaîne de sortie, et nous supprimons la virgule et l'espace de fin avant d'écrire la paire clé-valeur dans la sortie.

Implémentez le Pilote

Dans cette étape, nous allons créer une classe Pilote pour configurer et exécuter le travail MapReduce.

Tout d'abord, créez un fichier Java pour la classe Pilote :

touch /home/hadoop/WordLengthDriver.java

Ensuite, ajoutez le code suivant au fichier WordLengthDriver.java :

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class WordLengthDriver {

    public static void main(String[] args) throws Exception {
        if (args.length!= 2) {
            System.err.println("Usage: WordLengthDriver <input> <output>");
            System.exit(1);
        }

        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "Word Length");

        job.setJarByClass(WordLengthDriver.class);
        job.setMapperClass(WordLengthMapper.class);
        job.setReducerClass(WordLengthReducer.class);
        job.setOutputKeyClass(CompositeKey.class);
        job.setOutputValueClass(Text.class);

        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        System.exit(job.waitForCompletion(true)? 0 : 1);
    }
}

Dans le code ci-dessus, nous créons une classe WordLengthDriver qui sert de point d'entrée pour notre travail MapReduce. La méthode main prend deux arguments de ligne de commande : le chemin d'entrée et le chemin de sortie pour le travail.

Dans la méthode main, nous créons un nouvel objet Configuration et un nouvel objet Job. Nous configurons le travail en définissant les classes de mappeur et de réducteur, les classes de clé et de valeur de sortie, et les chemins d'entrée et de sortie.

Enfin, nous soumettons le travail et attendons sa fin. Si le travail se termine avec succès, nous sortons avec un code de statut de 0 ; sinon, nous sortons avec un code de statut de 1.

Pour exécuter le travail, vous pouvez utiliser la commande suivante :

javac -source 8 -target 8 -classpath "/home/hadoop/:/home/hadoop/hadoop/share/hadoop/common/hadoop-common-3.3.6.jar:/home/hadoop/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:/home/hadoop/hadoop/share/hadoop/common/lib/*" -d /home/hadoop /home/hadoop/WordLengthMapper.java /home/hadoop/CompositeKey.java /home/hadoop/WordLengthReducer.java /home/hadoop/WordLengthDriver.java
jar cvf word-length.jar *.class
hadoop jar word-length.jar WordLengthDriver /input /output

Enfin, nous pouvons vérifier les résultats en exécutant la commande suivante :

hadoop fs -cat /output/*

Sortie exemple :

A:3 Amr
A:6 AADzCv
A:10 AlGyQumgIl
...
h:7 hgQUIhA
h:8 hyrjMGbY, hSElGKux
h:10 hmfHJjCkwB
...
z:6 zkpRCN
z:8 zfMHRbtk
z:9 zXyUuLHma

Résumé

Dans ce laboratoire, nous avons exploré le concept de Hadoop Shuffle Comparable en implémentant un travail MapReduce qui regroupe les mots en fonction de leur premier caractère et de leur longueur. Nous avons créé un Mappeur personnalisé pour émettre des paires clé-valeur avec une clé composite, une classe CompositeKey personnalisée qui implémente l'interface WritableComparable, un Réducteur pour concaténer les mots ayant la même clé et une classe Pilote pour configurer et exécuter le travail.

Grâce à ce laboratoire, j'ai acquis une compréhension plus approfondie du cadre Hadoop MapReduce et de l'importance des types de données personnalisés et du tri dans l'informatique distribuée. En maîtrisant Hadoop Shuffle Comparable, nous pouvons concevoir des algorithmes efficaces pour le traitement et l'analyse des données, libérant le pouvoir des grands volumes de données comme le mystérieux danseur masqué triant les étals du marché nocturne chaotique.