分区操作
为什么要分区?
要求将统计结果按照条件输出到不同文件中(分区)。比如:将统计结果按
照手机归属地不同省份输出到不同文件中(分区)
默认 partition 分区
/**
源码中:numReduceTasks如果等于1 不会走getPartition方法
numReduceTasks:默认是1
*/
public class HashPartitioner extends Partitioner {
public int getPartition(K key, V value, int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
默认分区是根据 key 的 hashCode 对 reduceTasks 个数取模得到的。
用户没法控制哪个key 存储到哪个分区
自定义Partition
(1)自定义类继承 Partitioner,重写 getPartition()方法
/**
该方法返回不同的partition的值,从而就控制了分区个数、前提是numReduceTasks不等于1
KV:是Map的输出
*/
public class ProvincePartitioner extends Partitioner {
@Override
public int getPartition(Text key, FlowBean value, int numPartitions) {
// 1 获取电话号码的前三位
String preNum = key.toString().substring(0, 3);
int partition = 4;
// 2 判断是哪个省
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;
}
}
(2)在Runner类中设置partition
job.setPartitionerClass(CustomPartitioner.class);
(3)自定义 partition 后,要根据自定义 partitioner 的逻辑设置相应数量的 reduce task
job.setNumReduceTasks(5);
(4)注意:
如果 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,程序会正常运行,会产生空文件
本博客仅为博主学习总结,感谢各大网络平台的资料。蟹蟹!!