您的位置:首页 > 其它

reduce中Iterator<ritable>的循环陷阱

2013-11-16 14:08 513 查看
初学hadoop,尝试练习mapreduce中reduce侧关联例子的时候,越到莫名其妙的问题:

设计思路:对map过来的key,list结构进行三次循环,首先转成list,第二个是获取主键来源的信息行(主表数据,唯一一条),然后在循环第三次,对剩余的数据加上找出来的主表数据。

第一次循环代码,转换成list:

List<JoinWritable> rows = new ArrayList<JoinWritable>();
for (JoinWritable record : values) {

rows.add(record);
}
第二次找出主表数据

for (JoinWritable record : records) {
if (FILE_NAME_MASTER.equals(record.getFileName())) {
records.remove(record);
return record;
}
}
第三次彻底拼接结果

/* 2.判断reduce中的数据集,如果小于2,直接返回因为此处是内连接!!! */
if (records.size() < 2) {
return;
} else {
JoinWritable masterRecord = this
.searchAndRemoveMasterKeyRecord(records);
if (masterRecord == null) {
throw new RuntimeException("输入数据错误,没有对应主键【"
+ key.toString() + "】的主表记录");
}
for (JoinWritable record : records) {
context.write(key, new Text(masterRecord.toString() + ","
+ record.toString()));
}
}


逻辑看上去并没有问题,在马上下班的情况下,运行了次,结果抛出了异常,而且是在
throw new RuntimeException("输入数据错误,没有对应主键【"
+ key.toString() + "】的主表记录");
回家后,又走了下,还是如此的错误!弄了好久,发现每次到最后的时候list中数据都是一样的!这不科学呀,偶尔间在网上看到了一个信息,说hadoop的reduce中,Iterable循环Writable的时候都是指向的同一个对象,如果保存这个对象,实际是保存的引用!

将第一个循环代码改为

for (JoinWritable record : values) {
//此处真他妈的坑爹 直接add会引用一个对象!!!
rows.add(new JoinWritable(record));
}
可以解决这个问题!当然有更好的解决方法,以后会另有说明。

这个问题可能是hadoop推荐只用一次循环来处理所有的结果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: