Hadoop MR在reduce方法中保持阵列引用



我想要一个在reduce函数中保存对对象的引用的arrayList。

@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() 返回正确数量的元素,但列表中的所有元素都等于最后一个插入的元素。例如,如果

{id:1}

{id:2}

{id:3}

元素将入,bsonObjects将容纳3个项目,但所有项目都将是{id:3}。这种方法有问题吗?知道为什么会这样吗?我试图将列表更改为地图,但后来只向地图中添加了一个元素。我也试图将 bsonObject 的声明更改为全局,但相同的行为仍然存在。

这是

记录在案的行为。原因是 pValues 迭代器重用 BSONWriable 实例,当它在循环中的值发生变化时,bsonObjects ArrayList 中的所有引用也会更新。当你在bsonObjects上调用add()时,你正在存储一个引用。这种方法允许Hadoop节省内存。

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

试试这个:

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

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

但是,您还应该小心 - 如果您进行深度复制,则此化简器中键的所有值都需要适合内存。

最新更新