MapReduce经典案例——词频统计

MapReduce经典案例——词频统计

一、测试文件

test.txt

二、代码模块

1、Mapper组件

  • WordCountMapper.java

    package cn.itcast.hadoop.mr;
    
    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;
    
    /**
     *
     * 这里就是MapReduce程序 Map阶段业务逻辑实现的类 Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
     *
     * KEYIN:表示mapper数据输入时key的数据类型,在默认读取数据组件下,叫作ImportFormat,它的行为是每行读取待处理的数据
     * 读取一行,就返回一行给MR程序,这种情况下 KEYIN就表示每一行的起始偏移,因此数据类型是Long
     *
     * VALUEIN:表示mapper数据输入的时候Value的数据类型,在默认读取数据组件下,valueIN就表示读取的一行内容 因此数据类型是String
     *
     * KEYOUT:表示mapper阶段数据输出的时候key的数据类型,在本案例中输出的key是单词,因此数据类型是String
     * ValueOUT:表示mapper阶段数据输出的时候value的数据类型,在本案例中输出的value是单次的此书,因此数据类型是Integer
     *
     * 这里所说的数据类型String,Long都是JDK的自带的类型,数据在分布式系统中跨网络传输就需要将数据序列化,默认JDK序列化时效率低下,因此
     * 使用Hadoop封装的序列化类型。 long--LongWritable String --Text Integer intWritable ....
     *
     *
     *
     *
     *
     * @author itcast
     *
     */
    public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
        /**
         * 这里就是mapper阶段具体业务逻辑实现的方法 该方法的调用取决于读取数据的组件有没有给MR传入数据
         * 如果有数据传入,每一个<k,v>对,map就会被调用一次
         */
        @Override
        protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
                throws IOException, InterruptedException {
            // 拿到传入进来的一行内容,把数据类型转换为String
            String line = value.toString();
            // 将这行内容按照分隔符切割
            String[] words = line.split(" ");
            // 遍历数组,每出现一个单词就标记一个数组1 例如:<单词,1>
            for (String word : words) {
                // 使用MR上下文context,把Map阶段处理的数据发送给Reduce阶段作为输入数据
                context.write(new Text(word), new IntWritable(1));
                //第一行 hadoop hadoop spark  发送出去的是<hadoop,1><hadoop,1><spark,1>
            }
        }
    }
    

2、Reducer组件

  • WordCountReducer.java

    package cn.itcast.hadoop.mr;
    import java.io.IOException;
    
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    //都要继承Reducer 这就是我们所说的变成模型,只需要套模板就行了
    /**
     * 这里是MR程序 reducer阶段处理的类
     *
     * KEYIN:就是Reducer阶段输入的数据key类型,对应Mapper阶段输出KEY类型 ,在本案例中就是单词
     *
     * VALUEIN:就是Reducer阶段输入的数据value类型,对应Mapper阶段输出VALUE类型 ,在本案例中就是个数
     *
     * KEYOUT:就是Reducer阶段输出的数据key类型,在本案例中,就是单词 Text
     *
     * VALUEOUT:reducer阶段输出的数据value类型,在本案例中,就是单词的总次数
     *
     * @author itcast
     *
     */
    public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    
        /**
         * 这里是REDUCE阶段具体业务类的实现方法
         * 第一行 hadoop hadoop spark  发送出去的是<hadoop,1><hadoop,1><spark,1>
         * reduce接受所有来自Map阶段处理的数据之后,按照Key的字典序进行排序
         * 按照key是否相同作一组去调用reduce方法
         * 本方法的key就是这一组相同的kv对 共同的Key
         * 把这一组的所有v作为一个迭代器传入我们的reduce方法
         *
         * 迭代器:<hadoop,[1,1]>
         *
         */
        @Override
        protected void reduce(Text key, Iterable<IntWritable> value,
                              Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
            //定义一个计数器
            int count = 0;
            //遍历一组迭代器,把每一个数量1累加起来就构成了单词的总次数
    
            //
            for (IntWritable iw : value) {
                count += iw.get();
            }
            context.write(key, new IntWritable(count));
        }
    }
    

3、Combiner组件

  • WordCountCombiner.java

    package cn.itcast.hadoop.mr;
    import java.io.IOException;
    
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    public class WordCountCombiner 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 {
            // 1.局部汇总
            int count = 0;
            for (IntWritable v : values) {
                count += v.get();
            }
            context.write(key, new IntWritable(count));
        }
    }
    

4、mapReduce运行

  • WordCountDriver.java

    package cn.itcast.hadoop.mr;
    
    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;
    
    /**
     * Driver类就是MR程序运行的主类,本类中组装了一些程序运行时所需要的信息
     * 比如:使用的Mapper类是什么,Reducer类,数据在什么地方,输出在哪里
     *
     * @author itcast
     *
     */
    public class WordCountDriver {
    
        public static void main(String[] args) throws Exception {
            // 通过Job来封装本次MR的相关信息
            Configuration conf = new Configuration();
            conf.set("mapreduce.framework.name", "local");
            Job wcjob = Job.getInstance(conf);
    
            // 指定MR Job jar包运行主类
            wcjob.setJarByClass(WordCountDriver.class);
            // 指定本次MR所有的Mapper Reducer类
            wcjob.setMapperClass(WordCountMapper.class);
            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);
    
            //设置Combiner组件
            wcjob.setCombinerClass(WordCountCombiner.class);
    
    
            // 指定要处理的数据所在的位置
            FileInputFormat.setInputPaths(wcjob, "E:\\hadoop\\fileStorage\\WordFrequencyStatistics\\fileTest\\test.txt");
            // 指定处理完成之后的结果所保存的位置
            FileOutputFormat.setOutputPath(wcjob, new Path("E:\\hadoop\\fileStorage\\WordFrequencyStatistics\\fileDow\\dow.txt"));
    
            // 提交程序并且监控打印程序执行情况
            boolean res = wcjob.waitForCompletion(true);
            System.exit(res ? 0 : 1);
        }
    }
    

三、效果展示

1、生成本地文件

image-20240419150006825

(1)进入dow01.txt

image-20240419150102459

  • part-r-00000

    image-20240419150309320

(2)进入dow02.txt

image-20240419150417776

  • part-r-00000

    image-20240419150453648

FINISH

posted @ 2024-04-19 15:07  朝暮青丝  阅读(156)  评论(0编辑  收藏  举报