0

在 MapReduce 作业中使用 Avro 时,我看到了一种安静的奇怪行为。事实上,使用的 Iterable 非常奇怪:iterator.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 是如何编码的?为什么?或者也许我做错了什么?

4

1 回答 1

1

我找到了你的问题,因为我遇到了同样的问题。我运行的测试似乎表明,对于所有迭代,Iterable 只返回一个实例。每次读取新的 AVRO 对象时,Iterable 必须替换同一对象的内容。我最终得到了一个包含数千个返回的最后一个对象的列表。我发现,只要我调用了 iterator.next(),我之前迭代的对象就会突然变成新的对象。

我可以理解他们为什么这样做,因为 Iterable 用于通过处理启用无限数量的对象 - 即,一次可能超过内存。因此,他们不希望任何人在调用 iterator.next() 后持有对象。

如果您需要引用从可迭代对象返回的任何先前对象,则必须先将该对象复制到新实例中,然后再转到可迭代对象中的下一个对象。

我使用 google 的 cloning-1.8.5 工具中的 Cloner 来解决这个问题。我的对象大约有五六层嵌套,但它似乎有效。

谷歌克隆-1.8.5

另一种选择是在每个对象上实现自己的复制方法。

谢谢,维克

于 2014-04-02T12:29:48.850 回答