Apprentissage Hadoop de la technologie Big Data (4) - MapReduce

Table des matières

1. Présentation de MapReduce

1. L'idée centrale de MapReduce

2. Modèle de programmation MapReduce

2. Principe de fonctionnement de MapReduce

1. Partage et mise en forme des sources de données

2. Exécutez MapTask

3. Exécutez le processus de lecture aléatoire

4. Exécutez RecudeTack

5. Écrire dans un fichier

3. Cas

1. Statistiques de fréquence des mots

(1) Composant InputFormat

(2) Composant mappeur

(3) Composant réducteur

(4) Composant combinateur

(5) Mode de fonctionnement de MapReduce

2. Index inversé

(1. Introduction

(2) Mise en œuvre de l'étape Map

(3) Combiner la mise en œuvre de l'étape

(4) Mise en œuvre de la phase Réduire

(5) Implémentation de la classe principale du programme pilote

(6) Affichage des résultats

3. Déduplication des données

(1) Implémentation de l'étape Map

(2) Mise en œuvre de la phase Réduire

(3) Implémentation de la classe principale du programme pilote

(4) Affichage des résultats

4、HautN

(1) Présentation du cas

(2) Mise en œuvre de l'étape Map

(3) Mise en œuvre de la phase Réduire

(4) Implémentation de la classe principale du programme pilote

(5) Affichage des résultats


Le code du boîtier a été placé sur le disque réseau Baidu et vous pouvez l'extraire vous-même si nécessaire.

http://lien : https://pan.baidu.com/s/1Vcqn7-A5YWOMqhBLpr3I0A?pwd=759w code d'extraction : 759w

1. Présentation de MapReduce

1. L'idée centrale de MapReduce

        L'idée centrale de MapReduce est "diviser pour mieux régner" , c'est-à-dire décomposer une tâche en plusieurs sous-tâches. Il n'y a pas d'interdépendance nécessaire entre ces sous-tâches, et elles peuvent toutes être exécutées indépendamment. Enfin, les résultats de ces sous-tâches sont agrégés et fusionnés.

2. Modèle de programmation MapReduce

        En tant que modèle de programmation, MapReduce est spécialisé dans le traitement d'opérations parallèles de données à grande échelle. Ce modèle s'appuie sur l'idée de la programmation fonctionnelle. Le processus de mise en œuvre du programme est réalisé via la fonction map() et la fonction reduce(). Lorsque vous utilisez MapReduce pour traiter des tâches informatiques, chaque tâche est divisée en deux phases, la phase Map et la phase Reduce.

(1) Etape carte : prétraitement des données brutes.

(2) Réduire l'étape : Résumez les résultats du traitement de l'étape Carte et obtenez enfin le résultat final.

        Description du processus : la première étape consiste à convertir les données d'origine sous la forme d'une paire clé-valeur <k1, v1> ; la deuxième étape consiste à importer la paire clé-valeur convertie <k1, v1> dans la fonction map(), et la fonction map() Selon les règles de mappage, la paire clé-valeur <k1, v1> est mappée sur une série de paires clé-valeur <k2, v2> sous la forme de résultats intermédiaires ; la troisième étape consiste à former les paires clé-valeur <k2, v2> sous la forme intermédiaire dans <k2, La forme {v2......}> est passée à la fonction reduce() pour traitement, et la valeur de la clé avec la même résultat est fusionné pour générer une nouvelle paire clé-valeur <k3,v3>. À ce stade, la paire clé-valeur <k3 ,v3> est le résultat final.

2. Principe de fonctionnement de MapReduce

1. Partage et mise en forme des sources de données

        L'entrée de la source de données dans l'étape Map doit être fragmentée et formatée.

(1) Opération de fragmentation : Divisez le fichier source en petits blocs de données de taille égale, puis Hadoop créera une tâche Map pour chaque fragment, et la tâche exécutera la fonction map() personnalisée pour traiter les données dans la fragmentation. enregistrer.

(2) Opération de formatage : formatez les fragments divisés en données sous la forme de paires clé-valeur <clé, valeur>, où la clé représente le décalage et la valeur représente une ligne de contenu.

2. Exécutez MapTask

(1) Étape de lecture : Map Task analyse chaque paire clé-valeur <k,v> de l'entrée InputSplit via le RecordReader écrit par l'utilisateur.

(2) Étape de mappage : le <k, v> analysé est transmis à la fonction de mappage écrite par l'utilisateur pour traitement, et une nouvelle paire clé-valeur <k, v> est générée.

(3) Étape de collecte : dans la fonction map écrite par l'utilisateur, une fois les données traitées, outputCollector.collect() est généralement appelé pour générer le résultat, et le fragment de la paire clé-valeur <k,v> est généré à l'intérieur du fonction, et écrit comme un tampon de mémoire circulaire.

(4) Étape de déversement : si le tampon circulaire est plein, MapReduce écrira les données sur le disque local pour générer un fichier temporaire. Il convient de noter ici qu'avant que les données ne soient écrites sur le disque local, les données doivent être triées une fois, et les données doivent être fusionnées et compressées si nécessaire.

(5) Étape de combinaison : une fois toutes les données traitées, Map Task fusionnera tous les fichiers temporaires une fois pour s'assurer qu'un seul fichier de données sera généré à la fin.

3. Exécutez le processus de lecture aléatoire

        Shuffle distribuera la sortie des données de résultat de traitement par Map Task à RecudeTask, et pendant le processus de distribution, les données seront partitionnées et triées par clé.

4. Exécutez RecudeTack

(1) Étape de copie : Recude copiera à distance une copie des données de chaque MapTask, et pour certaines données, si leur taille dépasse une certaine valeur, elles seront écrites sur le disque, sinon elles seront stockées en mémoire.

(2) Étape de fusion : lors de la copie de données à distance, RecudeTack démarrera deux threads d'arrière-plan pour fusionner les fichiers en mémoire et sur le disque respectivement afin d'éviter une utilisation excessive de la mémoire ou trop de fichiers sur le disque.

(3) Étape de tri : l'utilisateur écrit la méthode reduce() pour saisir des données qui sont un ensemble de données agrégées par clé. Car je clave les mêmes données, Hadoop adopte une stratégie basée sur le tri. Étant donné que chaque MapTask a implémenté un tri partiel de ses propres résultats de traitement, la ReduceTask n'a besoin de trier toutes les données qu'une seule fois.

(4) Phase de réduction : appelez la méthode reduce() sur les paires clé-valeur triées, et appelez la méthode reduce() une fois pour les paires clé-valeur avec des clés égales. Chaque appel générera zéro ou plusieurs paires clé-valeur, et enfin mettre ces clés Les paires de valeurs sont écrites dans HDFS.

(5) Phase d'écriture : la fonction reduce() écrit les résultats du calcul dans HDFS.

5. Écrire dans un fichier

        Le framework MapReduce transférera automatiquement la <clé, valeur> générée par RecudeTack à la méthode d'écriture de OutputFormat pour implémenter l'opération d'écriture de fichier.

3. Cas

1. Statistiques de fréquence des mots

        Ici, nous utilisons le cas des statistiques de fréquence des mots pour comprendre brièvement les composants connexes de MapReduce.

(1) Composant InputFormat

        Ce composant est principalement utilisé pour décrire le format des données d'entrée et fournit les deux fonctions suivantes.

a. Segmentation des données : Selon la stratégie, les données d'entrée sont divisées en plusieurs fragments afin de déterminer le nombre de MapTasks et les fragments correspondants.

b. Fournissez la source de données d'entrée pour Mapper : étant donné une certaine tranche, analysez-la en paires clé-valeur <k, v>.

        Hadoop est livré avec une interface InputFormat, qui définit le code comme suit.

public abstract class InputFormat <K, V> {
        public abstract List<InputFormat>getSplits(JobContext context) throws IOException, InterruptedException;
        public abstract RecordReader <K, V> createRecordReader (InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException;
    }

         L'interface InputFormat définit deux méthodes : getSplits() et createRecordReader(). La méthode getSplits() est chargée de diviser le fichier en plusieurs fragments. La méthode createRecordReader() est chargée de créer un objet RecordReader pour obtenir des données à partir des fragments.

(2) Composant mappeur

        Le programme MapReduce générera plusieurs tâches de mappage en fonction du fichier d'entrée. La classe Mapper implémente une classe abstraite de la tâche Map. Cette classe fournit une méthode map(). Par défaut, cette méthode n'a aucun traitement. Pour le moment, nous pouvons personnaliser la méthode map(), hériter de la classe Mapper et réécrire la méthode map().

        Prenons ensuite l'exemple des statistiques de fréquence des mots et personnalisons la méthode map(). Le code est le suivant.

package cn.itcast.mr.wordcount;

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

import java.io.IOException;

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        //接收传入进来的一行文本,并转换成String类型
        String line = value.toString();

        //将这行内容按分隔符空格切割成单词,保存在String数组中
        String[] words = line.split(" ");

        //遍历数组,产生<K2,V2>键值对,形式为<单词,1>
        for (String word : words
             ) {
            //使用context,把map阶段处理的数据发送给reduce阶段作为输入数据
            context.write(new Text(word), new IntWritable(1));
        }
    }
}

(3) Composant réducteur

        Les paires clé-valeur générées par le processus Map seront fusionnées par le composant Reducer. Ici, nous prenons les statistiques de fréquence des mots comme exemple et personnalisons la méthode reduce().

package cn.itcast.mr.wordcount;

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

import java.io.IOException;

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        //定义一个计数器
        int count = 0;

        //遍历一组迭代器,把每一个数量1累加起来构成了单词出现的总次数
        for (IntWritable iw : values
             ) {
            count +=iw.get();
        }

        //向上下文context写入<k3,v3>
        context.write(key, new IntWritable(count));
    }
}

(4) Composant combinateur

        La fonction de ce composant est d'effectuer un calcul de fusion sur les données en double de sortie de l'étape Map, puis d'utiliser la nouvelle paire clé-valeur comme entrée de l'étape Reduce. Si vous souhaitez personnaliser la classe Combiner, vous devez hériter de la classe Reducer et réécrire la méthode reduce(). Le code spécifique est le suivant.

package cn.itcast.mr.wordcount;

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

import java.io.IOException;

public class WordCountCombiner extends Reducer<Text, IntWritable, Text, IntWritable> {
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        //局部汇总
        //定义一个计数器
        int count = 0;

        //遍历一组迭代器,把每一个数量1累加起来构成了单词出现的总次数
        for (IntWritable v : values
             ) {
            count += v.get();
        }

        //向上下文context写入<k3,v3>
        context.write(key, new IntWritable(count));
    }
}

(5) Mode de fonctionnement de MapReduce

        Il existe deux modes de fonctionnement de MapReduce, le mode de fonctionnement local et le mode de fonctionnement en cluster.

a. Mode d'exécution local : simulez l'environnement d'exécution de MapReduce dans l'environnement de développement actuel, et les résultats de sortie des données traitées sont tous locaux.

b. Mode de fonctionnement en cluster : compressez le programme MapReduce dans un package jar, téléchargez-le sur le cluster Yarn pour le fonctionnement et traitez les données et les résultats sur HDFS.

        Ici, nous parlons principalement du mode de fonctionnement local.Pour réaliser le fonctionnement local, nous avons également besoin d'une classe Driver, le code est le suivant.

package cn.itcast.mr.wordcount;

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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

public class WordCountDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //通过 Job 来封装本次 MR 的相关信息
        Configuration conf = new Configuration();
        //配置MR运行模式,使用 local 表示本地模式,可以省略
        conf.set("mapreduce.framework.name","local");
        //获取 Job 运行实例
        Job wcjob = Job.getInstance(conf);
        //指定 MR Job jar运行主类
        wcjob.setJarByClass(WordCountDriver.class);
        //指定本次 MR 所有的 Mapper Combiner Reducer类
        wcjob.setMapperClass(WordCountMapper.class);
        wcjob.setCombinerClass(WordCountCombiner.class); //不指定Combiner的话也不影响结果
        wcjob.setReducerClass(WordCountReducer.class);
        //设置业务逻辑 Mapper 类的输出 key 和 value 的数据类型
        wcjob.setMapOutputKeyClass(Text.class);
        wcjob.setMapOutputValueClass(IntWritable.class);

        //设置业务逻辑 Reducer 类的输出 key 和 value 的数据类型
        wcjob.setOutputKeyClass(Text.class);
        wcjob.setOutputValueClass(IntWritable.class);

        //使用本地模式指定要处理的数据所在的位置
        FileInputFormat.setInputPaths(wcjob,"/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/WordCount/input");
        //使用本地模式指定处理完成后的结果所保持的位置
        FileOutputFormat.setOutputPath(wcjob,new Path("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/WordCount/output"));

        //提交程序并且监控打印程序执行情况
        boolean res = wcjob.waitForCompletion(true);
        System.exit(res ? 0:1);
    }
}

         Une fois l'exécution terminée, un fichier de résultats sera généré localement.

2. Index inversé

(1. Introduction

        L'index inversé est une structure de format de données couramment utilisée dans les systèmes de recherche de documents et est largement utilisé dans les moteurs de recherche de texte intégral. Cela peut être simplement compris comme la recherche de documents en fonction du contenu, plutôt que la recherche de contenu en fonction des documents.

(2) Mise en œuvre de l'étape Map

package cn.itcast.mr.invertedIndex;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileSplit;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class InvertedIndexMapper extends Mapper<LongWritable, Text, Text, Text> {
    //存储单词和文档名称
    private static Text keyInfo = new Text();

    // 存储词频,初始化为1
    private static final Text valueInfo = new Text("1");

    /*
     * 在该方法中将K1、V1转换为K2、V2
     * key: K1行偏移量
     * value: V1行文本数据
     * context: 上下文对象
     * 输出: <MapReduce:file3 "1">
     */

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString();

        // 得到单词数组
        String[] fields = line.split(" ");

        //得到这行数据所在的文件切片
        FileSplit fileSplit = (FileSplit) context.getInputSplit();

        //根据文件切片得到文件名
        String filename = fileSplit.getPath().getName();

        for (String field : fields
             ) {
            // key值由单词和文件名组成,如“MapReduce:file1”
            keyInfo.set(field + ":" + filename);
            context.write(keyInfo, valueInfo);
        }
    }
}

(3) Combiner la mise en œuvre de l'étape

package cn.itcast.mr.invertedIndex;

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

import java.io.IOException;

public class InvertedIndexCombiner extends Reducer<Text, Text, Text, Text> {
    private static Text info = new Text();
    // 输入: <MapReduce:file3 {1,1,...}>
    // 输出:<MapReduce file3:2>
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        int sum = 0;  //统计词频
        //遍历一组迭代器,把每一个数量1累加起来构成了单词出现的总次数
        for (Text value : values) {
            sum += Integer.parseInt(value.toString());
        }
        int splitIndex = key.toString().indexOf(":");
        // 重新设置 value 值由文件名和词频组成
        info.set(key.toString().substring(splitIndex + 1) + ":" + sum);
        // 重新设置 key 值为单词
        key.set(key.toString().substring(0, splitIndex));

        //向上下文context写入<k3,v3>
        context.write(key, info);
    }
}

(4) Mise en œuvre de la phase Réduire

package cn.itcast.mr.invertedIndex;

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

import java.io.IOException;

public class InvertedIndexReducer extends Reducer<Text, Text, Text, Text> {
    private static Text result = new Text();

    // 输入:<MapReduce, file3:2>
    // 输出:<MapReduce, file1:1;file2:1;file3:2;>
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        // 生成文档列表
        StringBuffer fileList = new StringBuffer();
        for (Text value : values) {
            fileList.append(value.toString() + ";");
        }
        result.set(fileList.toString());
        context.write(key, result);
    }
}

(5) Implémentation de la classe principale du programme pilote

package cn.itcast.mr.invertedIndex;

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;

import java.io.IOException;

public class InvertedIndexDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //通过 Job 来封装本次 MR 的相关信息
        Configuration conf = new Configuration();
        //获取 Job 运行实例
        Job job = Job.getInstance(conf);
        //指定 MR Job jar运行主类
        job.setJarByClass(InvertedIndexDriver.class);
        //指定本次 MR 所有的 Mapper Combiner Reducer类
        job.setMapperClass(InvertedIndexMapper.class);
        job.setCombinerClass(InvertedIndexCombiner.class);
        job.setReducerClass(InvertedIndexReducer.class);
        //设置业务逻辑 Mapper 类的输出 key 和 value 的数据类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        //设置业务逻辑 Reducer 类的输出 key 和 value 的数据类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        //使用本地模式指定要处理的数据所在的位置
        FileInputFormat.setInputPaths(job,"/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/InvertedIndex/input");
        //使用本地模式指定处理完成后的结果所保持的位置
        FileOutputFormat.setOutputPath(job,new Path("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/InvertedIndex/output"));

        //提交程序并且监控打印程序执行情况
        boolean res = job.waitForCompletion(true);
        System.exit(res ? 0:1);
    }
}

(6) Affichage des résultats

3. Déduplication des données

(1) Implémentation de l'étape Map

package cn.itcast.mr.dedup;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class DedupMapper extends Mapper<LongWritable, Text, Text, NullWritable> {
    private static Text field = new Text();
    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, NullWritable>.Context context)
            throws IOException, InterruptedException {
        field = value;
        context.write(field,NullWritable.get());
    }
}

(2) Mise en œuvre de la phase Réduire

package cn.itcast.mr.dedup;

import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class DeupReducer extends Reducer<Text, NullWritable, Text, NullWritable> {
    @Override
    protected void reduce(Text key, Iterable<NullWritable> values, Reducer<Text, NullWritable, Text, NullWritable>.Context context)
            throws IOException, InterruptedException {
        context.write(key, NullWritable.get());
    }
}

(3) Implémentation de la classe principale du programme pilote

package cn.itcast.mr.dedup;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
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;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class DedupDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException{
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        job.setJarByClass(DedupDriver.class);
        job.setMapperClass(DedupMapper.class);
        job.setReducerClass(DeupReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);
        FileInputFormat.setInputPaths(job, new Path("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/Dedup/input"));
        FileOutputFormat.setOutputPath(job, new Path("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/Dedup/output"));

        //job.waitForCompletion(true);
        boolean res = job.waitForCompletion(true);
        if (res) {
            FileReader fr = new FileReader("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/Dedup/output/part-r-00000");
            BufferedReader reader= new BufferedReader(fr);
            String str;
            while ( (str = reader.readLine()) != null )
                System.out.println(str);

            System.out.println("运行成功");
        }
        System.exit(res ? 0 : 1);
    }
}

(4) Affichage des résultats

4、HautN

(1) Présentation du cas

        La méthode d'analyse TopN fait référence à la méthode d'installation d'un certain indicateur à partir de l'objet de recherche dans l'ordre inverse ou avant, en prenant les N cas requis et en se concentrant sur l'analyse des N données.

(2) Mise en œuvre de l'étape Map

package cn.itcast.mr.topN;

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

import java.io.IOException;
import java.util.TreeMap;

public class TopNMapper extends Mapper<LongWritable, Text,
        NullWritable, IntWritable> {
    private TreeMap<Integer, String>repToRecordMap =
            new TreeMap<Integer, String>();
    @Override
    public void map (LongWritable key, Text value, Context context) {
        String line = value.toString();
        String[] nums = line.split(" ");
        for (String num : nums
             ) {
            repToRecordMap.put(Integer.parseInt(num), " ");
            if (repToRecordMap.size() > 5) {
                repToRecordMap.remove(repToRecordMap.firstKey());
            }
        }
    }

    @Override
    protected void cleanup(Context context) {
        for (Integer i: repToRecordMap.keySet()
             ) {
            try {
                context.write(NullWritable.get(), new IntWritable(i));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

(3) Mise en œuvre de la phase Réduire

package cn.itcast.mr.topN;


import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;
import java.util.Comparator;
import java.util.TreeMap;

public class TopNReducer extends Reducer<NullWritable, IntWritable, NullWritable, IntWritable> {
    private TreeMap<Integer, String>repToRecordMap = new
            TreeMap<Integer, String>(new Comparator<Integer>() {
        public int compare(Integer a, Integer b) {
            return b-a;
        }
    });
    public void reduce(NullWritable key,
                       Iterable<IntWritable>values, Context context)
        throws IOException, InterruptedException {
        for (IntWritable value : values
             ) {
            repToRecordMap.put(value.get(), " ");
            if (repToRecordMap.size() > 5) {
                repToRecordMap.remove(repToRecordMap.lastKey());
            }
        }
        for (Integer i : repToRecordMap.keySet()
             ) {
            context.write(NullWritable.get(), new IntWritable(i));
        }
    }
}

(4) Implémentation de la classe principale du programme pilote

package cn.itcast.mr.topN;

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

import java.io.BufferedReader;
import java.io.FileReader;

public class TopNDriver {
    public static void main(String[] args) throws Exception{
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        job.setJarByClass(TopNDriver.class);
        job.setMapperClass(TopNMapper.class);
        job.setReducerClass(TopNReducer.class);
        job.setNumReduceTasks(1);
        job.setMapOutputKeyClass(NullWritable.class);
        job.setMapOutputValueClass(IntWritable.class);
        job.setOutputKeyClass(NullWritable.class);
        job.setOutputValueClass(IntWritable.class);
        FileInputFormat.setInputPaths(job, new Path("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/TopN/input"));
        FileOutputFormat.setOutputPath(job, new Path("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/TopN/output"));
        boolean res = job.waitForCompletion(true);
        if (res) {
            FileReader fr = new FileReader("/home/huanganchi/Hadoop/实训项目/HadoopDemo/textHadoop/TopN/output/part-r-00000");
            BufferedReader reader= new BufferedReader(fr);
            String str;
            while ( (str = reader.readLine()) != null )
                System.out.println(str);

            System.out.println("运行成功");
        }

        System.exit(res ? 0 : 1);
    }
}

(5) Affichage des résultats


livres de référence

"Principe et application de la technologie Hadoop Big Data"

 

Je suppose que tu aimes

Origine blog.csdn.net/weixin_63507910/article/details/128540149
conseillé
Classement