Hadoop一次读取多行

时间:2011-11-15 17:21:23

标签: hadoop

我有一个文件,其中每四行代表一条记录。

例如,前四行代表记录1,接下来四行代表记录2,依此类推......

如何确保Mapper一次输入这四行?

另外,我希望Hadoop中的文件拆分发生在记录边界(行号应该是4的倍数),因此记录不会跨越多个拆分文件。

如何做到这一点?

2 个答案:

答案 0 :(得分:11)

一些方法,有些比其他方法更脏:


正确的方式

您可能需要定义自己的RecordReaderInputSplitInputFormat。根据您要完成的操作,您将能够重复使用上述三个中已有的一些。您可能必须编写自己的RecordReader来定义键/值对,您可能需要编写自己的InputSplit来帮助定义边界。


另一种正确的方式,这可能是不可能的

上述任务非常艰巨。您是否可以控制数据集?你可以在某种程度上预处理它(无论是进入还是休息)?如果是这样,你应该强烈考虑尝试将数据集转换为更容易在Hadoop中开箱即用的内容。

类似的东西:

ALine1
ALine2            ALine1;Aline2;Aline3;Aline4
ALine3
ALine4        ->
BLine1
BLine2            BLine1;Bline2;Bline3;Bline4;
BLine3
BLine4

Down and Dirty

您是否可以控制数据的文件大小?如果手动在块边界上拆分数据,则可以强制Hadoop不关心跨越拆分的记录。例如,如果块大小为64MB,则以60MB块的形式写出文件。

不用担心输入拆分,你可以做一些脏事:在map函数中,将新的键/值对添加到列表对象中。如果列表对象中有4个项目,请进行处理,发出一些内容,然后清理列表。否则,不要发出任何东西,继续前进而不做任何事情。

您必须手动拆分数据的原因是您无法保证将整个4行记录提供给同一个地图任务。

答案 1 :(得分:3)

另一种方式(容易但在某些情况下可能效率不高)是实现FileInputFormat#isSplitable()。然后输入文件不会被拆分,并且每个地图都会处理一次。

import org.apache.hadoop.fs.*;
import org.apache.hadoop.mapred.TextInputFormat;
public class NonSplittableTextInputFormat extends TextInputFormat {
    @Override
    protected boolean isSplitable(FileSystem fs, Path file) {
        return false;
    }
}

正如orangeoctopus所说

In your map function, add your new key/value pair into a list object. If the list object has 4 items in it, do processing, emit something, then clean out the list. Otherwise, don't emit anything and move on without doing anything.

由于以下原因,这有一些开销

  • 处理最大文件的时间拖延了作业完成时间。
  • 可以在数据节点之间传输大量数据。
  • 未正确使用群集,因为#of maps = #of files。

**以上代码来自Hadoop : The Definitive Guide