3.3.3 OutputFormat接口的设计与实现

OutputFormat主要用于描述输出数据的格式,它能够将用户提供的key/value对写入特定格式的文件中。本小节将介绍Hadoop如何设计OutputFormat接口,以及一些常用的OutputFormat实现。

1.旧版API的OutputFormat解析

如图3-12所示,在旧版API中,OutputFormat是一个接口,它包含两个方法:


RecordWriter<K, V>getRecordWriter(FileSystem ignored, JobConf job,

String name, Progressable progress)

throws IOException;

void checkOutputSpecs(FileSystem ignored, JobConf job)throws IOException;


checkOutputSpecs方法一般在用户作业被提交到JobTracker之前,由JobClient自动调用,以检查输出目录是否合法。

3.3.3 OutputFormat接口的设计与实现 - 图1

图 3-12 旧版API的OutputFormat类图

getRecordWriter方法返回一个RecordWriter类对象。该类中的方法write接收一个key/value对,并将之写入文件。在Task执行过程中,MapReduce框架会将map()或者reduce()函数产生的结果传入write方法,主要代码(经过简化)如下。

假设用户编写的map()函数如下:


public void map(Text key, Text value,

OutputCollector<Text, Text>output,

Reporter reporter)throws IOException{

//根据当前key/value产生新的输出<newKey, newValue>,并输出

……

output.collect(newKey, newValue);

}


则函数output.collect(newKey, newValue)内部执行代码如下:


RecordWriter<K, V>out=job.getOutputFormat().getRecordWriter(……);

out.write(newKey, newValue);


Hadoop自带了很多OutputFormat实现,它们与InputFormat实现相对应,具体如图3-13所示。所有基于文件的OutputFormat实现的基类为FileOutputFormat,并由此派生出一些基于文本文件格式、二进制文件格式的或者多输出的实现。

3.3.3 OutputFormat接口的设计与实现 - 图2

图 3-13 Hadoop MapReduce自带OutputFormat实现的类层次图

为了深入分析OutputFormat的实现方法,我们选取比较有代表性的FileOutputFormat类进行分析。同介绍InputFormat实现的思路一样,我们先介绍基类FileOutputFormat,再介绍其派生类TextOutputFormat。

基类FileOutputFormat需要提供所有基于文件的OutputFormat实现的公共功能,总结起来,主要有以下两个:

(1)实现checkOutputSpecs接口

该接口在作业运行之前被调用,默认功能是检查用户配置的输出目录是否存在,如果存在则抛出异常,以防止之前的数据被覆盖。

(2)处理side-effect file

任务的side-effect file并不是任务的最终输出文件,而是具有特殊用途的任务专属文件。它的典型应用是执行推测式任务。在Hadoop中,因为硬件老化、网络故障等原因,同一个作业的某些任务执行速度可能明显慢于其他任务,这种任务会拖慢整个作业的执行速度。为了对这种“慢任务”进行优化,Hadoop会为之在另外一个节点上启动一个相同的任务,该任务便被称为推测式任务,最先完成任务的计算结果便是这块数据对应的处理结果。为防止这两个任务同时往一个输出文件中写入数据时发生写冲突,FileOutputFormat会为每个Task的数据创建一个side-effect file,并将产生的数据临时写入该文件,待Task完成后,再移动到最终输出目录中。这些文件的相关操作,比如创建、删除、移动等,均由OutputCommitter完成。它是一个接口,Hadoop提供了默认实现FileOutputCommitter,用户也可以根据自己的需求编写OutputCommitter实现,并通过参数{mapred.output.committer.class}指定。OutputCommitter接口定义以及FileOutputCommitter对应的实现如表3-2所示。

3.3.3 OutputFormat接口的设计与实现 - 图3

注意 默认情况下,当作业成功运行完成后,会在最终结果目录${mapred.out.dir}下生成空文件_SUCCESS。该文件主要为高层应用提供作业运行完成的标识,比如,Oozie[1]需要通过检测结果目录下是否存在该文件判断作业是否运行完成。

2.新版API的OutputFormat解析

如图3-14所示,除了接口变为抽象类外,新API中的OutputFormat增加了一个新的方法:getOutputCommitter,以允许用户自己定制合适的OutputCommitter实现。

3.3.3 OutputFormat接口的设计与实现 - 图4

图 3-14 新版API的OutputFormat类图

[1]具体可到http://incubator.apache.org/oozie/下查看相关文档。