使用带有大文件的自定义RecordReader时出现堆错误

时间:2013-02-11 11:03:49

标签: java hadoop heap

我编写了一个自定义文件阅读器,不分割我的输入文件,因为它们是大型的gzip压缩文件,我希望我的第一个mapper工作只是将它们解压缩。我按照'Hadoop The Definitive Guide'中的示例进行操作,但在尝试读入BytesWritable时遇到堆错误。我相信这是因为字节数组的大小为85713669,但我不知道如何克服这个问题。

以下是代码:

public class WholeFileRecordReader extends RecordReader<NullWritable, BytesWritable> {

private FileSplit fileSplit;
private Configuration conf;
private BytesWritable value = new BytesWritable();
private boolean processed = false;

@Override
public void close() throws IOException {
    // do nothing
}

@Override
public NullWritable getCurrentKey() throws IOException,
        InterruptedException {
    return NullWritable.get();
}

@Override
public BytesWritable getCurrentValue() throws IOException,
        InterruptedException {
    return value;
}

@Override
public float getProgress() throws IOException, InterruptedException {
    return processed ? 1.0f : 0.0f;
}

@Override
public void initialize(InputSplit split, TaskAttemptContext context)
        throws IOException, InterruptedException {
    this.fileSplit = (FileSplit) split;
    this.conf = context.getConfiguration();
}

@Override
public boolean nextKeyValue() throws IOException, InterruptedException {
    if (!processed) {
        byte[] contents = new byte[(int) fileSplit.getLength()];
        Path file = fileSplit.getPath();
        FileSystem fs = file.getFileSystem(conf);
        FSDataInputStream in = null;
        try {
            in = fs.open(file);
            IOUtils.readFully(in, contents, 0, contents.length);
            value.set(contents, 0, contents.length);
        } finally {
            IOUtils.closeStream(in);
        }
        processed = true;
        return true;
    }
    return false;
}

}

1 个答案:

答案 0 :(得分:1)

通常,您无法将整个文件加载到Java VM的内存中。 您应该找到一些处理大型文件的流式解决方案 - 按块读取数据块并将结果保存在内存整个数据集中 这个特定的任务 - 解压缩可能不适合MR,因为数据没有逻辑划分为记录。
另请注意,hadoop会自动处理gzip - 您的输入流已经解压缩。