Hadoop似乎在对给定reduce调用的值进行迭代的过程中修改了我的key对象
Hadoop版本:0.20.2(在Amazon EMR上) 问题:我有一个在映射阶段编写的自定义密钥,我在下面添加了它。在reduce调用期间,我对给定键的值进行了一些简单的聚合。我面临的问题是,在reduce调用中迭代值的过程中,我的键被更改了,我得到了那个新键的值 我的密钥类型:Hadoop似乎在对给定reduce调用的值进行迭代的过程中修改了我的key对象,hadoop,reduce,elastic-map-reduce,Hadoop,Reduce,Elastic Map Reduce,Hadoop版本:0.20.2(在Amazon EMR上) 问题:我有一个在映射阶段编写的自定义密钥,我在下面添加了它。在reduce调用期间,我对给定键的值进行了一些简单的聚合。我面临的问题是,在reduce调用中迭代值的过程中,我的键被更改了,我得到了那个新键的值 我的密钥类型: class MyKey implements WritableComparable<MyKey>, Serializable { private MyEnum type; //MyEnum i
class MyKey implements WritableComparable<MyKey>, Serializable {
private MyEnum type; //MyEnum is a simple enumeration.
private TreeMap<String, String> subKeys;
MyKey() {} //for hadoop
public MyKey(MyEnum t, Map<String, String> sK) { type = t; subKeys = new TreeMap(sk); }
public void readFields(DataInput in) throws IOException {
Text typeT = new Text();
typeT.readFields(in);
this.type = MyEnum.valueOf(typeT.toString());
subKeys.clear();
int i = WritableUtils.readVInt(in);
while ( 0 != i-- ) {
Text keyText = new Text();
keyText.readFields(in);
Text valueText = new Text();
valueText.readFields(in);
subKeys.put(keyText.toString(), valueText.toString());
}
}
public void write(DataOutput out) throws IOException {
new Text(type.name()).write(out);
WritableUtils.writeVInt(out, subKeys.size());
for (Entry<String, String> each: subKeys.entrySet()) {
new Text(each.getKey()).write(out);
new Text(each.getValue()).write(out);
}
}
public int compareTo(MyKey o) {
if (o == null) {
return 1;
}
int typeComparison = this.type.compareTo(o.type);
if (typeComparison == 0) {
if (this.subKeys.equals(o.subKeys)) {
return 0;
}
int x = this.subKeys.hashCode() - o.subKeys.hashCode();
return (x != 0 ? x : -1);
}
return typeComparison;
}
}
类MyKey实现可写、可比较、可序列化{
私有MyEnum类型;//MyEnum是一个简单的枚举。
私有树映射子键;
hadoop的MyKey(){}//
公共MyKey(MyEnum t,Map sK){type=t;子key=new TreeMap(sK);}
public void readFields(DataInput in)引发IOException{
文本类型t=新文本();
类型读取字段(输入);
this.type=MyEnum.valueOf(typeT.toString());
子键。清除();
int i=writeableutils.readVInt(in);
而(0!=i--){
Text keyText=新文本();
keyText.readFields(in);
文本值Text=新文本();
valueText.readFields(在中);
put(keyText.toString(),valueText.toString());
}
}
public void write(DataOutput out)引发IOException{
新文本(type.name())。写入(out);
WritableUtils.writeVInt(out,subKeys.size());
对于(每个条目:subKeys.entrySet()){
新文本(each.getKey()).write(out);
新文本(each.getValue()).write(out);
}
}
公共整数比较(MyKey o){
如果(o==null){
返回1;
}
int-typeComparison=this.type.comparieto(o.type);
如果(类型比较==0){
if(this.subKeys.equals(o.subKeys)){
返回0;
}
int x=this.subKeys.hashCode()-o.subKeys.hashCode();
返回(x!=0?x:-1);
}
返回类型比较;
}
}
密钥的这种实现有什么问题吗?以下是我在reduce call中面临的按键组合代码:
reduce(MyKey k, Iterable<MyValue> values, Context context) {
Iterator<MyValue> iterator = values.iterator();
int sum = 0;
while(iterator.hasNext()) {
MyValue value = iterator.next();
//when i come here in the 2nd iteration, if i print k, it is different from what it was in iteration 1.
sum += value.getResult();
}
//write sum to context
}
reduce(MyKey k、Iterable值、上下文){
迭代器迭代器=值。迭代器();
整数和=0;
while(iterator.hasNext()){
MyValue=iterator.next();
//当我在第二次迭代中来到这里时,如果我打印k,它与迭代1中的不同。
sum+=value.getResult();
}
//将总和写入上下文
}
在这方面的任何帮助都将不胜感激。这是预期的行为(至少在新API中)
当调用值Iterable的基础迭代器的next
方法时,将从排序的映射器/组合器输出中读取下一个键/值对,并检查该键是否仍然与前一个键属于同一组
由于hadoop重新使用传递给reduce方法的对象(只调用同一对象的readFields方法),关键参数“k”的底层内容将随着
值的每次迭代而改变。听起来可能很奇怪,但是我认为如果您删除compareTo方法的hashcode部分和return-1,那么它应该可以正常工作。谢谢您,托马斯。这听起来确实很奇怪,但我太绝望了,我还是试过了。首先,上述代码有效。我羞愧地承认,我粘贴的代码与我运行的代码完全不同。我只是简单地执行返回这个.subKeys.hashCode()-o.subKeys.hashCode()
,我知道这是错误的,但我没有修复实际的代码,而是尝试比较两个看起来冲突的键的hashCode。我在测试过程中犯了一个错误,并假设其他东西出错,然后修复了这里的代码。那么您是如何解决这个问题的呢?原因是hashCode(),还是?我在2.7版本中遇到过这种情况。如何避免这种行为?我只想计算我的对象(就像标准的wordCounter示例一样,唯一的区别是我使用自定义类型而不是hadoop文本),但最终我只得到一个对象的所有值的总和。reduce()只从run()窗体调用一次,而不是分别为每个键调用。