Mapper中map方法下context.write的流程与代码详解
来源:互联网 发布:openstack用哪些数据库 编辑:程序博客网 时间:2024/05/21 06:49
本文的分析基于Hadoop 2.4.0版本
任何Map任务在Hadoop中都会被一个MapTask对象所详细描述,MapTask会最终调用其run方法来执行它对应的Map任务,需要执行任务就必须要有相关的输入输出信息,这些信息都包含在Map任务对应的Context对象中,Context通过RecordReader来获取输入数据,Map任务的输入文件保存在InputSplit中,这个InputSplit保存了文件的路径、范围和位置;通过RecordWriter来保存处理后的数据,在Context中还有个任务报告器TaskReporter,它不断向ApplicationMaster报告任务的执行进度
Mapper abstract class Context implements MapContext(接口)
Reducer的abstract class Context implements ReduceContext(接口)
MapContext和ReduceContext都是extends TaskInputOutputContext(接口)
interface TaskInputOutputContext的实现abstractclass TaskInputOutputContextImpl
TaskInputOutputContextImpl的write方法由abstractclass RecordWriter<KEYOUT,VALUEOUT>实现
Map和Reduce中的Context对象的write方法都是调用RecordWriter的write方法
其中RecordWriter有很多的实现类如classMapTask下的privateclassNewOutputCollector、
private class NewDirectOutputCollector
以NewOutputCollector举例:
public void write(K key, V value)throws IOException, InterruptedException {
collector.collect(key, value,partitioner.getPartition(key,value,partitions));
}
其中collector的类型是MapOutputCollector(接口),最后实现类是static class MapOutputBuffer,是MapTask下的类,方法签名如下:
public synchronized void collect(K key, V value, final int partition ) throws IOException
在2.x中对1.x进行了改进,1.x中的int [] kvoffsets, int[] kvindices被2.x中的IntBufferkvmeta给替换了
首选会调用publicvoid init(MapOutputCollector.Context context 方法进行初始化)
什么时候调用init的呢?
如果是使用runNewMapper的话,当getNumReduceTasks() != 0时,调用private <KEY, VALUE> MapOutputCollector<KEY,VALUE>createSortingCollector(JobConfjob, TaskReporter reporter)方法内部调用的collector.init(context),其中在NewOutputCollector类的构造方法中调用了collector =createSortingCollector(job, reporter),getNumReduceTasks() == 0时,调用另一种直接的方式
使用runOldMapper的话,是直接当numReduceTasks > 0时调用createSortingCollector(job, reporter),当numReduceTasks =0时,调用另一种直接的方式
final float spillper = job.getFloat(JobContext.MAP_SORT_SPILL_PERCENT, (float)0.8);
final int sortmb = job.getInt(JobContext.IO_SORT_MB, 100);
key和value需要进行序列化的操作
keyClass = (Class<K>)job.getMapOutputKeyClass();
valClass = (Class<V>)job.getMapOutputValueClass();
serializationFactory = new SerializationFactory(job);
keySerializer = serializationFactory.getSerializer(keyClass);
keySerializer.open(bb);
valSerializer = serializationFactory.getSerializer(valClass);
valSerializer.open(bb);
初始化操作之后就执行public synchronized void collect(K key,V value, final int partition)方法
然后执行flush方法:将缓存中的数据刷到磁盘上
进行spill的时候,先是对缓存中的数据进行排序
sorter.sort(MapOutputBuffer.this, mstart, mend,reporter)MapTask的运行主要代码:
MapTask的入口是run方法publicvoid run(final JobConf job,final TaskUmbilicalProtocol umbilical)
if (isMapTask()) {
// 如果没有reducer的任务,map阶段会支配所有的进程
if (conf.getNumReduceTasks() == 0) {
mapPhase = getProgress().addPhase("map", 1.0f);
} else {
// 如果有reducer的任务,全部被分为map阶段和sort阶段,各自占据一定的处理过程.
mapPhase = getProgress().addPhase("map", 0.667f);
sortPhase =getProgress().addPhase("sort", 0.333f);
}
}
//判断是否使用新的api
boolean useNewApi = job.getUseNewMapper()
Configuration类中的方法,默认是false
public boolean getUseNewMapper() {
return getBoolean("mapred.mapper.new-api",false);
}
//useNewAPi是关于committer的设置不同,
initialize(job, getJobID(), reporter,useNewApi);
if (useNewApi) {
if (LOG.isDebugEnabled()) {
LOG.debug("using new api for outputcommitter");
}
outputFormat =
ReflectionUtils.newInstance(taskContext.getOutputFormatClass(), job);
committer = outputFormat.getOutputCommitter(taskContext);
} else {
committer = conf.getOutputCommitter();
}
做一些处理操作
if (jobCleanup) {
runJobCleanupTask(umbilical, reporter);
return;
}
if (jobSetup) {
runJobSetupTask(umbilical, reporter);
return;
}
if (taskCleanup) {
runTaskCleanupTask(umbilical, reporter);
return;
}
然后
if (useNewApi) {
runNewMapper(job, splitMetaInfo, umbilical, reporter);
} else {
runOldMapper(job, splitMetaInfo, umbilical, reporter);
}
runNewMapper与runOldMapper的不同,对代码的不同包装,实现效果基本相同- Mapper中map方法下context.write的流程与代码详解
- hadoop 中context.collect 和 context.write的区别
- Hadoop 中context.collect 和 context.write的区别
- Mapper中setup、map、cleanup的浅析
- Mapper中insert方法与insertSelective的区别
- PrintWriter中write与println方法的区别
- PrintWriter中write与println方法的区别
- HDFS write流程与代码分析(Hadoop 2.0)
- android中context的详解
- Mybatis中配置Mapper的方法
- hadoop中mapper类的setup方法
- Mybatis中配置Mapper的方法
- Mybatis中配置Mapper的方法
- Mybatis中配置Mapper的方法
- Mybatis中配置Mapper的方法
- Mybatis中配置Mapper的方法
- Mybatis中配置Mapper的方法
- Mybatis中配置Mapper的方法
- 杭电 Moving Tables
- android 状态机
- 关于字符编码
- 正则表达式与文本格式化处理
- 简单的实现Scrollview点击左右滑动
- Mapper中map方法下context.write的流程与代码详解
- 010给定一个循环链表,实现一个算法返回这个环的开始结点 (keep it up)
- 转义字符及字符串示例
- leetcode Unique Binary Search Trees II
- The area
- 黑马程序员_实现java快速排序代码详解
- cocos2dx塔防游戏逻辑
- JS动态添加行
- C#List<>能按照List中的对象某个属性排序