默认的分区器
public class HashPartitioner<K, V> extends Partitioner<K, V> {
/** Use {@link Object#hashCode()} to partition. */
public int getPartition(K key, V value,
int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
- 获取key的哈希值
- 使用key的哈希值对reduce任务数求模
- 这样做的目的是可以把(key,value)对均匀的分发到各个对应编号的reduce task节点上,达到reduce task节点的负载均衡。
自定义Partitioner
- 自定义类继承Partitioner,重写getPartition()方法
- 在Driver中,设置自定义的Partitioner
- 自定义Partition后,根据自定义的Partitioner的逻辑设置相应的ReduceTask
- 如果
ReduceTask的数量 > getPartition
的结果数,则会多产生几个空的输出文件 - 如果
1 < ReduceTask的数量 < getPartition
的结果数,则会一部分文件无处存放Excpetion
- 如果
ReduceTask的数量 =1
的结果数,则会多产生几个空的输出文件 - 分区号必须从零开始,逐一累加
- 如果
// 按照手机号前缀不同,分到不同的5个区
public class ProvincePartitioner extends Partitioner<FlowBean, Text> {
@Override
public int getPartition(FlowBean flowBean, Text text, int numPartitions) {
String preNum = text.toString().substring(0, 3);
int partition = 4;
if ("136".equals(preNum)) {
partition = 0;
}else if ("137".equals(preNum)){
partition = 1;
}else if ("138".equals(preNum)){
partition = 2;
}else if ("139".equals(preNum)){
partition = 3;
}
return partition;
}
}
Driver端设置
// 指定自定义数据分区
job.setPartitionerClass(ProvincePartitioner.class);
// 同时指定相应数量的reduce task
job.setNumReduceTasks(5);