在Hadoop中,我有一个3GB大小的序列文件。我想并行处理它。因此,我将创建8个maptasks,因此创建8个FileSplits。
FileSplit类具有需要:
的构造函数Path of the file
Start position
Length
例如,fisrt split可以是0,长度为3GB / 8,下一个是3GB / 8,长度为3GB / 8,等等。
现在SequenceFile.Reader有一个构造函数,它采用相同的:
Path of the file
Start position
Length
对于第一次拆分(从长度为3Gb / 8的0开始),序列文件能够读取它,因为它包含文件头,压缩类型以及有关键和值类的信息。
但是,对于其他分割,SequenceFile.Reader无法读取分割,因为我认为该文件的一部分不包含序列文件的头部(因为文件分割不是从0开始)因此,当我尝试使用序列文件时,它会抛出NullPointerException。
那么有没有办法从序列文件中分割文件?
答案 0 :(得分:0)
好吧,我们的想法是 SequenceFile.Reader 的开始和长度参数不是用于指定序列文件的一部分而是用于用于在序列文件中指定实际开始和 span (例如,如果您有一个包含五个序列文件的容器文件,并且您想要使用其中一个,那么指定容器文件中的序列文件的开始和长度。 OR 以防您想要从序列文件的开头读取特定长度;但是无法将开头设置为在序列文件的中间,因为你将跳过序列文件的标题,你将得到"而不是序列文件错误",因此你必须将start参数设置为序列文件的开头。)
因此,解决方案是像往常一样在InputFormat中创建文件:
new FileSplit(path, start, span, hosts);
并且像往常一样在RecordReader中创建序列阅读器(无需指定开始或长度):
reader = new SequenceFile.Reader(fs, path, conf);// As usual
start = Split.getStart();
reader.sync(start);
这个想法在" sync"它会跳过" start"指定的字节数。分裂。
RecordReader 的 nextKeyValue :
if ((reader.getPosition() >= (start + span)) || !reader.next(key, value)) {
return false;
} else {
return true;
}