这篇文章记录一下自己对Hadoop输入格式的理解。详细参考hadoop API org.apache.hadoop.mapreduce 以及org.apache.hadoop.mapreduce.input.lib 包。
图一:InputFormat类结构
以上是hadoop输入部分用到的类的结构层次图(注:改图是根据旧版API画,类所在的包显示的均是就版API中所在,我在学习时均使用新版API,贴出此图为了直观的理解)。
InputFormat(org.apache.hadoop.mapreduce):
从上图可以看出,最上层是一个InputFormat接口,它描述MapReduce Job的输入。以下是API中对InputFormat类的解释:
图 二 InputFormat 解释
图 三 InputFormat 方法总结
即通过InputFormat,hadoop可以实现:
1.检查MapReduce输入数据的正确性。2.将数据数据切分为逻辑分片InputSplit,分片分配给Mapper,一个分片只能够被单个map操作处理,每个map操作也只处理一个数据分片。3.提供一个RecorReader的实现,Mapper用改实现从InputSplit中读取<k,v>对。
Hadoop可以处理很多格式的数据,从一般的文件到数据库数据等,所以从图一的第二层可以看到有FileInputFormat,DBInputFormat。
FileInputFormat(org.apache.hadoop.mapreduce.lib.input):
FileInputFormat是所有以文件作为数据源的InputFormat的实现。它保存job输入的所有文件,并实现为文件计算split的方法。至于如何读取记录(RecordReader),不同的子类有不同的实现方法。下图是API中对FileInputFormat类的解释:
图 四 FileInputFormat 类解释
FileInputFormat类的方法有很多,详细可以查看API,至于FileInputFormat如何划分split,它只划分比HDFS block(默认64M大小)大的文件,如果一个文件比block块小,它不会被划分,这也是hadoop处理大文件比处理小文件效率高的原因。
FileInputFormat类有很多子类,比较重要的是TextInputFormat类和SequenceFileInputFormat类。这里主要说一下这两个类,其他的可以查看《Hadoop权威指南》和最后给的参考资料。
TextInputForamt(org.apache.hadoop.mapreduce.lib.input):
Hadoop默认的输入方式是TextInputFormat,它重写了FileInputFormat的creatRecordReader和isSplit方法。createRecordReader( )方法返回的是LineRecordReader对象(),该对象读取记录时是按行读取,以回车键和换行符为行分割符。key为行开始位置的偏移量,value为该行的内容。
当然有时这种读取记录的方式并不能满足你的要求,有时候你不想用回车或换行作为分割符,而是有自己特殊的行分割符,这时你要重写一个InputFormat 重写的类继承FileInputFormat,参考资料其中之一讲到如何重写InputFormat类。
SequenceFileInputFormat(org.apache.hadoop.mapreduce.lib.input):
SequenceFileInputFormat存储二进制键/值对的序列。如果在MapReduce中使用顺序文件,就必须使用改输入方式。它重载了listStatus,实现了createRecordReader方法返回一个SequenceFileRecordReader对象。下面是API中该类的方法:
图 五 SequenceFileInputFormat 方法总结
TextInputFormat和SequenceFileInputFormat中都实现了createRecordReader类,该类要返回一个RecordReader对象。很多时候我们要自己定义InputFormat类,在InputFormat类中写自己需要的读取记录的方式即RecordReader对象,下面就RecordReader做简单的解释。
RecordReader(org.apache.hadoop.mapreduce):
RecordReader用于在划分中读取<Key,Value>对。RecordReader有五个虚方法,分别是:
initialize:初始化,输入参数包括该Reader工作的数据划分InputSplit和Job的上下文context;
nextKey:得到输入的下一个Key,如果数据划分已经没有新的记录,返回空;
nextValue:得到Key对应的Value,必须在调用nextKey后调用;
getProgress:得到现在的进度;
close,来自java.io的Closeable接口,用于清理RecordReader。
图 六 RecordReader 方法总结
当然要具体弄明白RecordReader类还是建议找个例子的代码或Hadoop中LineRecordReader类的源码分析一下。
还有很多输入方式没说,自己也还没弄清楚,感兴趣的可以自己去查资料。自己小总结一下:也就是hadoop的输入文件要通过***InputFormat 类来将文件分片,可以自己设定是否分片以及分片规则isSplitable()/getSplits,然后要有一个RecordReader对象来读取记录,改RecordReader对象读取记录是要实现图六中的方法。最后就会按需要的<K,V>对方式 输送个Mapper。
具体可以查询下面的参考资料。
参考资料:
《Hadoop权威指南》
Hadoop-0.20 API