-
-
输入格式
-
输入分片与记录
-
一个输入分片就是一个由单个mapTask来处理的输入块。每个分片被划分成若干条记录,每条记录就是一个键值对。输入分片和记录都是逻辑概念。
-
输入分片在Java中表现为InputSplit接口。InputSplit包含一个以字节为单位的长度和一组存储位置。注意,分片并不包含数据本身,而是指向数据的引用。存储位置让mapreduce可以将map任务尽量放在分片数据附近,而分片大小用来排序分片,以便优先处理最大分片,从而最小化作业运行时间。
-
客户端通过调用getSplits()方法计算分片,然后将结果发送到application master,application master使用其存储位置信息来调度mapTask。mapTask把输入分片传给InputFormat的createRecordReader()方法来获得这个分片的RecordReader。RecordReader就像记录的迭代器,可以生成记录键值对传递给map函数。
public void run(Context context) throws IOException, InterruptedException{ setup(context); while(context.nextKeyValue()){ map(context.getCurrentKey(), context.getCurrentValue(), context); } cleanup(context); }-
运行setup()之后,通过Context,键-值从RecordReader中被检索出,并传递给map()方法。当reader读到stream结尾时,nextKeyValue()返回false,map()任务运行其cleanup()方法,然后结束。
-
FileInputFormat类
-
FileInputFormat是所有使用文件作为其数据源的InputFormat实现的基类。它提供两个功能:一个用于指定作业的输入文件位置;一个是为输入文件生成分片提供代码实现。把分片切割成记录的功能由子类实现。
-
-
-
-
-
2. FileInputFormat类的输入分片:FileInputFormat只分割大文件。这里的大指的是文件超过HDFS块的大小。
2. 小文件与CombineFileInputFormat
0. 相对于大批量的小文件,Hadoop更适合处理少量的大文件。一个原因是FileInputFormat生成的分块是一个文件或该文件的一部分。如果该文件很小(远小于HDFS块大小),并且文件数量很多,那么每次map任务只能处理很少的数据,效率很低。
0. CombineFileInputFormat可以缓解这个问题,它是针对小文件而设计的。FileInputFormat为每个文件产生至少1个分片,而CombineFileInputFormat把多个文件打包到一个分片中以便每个mapper能处理更多数据。同时它会考虑机架和节点因素,所以在典型mapreduce作业中处理输入的速度并不会下降。
0. 避免切分:有的应用程序可能不希望文件被切分,而是用一个mapper完整处理一个输入文件,例如检查一个文件中所有记录是否有序。有两种方法可以保证输入文件不被切分:一是将最小分片大小设置为Long.MAX_VALUE;二是使用FileInputFormat的具体子类,并把isSplitable的返回值设置为false。
0. 文本输入
0. TextInputFormat:TextInputFormat是默认的InputFormat。每条记录是一行输入。键是LongWritable类型,存储着该行的偏移量。值是这行的内容,不包括任何终止符(换行符和回车符),它被打包成Text类型。
0. 二进制输入:SequenceFileInputFormat
0. 多个输入:
1. MultipleInputs:一个mapreduce作业的输入可能包含多个输入文件,但是所有文件都由同一个InputFormat和同一个mapper来解释。对于数据可能格式不同(分隔符不同),或者文件类型不同(二进制和文本),因此需要分别进行解析。MultipleInputs可以针对不同文件,指定不同的文件类型和mapper来进行解析。
```
MultipleInputs.addInputPath(job, ncdcInputPath, TextInputFormat.class, MaxTemMapper.class);
MultipleInputs.addInputPath(job, metofficeInputPath, TextInputFormat.class, MetofficeMaxTemMapper.class);
```
0. 输出格式