MapReduce实现WordCount以及聊聊Shuffle过程
一、Mapper代码
public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
/**
* 一个Block对应一个Mapper
* 一个行出发一次Mapper中的map
* Key:map的输入,是当前处理的行在文件中的偏移量
* value:map的输入,是当前行的内容
* context:环境对象,用来输出数据
*/
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text,
Text, LongWritable>.Context context)throws IOException, InterruptedException {
String line = value.toString();
String [] words = line.split(" ");
for(String word : words){
context.write(new Text(word), new LongWritable(1));
}
}
}
二、Reducer代码:
public class WCReducer extends Reducer<Text,LongWritable,Text,LongWritable> {
/**
* Reducer进行数据的合并处理
* key:reduce的输入,是map的输出
* values:reduce的输入,是map输出中键相同的值的集合
* context:环境对象,可以输出数据
*/
@Override
protected void reduce(Text key, Iterable<LongWritable> values,
Reducer<Text, LongWritable, Text, LongWritable>.Context context)
throws IOException, InterruptedException {
String word = key.toString();
long count = 0;
for(LongWritable l : values){
count += l.get();
}
context.write(new Text(word), new LongWritable(count));
}
}
三、Dirver代码:
public class WCDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf );
job.setJarByClass(WCDriver.class);
job.setMapperClass(WCMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
FileInputFormat.setInputPaths(job, new Path("/wc/words.txt"));
job.setReducerClass(WCReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
FileOutputFormat.setOutputPath(job, new Path("/wc/result01"));
job.waitForCompletion(true);
}
}
四、发布
然后将项目打成jar包,上传到虚拟机上,执行:hadoop -jar xxx.jar 执行
五、Combiner合并
合并的目的是减少Reduce端 迭代的次数
combiner是实现Mapper端进行key的归并,combiner具有类似本地的reduce功能。如果不用combiner,那么所有的结果都是reduce完成,效率会很低。使用combiner先做合并,然后发往reduce。
六、Shuffle
系统将map输出作为reduce输入称为shuffle。shuffle是MapReduce的“心脏”,是奇迹发生的地方。
知识点1:Spill的分区和Reduce分区有关吗?有关
知识点2:一定会产生spill文件吗?不一定,假设一开始的输出就没有达到溢写阈值,就不会发生Spill过程,也就不会发生Merge过程
知识点3:假设输出数据是90MB,当写满80MB时,发生一次Spill,剩下的10MB会通过flush()刷到文件里,确保数据不丢失。
知识点4:溢写缓冲区大小默认是100MB,但是可以更改。阈值也可以改
知识点5:一个Map任务对应一个溢写缓冲区。
知识点6:一个Map任务结束后,会生成一个结果文件(前提是发生了Spill和Merge过程)
知识点7:不能单纯的根据128MB切片来决定Spill的文件数量,要根据Mapper里的代码来决定
知识点8:Hadoop的一个调优策略是调大溢写缓冲区大小,从而减少Spill溢写次数,介绍磁盘I/O次数,从而提供性能。
知识点9:什么时候开始Merge过程?一个Map任务完成时,即不再输出k,v对的时候,开始Merge。