目录
MapReduce中的Combiner组件
1 Combiner组件的作用
2 定义Combiner组件
3 什么时候可以使用Combiner组件?
MapReduce中的Combiner组件
由于map的并行度与split(切片)相关,与数据有关。数据越大,mapTask的并行度就越大,而且map的实质就是将一行数据拆分,然后打个标记。这就导致所有数据的计算任务,都在reduce中。而且原本reduce端的并行度就不高,容易产生性能不高等问题。如果map端可以分担一些计算任务,那么reduce端的性能肯定会有所提高。
1 Combiner组件的作用
(1)减少Reduce端的数据量,相当于在Map端做了一次合并;Combiner本质上相当于在map端进行了一次reduce操作。
(2)减少shuffle过程的数据量,提高分布式计算程序的整体性能;
效果图为:
2 定义Combiner组件
Combiner组件中的业务逻辑与reducer中的业务逻辑相似。MR中,默认没有没有Combiner组件,需要自定义组件并实现。
具体实现方法为:
①自定义Combiner类,并继承Reducer类
类的泛型参数:前两个泛型是map的输出KV,后面两个是reduce的输入KV。
public class MyCombiner extends Reducer<KEYIN, VALUEIN, KEYOUT, VALUEOUT>{}
当我们在写MR程序时,Map端的输出就是Reduce端的输入。所以Combiner的前两个泛型和后两个泛型的类型是一致的。
② 重写reduce()方法
该方法对应的是一个切片(split,mapTask), 该方法只对一个mapTask中的数据进行统计。
package com.ethan.mrcombiner;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
/**
* 前两个泛型map的输出,后面两个是reduce的输入
* 前后两个泛型类型一致
* @Description Combiner
* @author Ethan
* @date 2020年1月31日
*/
public class MyCombiner extends Reducer<Text, IntWritable, Text, IntWritable>{
/**
* 重写reduce方法
* 该方法对应的是一个切片(split,mapTask)
* 该方法只对一个mapTask中的数据进行统计
* key:map发出的key
* values:map发出相同key的一组value
*
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable v : values) {
sum += v.get();
}
context.write(key, new IntWritable(sum));
}}
③在驱动类中添加该Combiner类
job.setCombinerClass(MyCombiner.class);
因为Combiner本质上相当于在map端进行了一次reduce操作,有时候没必要重写一遍reduce方法,通常情况下,都可以直接使用Reducer类作为自定义的Combiner类。如:
job.setCombinerClass(WordCountReducer.class);
注意:
Combiner组件针对的、对应的是单个mapTask <----> 切片 <----> 数据块,不可以对多个mapTask结果进行合并。
Reducer针对的是所有mapTask,是全局的。
3 什么时候可以使用Combiner组件?
可以使用:求和、求最大、最小值
不可以使用:求平均值
使用场景:以每个mapTask为单位,进行计算的最终结果,不会影响以所有mapTask为单位进行结算的结果。具体应用还需根据自己的业务逻辑详细分析,能否利用combiner进行优化。
Combiner组件不参与业务逻辑,只是一个map到reduce之间的优化组件,有没有Combiner对整体业务逻辑没有影响。