我尝试过不同的方法来创建一个大的Hadoop SequenceFile 只需一个短(< 100bytes)密钥,但一个大(> 1GB)值(BytesWriteable)。
以下示例适用于开箱即用:
写入多个随机长度的密钥和值,总大小> 3GB。
但是,这不是我想要做的。所以我使用hadoop 2.2.0 API将其修改为:
Path file = new Path("/input");
SequenceFile.Writer writer = SequenceFile.createWriter(conf,
SequenceFile.Writer.file(file),
SequenceFile.Writer.compression(CompressionType.NONE),
SequenceFile.Writer.keyClass(BytesWritable.class),
SequenceFile.Writer.valueClass(BytesWritable.class));
int numBytesToWrite = fileSizeInMB * 1024 * 1024;
BytesWritable randomKey = new BytesWritable();
BytesWritable randomValue = new BytesWritable();
randomKey.setSize(1);
randomValue.setSize(numBytesToWrite);
randomizeBytes(randomValue.getBytes(), 0, randomValue.getLength());
writer.append(randomKey, randomValue);
writer.close();
当fileSizeInMB> 700MB时,我收到的错误如下:
java.lang.NegativeArraySizeException
at org.apache.hadoop.io.BytesWritable.setCapacity(BytesWritable.java:144)
at org.apache.hadoop.io.BytesWritable.setSize(BytesWritable.java:123)
...
我看到正在讨论这个错误,但没有看到任何解决方案。请注意,int(2 ^ 32)可以大到2GB,它不应该在700MB时失败。
如果您有其他选择来创建这样的大值SequenceFile,请指教。我尝试了其他方法,如输入流中的IOutils.read到byte [],我得到堆大小或OOME。
答案 0 :(得分:1)
只需使用ArrayPrimitiveWritable。
通过在BytesWritable设置新容量,存在一个int溢出:
public void setSize(int size) {
if (size > getCapacity()) {
setCapacity(size * 3 / 2);
}
this.size = size;
}
700 Mb * 3> 2Gb = int溢出!
结果,您无法将超过700 Mb的序列化(但可以写入和序列化)到BytesWritable中。
答案 1 :(得分:0)
如果你想使用BytesWritable
,之前的选项设置容量足够高,所以你使用2GB,而不仅仅是700MB:
randomValue.setCapacity(numBytesToWrite);
randomValue.setSize(numBytesToWrite); // will not resize now
最近在Hadoop中修复了这个错误,所以在新版本中它甚至可以在没有它的情况下工作:
public void setSize(int size) {
if (size > getCapacity()) {
// Avoid overflowing the int too early by casting to a long.
long newSize = Math.min(Integer.MAX_VALUE, (3L * size) / 2L);
setCapacity((int) newSize);
}
this.size = size;
}