使用ArrayWritable的序列化似乎以一种有趣的方式工作

我正在使用ArrayWritable ,在某些时候我需要检查Hadoop如何序列化ArrayWritable ,这是我通过设置job.setNumReduceTasks(0)

 0   IntArrayWritable@10f11b8 3   IntArrayWritable@544ec1 6   IntArrayWritable@fe748f 8   IntArrayWritable@1968e23 11   IntArrayWritable@14da8f4 14   IntArrayWritable@18f6235 

这是我使用的测试映射器:

 public static class MyMapper extends Mapper { public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { int red = Integer.parseInt(value.toString()); IntWritable[] a = new IntWritable[100]; for (int i =0;i<a.length;i++){ a[i] = new IntWritable(red+i); } IntArrayWritable aw = new IntArrayWritable(); aw.set(a); context.write(key, aw); } } 

IntArrayWritable取自javadoc: ArrayWritable中给出的示例。

 import org.apache.hadoop.io.ArrayWritable; import org.apache.hadoop.io.IntWritable; public class IntArrayWritable extends ArrayWritable { public IntArrayWritable() { super(IntWritable.class); } } 

我实际上检查了Hadoop的源代码,这对我没有意义。 ArrayWritable不应该序列化类名,并且不能使用6/7hex值序列化100 IntWritable数组。 应用程序实际上似乎工作正常,reducer反序列化正确的值…发生了什么? 我错过了什么?

问题是您从MapReduce作业获得的输出不是该数据的序列化版本。 它被翻译成漂亮的印刷字符串。

当您将reducer的数量设置为零时,您的映射器现在会通过输出格式传递,这将格式化您的数据,可能会将其转换为可读字符串。 它不会将其转储出序列化,就像它将被减速器拾取一样。

您必须覆盖默认的toString()方法。

TextOutputFormat调用它来创建一个人类可读的格式。

尝试以下代码并查看结果:

 public class IntArrayWritable extends ArrayWritable { public IntArrayWritable() { super(IntWritable.class); } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (String s : super.toStrings()) { sb.append(s).append(" "); } return sb.toString(); } } 

您是否查看了SequenceFileInputFormat和SequenceFileOutputFormat? 你可以设置:

 job.setInputFormatClass(SequenceFileInputFormat.class); 

 job.setOutputFormatClass(TextOutputFormat.class); 

这很简单。 Hadoop使用thé方法write(DataOutput out)以序列化版本编写对象(有关更多信息,请参阅hadoop ArrayWritable doc)。 当您通过IntArrayWritable扩展ArrayWritable时,您自己的类将使用inheritance类中的这些方法。 再见。