在MapReduce作业中使用Avro时,我看到了一个非常奇怪的行为。确实Iterable使用了很奇怪:迭代器。Next不要指向一个对象,而是指向在每次调用"Next"函数时改变其值的东西!!
的例子:
public static class MyAvroReducer extends AvroReducer<Long, MyAvroType,
Pair<Long, MyAvroType>> {
@Override
public void reduce(Long user, Iterable<MyAvroType> listAvroType,
AvroCollector<Pair<Long,MyAvroType>> collector,
Reporter reporter)
throws IOException {
// basically here I am expecting a list of two MyAvroType object
// The first one who has a field "type" equals to "foo" and the second
// who has a filed "type" equals to "bar"
MyAvroType foo;
MyAvroType bar;
for (MyAvroType obj : listAvroType){
if (obj.getType().equals("foo") {foo = obj;}
else if (obj.getType().equals("bar") {bar = obj;}
}
system.out.println("FOO: " + foo.getType());
system.out.println("FOO: " + bar.getType());
}
标准输出显示:
FOO:酒吧
栏:酒吧
这里的Iterable是如何编码的?为什么??或者我做错了什么?
我发现了你的问题,因为我有同样的问题。我运行的测试似乎表明,Iterable对所有迭代只返回一个实例。Iterable必须在每次读取一个新的AVRO对象时替换相同对象的内容。我最终得到了一个包含数千个最后返回对象的列表。我发现,只要调用了iterator.next(),之前迭代得到的对象就会突然变成新对象。
我可以理解他们为什么这样做,因为Iterable用于通过处理启用无限数量的对象-也就是说,一次可以容纳更多的对象。因此,他们不希望任何人在调用iterator.next()之后保留对象。
如果你需要引用从iterable返回的任何先前的对象,你必须在访问iterable中的下一个对象之前将该对象复制到一个新的实例中。
我使用克隆从谷歌的克隆-1.8.5工具来解决这个问题。我的对象大约有五到六层的嵌套,但它似乎有效。
谷歌cloning-1.8.5
另一种选择是在每个对象上实现自己的copy方法。
谢谢,维克