Combiner 是 MapReduce 程序中 Mapper 和 Reducer 之外的一种组件,它的作用是在 maptask
之后给 maptask 的结果进行局部汇总,以减轻 reducetask 的计算负载,减少网络传输。
Combiner 和 Reducer 一样,编写一个类,然后继承 Reducer,reduce 方法中写具体的 Combiner逻辑,然后在 job 中设置 Combiner 组件:job.setCombinerClass(FlowSumCombine.class)
例如求平均值:
maptask01:
1:4 1:5 1:3
2:4 2:6
maptask02:
1:6 1:8
2:7 2:8 2:9
没有combiner组件:
reduce求平均值:
1:4+5+3+6+8/5=5.2
添加combiner:
maptask01:1:4+5+3/3=4
maptask02:1:6+8/2=7
reduce:
1:4 1:7
:(4+7)/2=5.5!=5.2 结果会有偏差
import java.io.IOException;
import java.io.Serializable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
@Override
protected void map(LongWritable key,
Text value,
Context context)
throws IOException, InterruptedException {
//拿到每一行的内容 进行分割
//将text---String
String line = value.toString();
//拆分单词
String[] words = line.split("\t");
//循环遍历每一个单词 进行打标机 1 发送给reduce进行统一统计
for(String w:words){
//参数1:key 参数2:value
//String--text
Text k=new Text(w);
IntWritable v=new IntWritable(1);
context.write(k, v);
}
}
}
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
/**
* 这个方法的调用频率:每组调用一次 有几组会调用几次
* 分组规则:
* key相同的为一组
* hello,1 hello,1 hadoop,1 hello,1
* key:reduce输入的 这里指的是单词 每一组中的一个key
* values:每一组中的所有value <1,1,1>
*/
@Override
protected void reduce(Text key,
Iterable values,
Context context) throws IOException, InterruptedException {
//进行词频统计
int sum=0;
//循环变遍历values 求和
for(IntWritable v:values){
//v.get() 这个是将intwritable转换为int
sum+=v.get();
}
context.write(key, new IntWritable(sum));
}
}
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class MyCombiner extends Reducer<Text, IntWritable, Text, IntWritable>{
@Override
protected void reduce(Text key, Iterable values,
Reducer.Context context) throws IOException, InterruptedException {
int sum=0;
for(IntWritable i:values){
sum+=i.get();
}
context.write(key, new IntWritable(sum));
}
}
package com.ghgj.cn.combiner;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineFileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class Driver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
System.setProperty("HADOOP_USER_NAME", "hadoop");
//加载配置文件
Configuration conf=new Configuration();
//启动一个job 一个map reduce程序 这里叫做一个job
Job job=Job.getInstance(conf);
//指定job运行的主类
job.setJarByClass(Driver.class);
//指定这个job的mapper类和reduce类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//指定map的输出的key 和 value的类型
//这里为什么还要指定 泛型的只在编译的时候有作用 运行会自动擦除 所以在这里需要指定一下
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//指定reduce输出的key和value类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//指定combiner组件
job.setCombinerClass(MyCombiner.class);
//job.setCombinerClass(WordCountReducer.class);
FileInputFormat.addInputPath(job, new Path("hdfs://hadoop01:9000/in"));
//添加输出路径 输出路径一定不能存在 怕如果存在会进行覆盖
FileOutputFormat.setOutputPath(job, new Path("hdfs://hadoop01:9000/combine02"));
//提交job
job.waitForCompletion(true);
}
}