Mapreduce确保每个reducer的输入都是按key键排序的。系统执行排序的过程(即将map输出作为输入传给reducer)称为shuffle。map之后reduce之前都是suffer.
就是下面这个图从mapper程序出来到缓冲区,缓冲区到分区的过程中对key进行排序,分区是在内存中操作,然后落盘到硬盘上,然后传给reduce的过程中还要进行合并,这个过程称为shuffle.
![](https://i-blog.csdnimg.cn/blog_migrate/cbabb348e6873b8a4a9192343eba84ef.png)
默认是使用key的hash进行分区的.
![](https://i-blog.csdnimg.cn/blog_migrate/1711d0e93df7885512cb9c80cd12baa7.png)
实际操作
MapReduce序列化即案例演示-02
按手机号码前三位进行分区,135,136,137,138各一分区,剩下的为一分区.
在案例2上进行操作,写一个自定义分区类.
package com.buba.mapreduce.flow;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
//key和value的类型为mapper的输出key,value的类型
public class FlowPartitioner extends Partitioner<Text,FlowBean> {
@Override
public int getPartition(Text key, FlowBean flowBean, int i) {
//1.需求:根据电话号码的前三位是几来分区
//拿到电话号码的前三位
String phoneNum = key.toString().substring(0, 3);
//总共定义了五个分区
//剩下的为4分区
int partition = 4;
if("135".equals(phoneNum)){ //如果开头是135那么就把这个key放0分区.
partition = 0;
}else if("136".equals(phoneNum)){//如果开头是136那么就把这个key放1分区.
partition = 1;
}else if("137".equals(phoneNum)){//如果开头是137那么就把这个key放2分区.
partition = 2;
}else if("138".equals(phoneNum)){//如果开头是138那么就把这个key放3分区.
partition = 3;
}
return partition;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/cc9d9653f9f92d30a8f5839556bbb0db.png)
//设置分区
job.setPartitionerClass(FlowPartitioner.class);
//设置reducetask个数也就是得和FlowPartitioner里设置的分区个数一致
job.setNumReduceTasks(5);
执行完后就按自定义的生成五个分区了
![](https://i-blog.csdnimg.cn/blog_migrate/10d3f29582bac997ca48c77f0e4b818c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/afe12f301afe60ea2c1d189dc343b942.png)
注意:
如果reduceTask的数量> getPartition的结果数,则会多产生几个空的输出文件part-r-000xx;
如果1<reduceTask的数量<getPartition的结果数,则有一部分分区数据无处安放,会Exception;
如果reduceTask的数量=1,则不管mapTask端输出多少个分区文件,最终结果都交给这一个reduceTask,最终也就只会产生一个结果文件 part-r-00000;
例如:假设自定义分区数为5,则
(1)job.setNumReduceTasks(1);会正常运行,只不过会产生一个输出文件
(2)job.setNumReduceTasks(2);会报错
(3)job.setNumReduceTasks(6);大于5,程序会正常运行,会产生空文件
MapReduce概述和编写简单案例-01
wordcount案例上按单词首字母的ASCLL码的基偶进行分区
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class WordCountPartitioner extends Partitioner<Text, IntWritable>{
// hadoop
@Override
public int getPartition(Text key, IntWritable value, int numPartitions) {
// 需求:按照单词首字母的ASCII的奇偶分区
String line = key.toString();
// 1 截取首字母
String firword = line.substring(0, 1);
// 2 转换成ASCII
char[] charArray = firword.toCharArray();
int result = charArray[0];
// 3 按照奇偶分区
if (result % 2 ==0 ) {
return 0;
}else {
return 1;
}
}
}
然后把driver里的 setNumReduceTasks(2);设置为2就可以了