我试图学习将存储在hdfs中的文件潜入分裂并将其读取到不同的进程(在不同的机器上)。
我的期望是,如果我的SequenceFile
包含12个进程的1200条记录,我会看到每个进程大约有100条记录。划分文件的方法是获取数据长度,然后除以进程数,导出每个拆分的块/乞讨/结束大小,然后将该拆分传递给例如SequenceFileRecordReader
,在简单的while循环中检索记录:代码如下。
private InputSplit getSplit(int id) throws IOException {
...
for(FileStatus file: status) {
long len = file.getLen();
BlockLocation[] locations =
fs.getFileBlockLocations(file, 0, len);
if (0 < len) {
long chunk = len/n;
long beg = (id*chunk)+(long)1;
long end = (id)*chunk;
if(n == (id+1)) end = len;
return new FileSplit(file, beg, end, locations[locations.length-1].getHosts());
}
}
...
}
但是,结果显示每个进程计算的总记录总数与文件中存储的记录不同。将SequenceFile均匀分成块并将它们分配给不同主机的正确方法是什么?
感谢。
答案 0 :(得分:4)
我不禁想知道你为什么要做这样的事情。 Hadoop自动拆分您的文件,1200条记录被分成100条记录,听起来不像是很多数据。如果你详细说明你的问题是什么,有人可能会更直接地帮助你。
以下是我的两个想法:
选项1:使用Hadoop的自动拆分行为
Hadoop会自动拆分您的文件。文件分割成的块数是文件的总大小除以块大小。默认情况下,将为每个块(而不是每个文件)分配一个映射任务。
在conf/hdfs-site.xml
配置文件中,有一个dfs.block.size
参数。大多数人将此设置为64或128mb。但是,如果你试图做一些微小的事情,比如每个块100个序列文件记录,你可以设置这个真的很低......比如说1000个字节。我从来没有听说过有人想要这样做,但这是一个选择。
选项2:使用MapReduce作业拆分数据。
让你的工作使用“身份映射器”(基本上实现Mapper并且不要覆盖map
)。另外,让你的工作使用“身份减少器”(基本上实现Reducer并且不要覆盖reduce
)。将减速器数量设置为您想要的分割数量。假设您有三个序列文件要分割成总共25个文件,您可以加载这3个文件并将减速器数量设置为25.记录将随机发送到每个减速器,最终结果将接近25个相等的分裂。
这是有效的,因为身份验证器和缩减器实际上没有做任何事情,因此您的记录将保持不变。记录被发送到随机Reducer,然后它们将被写出来,每个reducer一个文件到part-r-xxxx
个文件。这些文件中的每一个都将包含您的序列文件,这些文件被分成几个偶数块。