学习资料来源于:
《Hadoop权威指南》
https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hadoop-MapReduce.md
感谢🙏
Combiner
比较熟悉的MapReduce工作流程如下:

-
首先从local HDFS中读取文件,即我们将要在主方法中定义的InputPath。
-
其次读取出来的文件交给InputFormat处理,InputFormat将文件拆分为多个InputSplit。
-
得到的多个 InputSplit将会经过 RecordReader层的处理,变成标准的<key,value>键值对,此时,预处理部分才结束,只有这些键值对才能作为Map函数的输入。
-
经过map层的处理之后,开始介绍我们的Combiner 。首先Combiner不是必须的,这是可选的,事实上如果没有必要使用Combiner时使用了Combiner反而会降低效率。可以把Combiner理解为本地节点的Reduce操作,它将对本地map的输出进行一次类似Reduce的操作,这样做的好处是能够减少最终从map节点往reduce节点传输的记录的数量,减少贷款提升效率。
此处以统计词汇频率为例,给出如下两张图说明,有无combiner的区别。
without combiner

with combiner

可以发现,使用了Combiner之后,传输的键值对的数量由12变成10,在某些实际的应用场景下,Combiner有时能提升数百倍的效率。
partitioner
Partitioner主要适用于某些分类的需求,可以把Partitioner理解为一个分类器,比如要对最终结果按key值分类输出到不同的文件中去,此时就要用到Partitioner。
默认的 MapReduce的分类规则
在构建一个Job的时候,如果不指定Partitioner,则默认使用HashPartitioner,对key的值进行取Hash值最后再对numReduceTasks进行取余操作。给出实现如下:
public class HashPartitioner<K, V> extends Partitioner<K, V> {
public int getPartition(K key, V value,
int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
自定义分类规则
自定义一个继承了Partitioner的子类,实现getPartitioner方法,最终在主方法中给作业设置分类规则,并且要设置Reducer的数量。
public class CustomPartitioner extends Partitioner<Text, IntWritable> {
public int getPartition(Text text, IntWritable intWritable, int numPartitions) {
return WordCountDataUtils.WORD_LIST.indexOf(text.toString());
}
}
// 设置自定义分区规则
job.setPartitionerClass(CustomPartitioner.class);
// 设置 reduce 个数
job.setNumReduceTasks(WordCountDataUtils.WORD_LIST.size());
网友评论