我有一个文件,其中每四行代表一条记录。
例如,前四行代表记录1,接下来四行代表记录2,依此类推......
如何确保Mapper一次输入这四行?
另外,我希望Hadoop中的文件拆分发生在记录边界(行号应该是4的倍数),因此记录不会跨越多个拆分文件。
如何做到这一点?
答案 0 :(得分:11)
一些方法,有些比其他方法更脏:
正确的方式
您可能需要定义自己的RecordReader,InputSplit和InputFormat。根据您要完成的操作,您将能够重复使用上述三个中已有的一些。您可能必须编写自己的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.
由于以下原因,这有一些开销
**以上代码来自Hadoop : The Definitive Guide