我有一个604行的表,我正在尝试启动mapreduce,但是我得到了一些奇怪的结果。 这是一个简化版本,命令result.total = values.length应该返回604而不是5.你能帮助我在这段代码中得到错误吗?
db.foo.mapReduce(
function() {
emit("ALL" , this.libres)
},
function(key, values) {
result = {total: 0,count:0};
result.total=values.length;
for (var i= 0; i < values.length; i++) {
if (values[i]==0){result.count++}
}
return result
},
{out:{inline:1}})
{
"results" : [
{
"_id" : "ALL",
"value" : {
"total" : 5,
"count" : 0
}
}
],
"timeMillis" : 26,
"counts" : {
"input" : 604,
"emit" : 604,
"reduce" : 7,
"output" : 1
},
"ok" : 1
}
答案 0 :(得分:2)
因为可以多次调用reduce函数 对于相同的密钥,以下属性必须为真:
返回对象的类型必须与其类型相同 map函数发出的值。
必须使用reduce函数 关联。以下陈述必须为真:
reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
reduce函数必须是幂等的。确保以下内容 陈述是真的:
reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
你的reduce函数不满足这些条件,并且根据输出"reduce" : 7
,reduce函数被调用了7次。
您的映射器仅输出1个键"ALL"
,因此对于此键,reduce函数被调用7次,后来的调用将先前调用的输出作为输入。
因此,您会看到计数的意外结果,因为最终reduce调用的输入不是604行的完整映射器结果。相反,输入是reduce函数的一些先前调用的输出。
要解决此问题,您需要返回map函数并将输出更改为reducer也可用作输出的格式。它可以与当前的reducer输出格式相同,但值只是一个文档的摘要。在地图功能中尝试以下操作:
emit("ALL" , {total : 1, count : this.libres == 0 ? 1 : 0} )
然后你的reducer需要对total
和count
的值求和,总是返回相同格式的对象,你应该得到预期的值。
result = { total: 0, count:0 };
for (var i = 0; i < values.length; i++) {
result.total += values[i].total;
result.count += values[i].count;
}
return result;