Hadoop中的迭代器;对象重用;reduce中的kv
The framework will reuse the key and value objects that are passed into the reduce, therefore the application should clone the objects they want to keep a copy of.(官方文档)
翻译:框架将重用传递到reduce的key和value对象,因此应用程序应该克隆要保留副本的对象。
在Reduce阶段中,Hadoop的迭代器(Iterable<object> values)调用next()方法后,会从ReduceContext中获取新的key-value判断下一个key和上一个key是否相同,然后决定hashNext方法是否结束,同时对key和value进行了一次重新赋值。
重新赋值的过程就是对象重用,即迭代时key / value始终指向一个内存地址(引用值始终不变),改变的是引用指向的内存地址中的数据。
(具体过程可参考以下链接:https://www.cnblogs.com/intsmaze/p/6737337.html#undefined)
举个例子:
public class TableReducer extends Reducer<Text,TableBean,TableBean, NullWritable> { @Override protected void reduce(Text key, Iterable<TableBean> values, Context context) throws IOException, InterruptedException { ArrayList<TableBean> orderBeans = new ArrayList<>(); TableBean pdBean = new TableBean(); for (TableBean value : values) { //判断数据来自哪个表 if("order".equals(value.getFlag())){ //订单表 //创建一个临时 TableBean 对象接收 value TableBean tmpOrderBean = new TableBean(); try { BeanUtils.copyProperties(tmpOrderBean,value); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } //将临时 TableBean 对象添加到集合 orderBeans orderBeans.add(tmpOrderBean); }else { //商品表 try { BeanUtils.copyProperties(pdBean,value); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } //遍历集合 orderBeans,替换掉每个 orderBean 的 pid 为 pname,然后写出 for (TableBean orderBean : orderBeans) { orderBean.setPname(pdBean.getPname()); //写出修改后的 orderBean 对象 context.write(orderBean,NullWritable.get()); } } }
代码红色部分创建了一个临时变量,将value对象的各个属性拷贝给该临时变量。之后将对象添加到集合进行输出。
在迭代时,若不创建临时变量而是直接把value放进集合中,由于对象重用,value的值始终不变(假设是1001)始终指向同一个地方,改变的是地址为1001存放的数据,最终导致集合中存放的都是同一个value。
( 集合={1001,1001,1001} )👆
总结:key和value的(引用)值始终不变,但(引用)指向的数据是不断变化的。