一共8个步骤:

1. map任务处理

1.1 读取hdfs中的文件。每一行解析成一个<k,v>。(每一个键值对调用一次map函数)

1.2 覆盖map(),接收1.1产生的<k,v>,进行处理,转换为新的<k,v>输出

1.3 对1.2输出的<k,v>进行分区。默认分为1个区。

1.4 对不同分区中的数据进行排序(按照k)、分组。分组指的是相同key的value放到一个集合中。

1.5 (可选)对分组后的数据进行规约。


2.reduce任务处理

2.1 多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点上。

2.2 对多个map的输出进行合并、排序。覆盖reduce函数,接收的是分组后的数据,实现自己的业务逻辑,处理后,产生新的<k,v>输出

2.3 对reduce输出的<k,v>写到hdfs中。




最主要的变化在

1.1 从文件读取成<偏移量,文本行内容>形式(注意空格,回车换行都算一个偏移量)

1.2 对1.1内容转换成<文本行内容,1><文本行内容,1><文本行内容,1>形式

1.4 对1.2内容先排序,再分组成<文本行内容,{1,1,1}>形式  这样表示此文本行内容出现了3次

2.2  对map任务输出的<文本行内容,{1,1,1}>形式形式转换成<文本行内容,3>形式



例如:hdfs中hello文件的处理过程(统计各个单词出现的个数,以键值对形式返回)

hello文件内容:

hello java

hello hadoop

hello java


需要得到的结果是:

hello java 2

hello hadoop


1. map任务处理

1.1读取hdfs中hello文件。解析每一行内容,输出的是:<0,hello java><11,hello hadoop><22,hello java>  键表示偏移量,从1开始第一行hello(5个)+空格(1个)+java(4个)+回车换行(1个)=11   (偏移量从1开始计数)

1.2遍历每个键值对,产生新的键值对    

     即从<0,hello java><11,hello hadoop><22,hello java>类型转换成<hello java,1><hello hadoop,1><hello java,1>的形式输出

public void map(k, v, ctx){
   String[] splited = v.split("\t");
   for(String word : splited){
      ctx.write(word, 1);
   }
}


1.3对1.2输出的<k,v>进行分区。默认分为1个区。(暂不干预)

1.4对不同分区中的数据进行排序(按照k)、分组。将<hello java,1><hello hadoop,1><hello java,1>类型

     先排序:<hello java,1><hello java,1><hello hadoop,1>

     再分组:<hello java,{1,1}><hello hadoop,{1}>

1.5 (可选)对分组后的数据进行规约。


2.reduce任务处理

2.1 多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点上。(框架自动完成)

2.2 对多个map的输出进行合并、排序。覆盖reduce函数,接收的是分组后的数据,实现自己的业务逻辑,处理后,产生新的<k,v>输出

因为合并、排序在map的1.4步已经完成,这里只需要覆写reduce函数,实现自己的逻辑即可。由于这里是统计各个单词的出现次数,输出<hello java,2><hello hadoop 1>

//reduce函数被调用的次数是2,因为接收到map任务输出的内容为2个键值对
public void reduce(k,vs, ctx){
    long sum = 0L;
    for(long times : vs){
        sum += times;    
    }  
    ctx.write(k, sum);
}


2.3 对reduce输出的<k,v>写到hdfs中。