所以我对mongodb和mapreduce一般是新手,并且遇到了这个“怪癖”(或者至少在我看来是个怪癖)
假设我的收藏中的对象是这样的:
{'key':5,'value':5}
{'key':5,'value':4}
{'key':5,'value':1}
{'key':4,'value':6}
{'key':4,'value':4}
{'key':3,'value':0}
我的地图功能只会发出键和值
我的 reduce 函数只是添加值 AND ,然后返回它们添加1(我这样做是为了检查是否甚至调用了reduce函数)
我的结果如下:
{'_ id':3,'value':0 }
{'_ id':4,'value':11.0}
{'_ id':5,'value':11.0}
正如您所看到的,对于按键4& 5我得到11键的预期答案但键3(在该键的集合中只有一个条目)我得到了意想不到的0!
这一般是mapreduce的自然行为吗?对于MongoDB?对于pymongo(我正在使用)?
答案 0 :(得分:37)
reduce函数将具有相同键的文档合并到一个文档中。如果map函数为特定键发出单个文档(与键3的情况一样),则不会调用reduce函数。
答案 1 :(得分:4)
我意识到这是一个较老的问题,但我发现它并感觉我仍然不明白为什么这种行为存在以及如何构建map / reduce功能因此它不是问题。
如果有一个密钥实例,MongoDB不会调用reduce函数的原因是因为没有必要(我希望这会在一瞬间更有意义)。以下是requirements for reduce functions:
- reduce函数必须将类型必须相同的对象返回到map函数发出的值的类型。
- valuesArray中元素的顺序不应影响reduce函数的输出
- reduce函数必须是幂等的。
第一个要求非常重要,似乎很多人都忽略了它,因为我看到很多人在reduce函数中映射然后处理finalize函数中的单键情况。然而,这是解决问题的错误方法。
这样想:如果只有一个键的实例,一个简单的优化是完全跳过reducer(没有什么可以减少的)。单键值仍包含在输出中,但reducer的目的是在集合中构建多键文档的聚合结果。如果mapper和reducer输出的是同一类型,那么通过查看map / reduce函数输出的对象结构,你应该不知道。您不必使用finalize函数来更正未通过reducer运行的对象的结构。
简而言之,在map函数中进行映射,并将多键值减少为reduce函数中的单个聚合结果。
答案 2 :(得分:3)
解决方案:
检查此字段并执行必要的操作
$map = new MongoCode("function() {
var value = {
time: this.time,
email_id: this.email_id,
single: 0
};
emit(this.email, value);
}");
$reduce = new MongoCode("function(k, vals) {
// make some need actions here
return {
time: vals[0].time,
email_id: vals[0].email_id,
single: 1
};
}");
$finalize = new MongoCode("function(key, reducedVal) {
if (reducedVal.single == 0) {
reducedVal.time = 11111;
}
return reducedVal;
};");
答案 3 :(得分:1)
“MongoDB不会为只有一个值的键调用reduce函数.values参数是一个数组,其元素是”映射“到键的值对象。”
http://docs.mongodb.org/manual/reference/command/mapReduce/#mapreduce-reduce-cmd
答案 4 :(得分:0)
这通常是mapreduce的自然行为吗?
是