我想有一个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中的键的所有值都需要容纳在内存中。