我在map-reduce过程中丢失了行吗?

时间:2015-09-14 18:43:59

标签: mongodb mapreduce

我有一个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
}

1 个答案:

答案 0 :(得分:2)

来自MongoDB mapReduce docs

  

因为可以多次调用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需要对totalcount的值求和,总是返回相同格式的对象,你应该得到预期的值。

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;