我想有一个arrayList,它保存reduce函数中对对象的引用。

@Override
public void reduce( final Text pKey,
                    final Iterable<BSONWritable> pValues,
                    final Context pContext )
        throws IOException, InterruptedException{
    final ArrayList<BSONWritable> bsonObjects = new ArrayList<BSONWritable>();

    for ( final BSONWritable value : pValues ){
        bsonObjects.add(value);
        //do some calculations.
    }
   for ( final BSONWritable value : bsonObjects ){
       //do something else.
   }
   }

问题是bsonObjects.size()返回正确数量的元素,但是列表中的所有元素都等于最后插入的元素。
例如如果



要插入的元素bsonObjects将容纳3个项目,但所有项目均为{id:3}。
这种方法有问题吗?知道为什么会这样吗?
我试图将列表更改为 map ,但随后仅将一个元素添加到 map 。
我也尝试将bsonObject的声明更改为global,但行为相同。

最佳答案

这是记录的行为。原因是pValues迭代器重新使用了BSONWritable实例,并且当其值在循环中更改时,bsonObjects ArrayList中的所有引用也会更新。在bsonObjects上调用add()时,您正在存储一个引用。这种方法允许Hadoop节省内存。

您应该在第一个循环中实例化一个新的BSONWritable变量,该变量等于变量值(深拷贝)。然后将新变量添加到bsonObjects中。

试试这个:

for ( final BSONWritable value : pValues ){
    BSONWritable v = value;
    bsonObjects.add(v);
    //do some calculations.
}
for ( final BSONWritable value : bsonObjects ){
   //do something else.
}

然后,您将能够在第二个循环中遍历bsonObjects并检索每个不同的值。

但是,您也应该小心-如果进行深拷贝,则此reducer中的键的所有值都需要容纳在内存中。

08-03 17:00