【发布时间】:2011-11-15 17:21:22
【问题描述】:
我有一个文件,其中每四行一组代表一条记录。
例如,前四行代表记录 1,接下来的四行代表记录 2,依此类推。
如何确保 Mapper 一次输入这四行?
另外,我希望 Hadoop 中的文件拆分发生在记录边界(行号应该是四的倍数),因此记录不会跨越多个拆分文件..
如何做到这一点?
【问题讨论】:
标签: hadoop
我有一个文件,其中每四行一组代表一条记录。
例如,前四行代表记录 1,接下来的四行代表记录 2,依此类推。
如何确保 Mapper 一次输入这四行?
另外,我希望 Hadoop 中的文件拆分发生在记录边界(行号应该是四的倍数),因此记录不会跨越多个拆分文件..
如何做到这一点?
【问题讨论】:
标签: hadoop
一些方法,有些比其他方法更脏:
正确的方式
您可能必须定义自己的RecordReader、InputSplit 和InputFormat。根据您正在尝试做的事情,您将能够重用上述三个中的一些已经存在的。您可能必须编写自己的 RecordReader 来定义键/值对,并且您可能必须编写自己的 InputSplit 来帮助定义边界。
另一种正确的方式,可能是不可能的
上述任务相当艰巨。你对你的数据集有任何控制权吗?你能以某种方式对它进行预处理(无论是在它进入时还是在静止时)?如果是这样,您应该强烈考虑尝试将您的数据集转换为更易于在 Hadoop 中开箱即用地读取的内容。
类似:
ALine1
ALine2 ALine1;Aline2;Aline3;Aline4
ALine3
ALine4 ->
BLine1
BLine2 BLine1;Bline2;Bline3;Bline4;
BLine3
BLine4
又脏又臭
您可以控制数据的文件大小吗?如果您在块边界上手动拆分数据,您可以强制 Hadoop 不关心跨越拆分的记录。例如,如果您的块大小为 64MB,则以 60MB 块的形式写入文件。
不用担心输入拆分,您可以做一些肮脏的事情:在您的地图函数中,将您的新键/值对添加到列表对象中。如果列表对象中有 4 个项目,则进行处理,发出一些东西,然后清除列表。否则,什么都不发射,什么都不做,继续前进。
您必须手动拆分数据的原因是您无法保证将整个 4 行记录提供给同一个地图任务。
【讨论】:
另一种方法(简单但在某些情况下可能效率不高)是实现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;
}
}
正如橙章鱼所说
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
【讨论】: