2017-08-24 26 views
0

我在MR作业的映射阶段中使用了一个自定义可写类作为VALUEOUT,其中类有两个字段A org.apache.hadoop.io.Textorg.apache.hadoop.io.MapWritable。在我的reduce函数中,遍历每个键的值,并执行两个操作:1. filter,2. aggregate。在过滤器中,我有一些规则来检查MapWritable中的某些值(键为Text,值为IntWritableDoubleWritable)是否满足某些条件,然后将其简单地添加到ArrayList中。在过滤操作结束时,我有一个过滤的自定义可写对象列表。在汇总阶段,当我访问这些对象时,结果是最后一个被成功过滤的对象已经覆盖了数组列表中的所有其他对象。在对最后一个对象覆盖所有其他对象的SO上列出了一些类似的问题之后,我确认了我没有静态字段,也没有通过设置不同的值来重复使用相同的自定义可写(这被引用为可能的原因)一个问题)。对于减速器中的每个键,我都确保CustomWritableText键和MapWritable是新对象。另外,我还通过在我的reduce中删除了过滤器&聚合操作并刚刚迭代了这些值并使用for循环将它们添加到ArrayList中来执行简单测试。在循环中,每次我将一个CustomWritable添加到列表中时,我都记录了列表中所有内容的值。我在将元素添加到列表之前和之后进行了记录。这两个日志都表明前一组元素已被覆盖。我很困惑这种情况如何发生。一旦迭代值中的下一个元素被循环for (CustomWritable result : values)访问,列表内容就被修改了。我无法弄清楚这种行为的原因。如果任何人都可以对此有所了解,这将非常有帮助。谢谢。迭代减速器中定制可写组件的问题

+0

我注意到这里有一个类似的问题:可迭代到ArrayList的元素改变(https://stackoverflow.com/questions/23329173/iterable-to-arraylist-elements-change?rq=1)。也许问题是相似的,但它有相同的值,不知道它是最后一个元素还是第一个访问的元素。即便如此,我有一个复杂的对象,每次都不得不重新创建一个新对象,这看起来像是一种笨拙和痛苦的选择,我不想诉诸于此。任何其他更好的选择? – KNP

回答

1

reducer中的“values”迭代器在迭代时重用该值。这是一种用于性能和更小内存占用的技术。在幕后,Hadoop将下一条记录反序列化为同一个Java对象。如果你需要“记住”一个对象,你需要克隆它。

您可以利用Writable接口并使用原始字节来填充新对象。

IntWritable first = WritableUtils.clone(values.next(), context.getConfiguration()); 
IntWritable second = WritableUtils.clone(values.next(), context.getConfiguration()); 
+0

谢谢杰夫。像魅力一样工作。我想知道它是如何工作的,因为我们使用HBase org.apache.hadoop.hbase.client.Result作为值,因为它不是一个Writable类。尽管如此,我不记得遇到过这种Result对象的问题。 – KNP