MapReduce具体过程

统计hdfs某个文件中重复单词的数目(WordCount),每个单词用空格分隔,统计每个单词的出现频率,说明MapReduce框架的过程。


进行map过程之前,进行Pre-Map过程。框架帮我们把文件切分,NameNode把文件切分成block,每个block最大为128M;文件小于128M时,文件多大形成的block就是多大;一个block不能跨多个文件。

分隔好后,针对每个文件内部,再根据换行符\n分割文件内容,形成key-value对,其中key是这一行首相对文件开头的偏移量,如图中<0,"c b a">,<5,"d c b">,其中“d c b”是第二行,相对于第一行第一个字,d是第五个字符。

这样的key-value对传入map,有几个文件就形成几个map,map内部分成分区(partition)、排序(sort)、有时还有Combine过程。当Pre-Map过程形成的key-value进入map后,map方法逐个处理value,这就开始需要我们自己写一些代码来定义map方法,根据需求,我们需要按空格把每个词分开,将其作为新的key,给每一个词分配相同的value,我们现在指定value为1,这样就形成了新的key-value对,如<"a",1>、<"b",1>、<"c",1>、<"d",1>、<“e”,1>。接下来进入分区过程,分区的依据是用key的哈希值模reduce的个数,当不指定reduce个数是,默认它为1。分区结束后,key-value进入这些分区,并在分区中进行按asc码的排序(sort)。排序结束后,如果我们设定了combine过程,将在同一个分区内进行局部运算(其实是map端的reduce计算),如图中对partition1中相同的部分做了合并形成了<"b",2>,<"c",2>。

接下来进入reduce,同一分区的放到一起,当文件特别大时,用partition0举例,如果某一个partition0有1G数据,另外一个partition0有2G数据,多个partition0的数据合起来有几十G,很明显内存是不够用的,这时候数据fetch到reduce中形成文件时,需要先把一部分数据在内存处理后,经过聚合(merge),再放到磁盘中形成文件,同时进行排序(sort),让key相同的都排列在一起。框架自动把key相同的value放到一起,此时形成了键组,如先前的<"a",1><"a",1><"b",1><"b",2>,形成了键组<"a",{1,1}>,<"b",{1,2}>,然后进入reduce方法,现在又需要自己定义reduce方法,reduce内的key都是不重复的,形成了以a为key,以数组{1,1}的value。把一个键组内的value叠加求和,就可以求出某一单词出现的次数。

注意:对于combine过程,它可以减轻io的负担,减少计算量,但是并不是所有的过程都可以进行combine(局部计算),比如计算平均数,表格的左连接和右连接。

package com.wh.mapper;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class MyTokenizerMapper extends
        Mapper<Object, Text, Text, IntWritable> {
    // 暂存每个传过来的词频计数,均为1,省掉重复申请空间
    private final static IntWritable one = new IntWritable(1);
    // 暂存每个传过来的词的值,省掉重复申请空间
    private Text word = new Text();
    // 核心map方法的具体实现,逐个<key,value>对去处理
    public void map(Object key, Text value, Context context)
            throws IOException, InterruptedException {
        // 用每行的字符串值初始化StringTokenizer
        StringTokenizer itr = new StringTokenizer(value.toString());
        // 循环取得每个空白符分隔出来的每个元素
        while (itr.hasMoreTokens()) {
            // 将取得出的每个元素放到word Text对象中
            word.set(itr.nextToken());
            // 通过context对象,将map的输出逐个输出
            context.write(word, one);
        }
    }
}

Reducer类编写
新类介绍
Reducer:是MapReduce计算框架中Reduce过程的封装
源码编写
package com.wh.reducer;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
//reduce类,实现reduce函数
public class IntSumReducer extends
                Reducer<Text, IntWritable, Text, IntWritable> {
         private IntWritable result = new IntWritable();
         //核心reduce方法的具体实现,逐个<key,List(v1,v2)>去处理
         public void reduce(Text key, Iterable<IntWritable> values,
                      Context context) throws IOException, InterruptedException {
                //暂存每个key组中计算总和
                int sum = 0;
                //加强型for,依次获取迭代器中的每个元素值,即为一个一个的词频数值
                for (IntWritable val : values) {
                      //将key组中的每个词频数值sum到一起
                      sum += val.get();
                }
                //将该key组sum完成的值放到result IntWritable中,使可以序列化输出
                result.set(sum);
                //将计算结果逐条输出
                context.write(key, result);
         }
   }

Driver类编写
新类介绍
Configuration:与hdfs处的configuration一致,负责参数的加载和传递。
Job:是对一轮MapReduce任务的抽象,即一个MapReduce的执行全过程的管理类。
FileInputFormat:指定输入数据的工具类,用于指定任务的输入数据路径。
FileOutputFormat:指定输出数据的工具类,用于指定任务的输出数据路径。
源码编写
package com.wh.driver;
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 com.tianliangedu.mapper.MyTokenizerMapper;
import com.tianliangedu.reducer.IntSumReducer;
public class WordCount {
   // 启动mr的driver方法
   public static void main(String[] args) throws Exception {
       // 得到集群配置参数
       Configuration conf = new Configuration();
       // 设置到本次的job实例中
       Job job = Job.getInstance(conf, "Mrs.Wu HO_o的WordCount");
       // 指定本次执行的主类是WordCount
      job.setJarByClass(WordCount.class);
       // 指定map类
      job.setMapperClass(MyTokenizerMapper.class);
       // 指定combiner类,要么不指定,如果指定,一般与reducer类相同
      job.setCombinerClass(IntSumReducer.class);
       // 指定reducer类
      job.setReducerClass(IntSumReducer.class);
       // 指定job输出的key和value的类型,如果map和reduce输出类型不完全相同,需要重新设置map的output的key和value的class类型
      job.setOutputKeyClass(Text.class);
      job.setOutputValueClass(IntWritable.class);
       // 指定输入数据的路径
      FileInputFormat.addInputPath(job, new Path(args[0]));
       // 指定输出路径,并要求该输出路径一定是不存在的
      FileOutputFormat.setOutputPath(job, new Path(args[1]));
       // 指定job执行模式,等待任务执行完成后,提交任务的客户端才会退出!
      System.exit(job.waitForCompletion(true) ? 0 : 1);
   }
}









  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值