0

我正在尝试使用 Map Reduce 根据每个日期的字段值之一来计算文档数量。首先,这是几个常规 find() 函数的结果:

db.errors.find({ "cDate" : ISODate("2012-11-20T00:00:00Z") }).count();

返回 579(即该日期有 579 个文档)

db.errors.find( { $and: [ { "cDate" : ISODate("2012-11-20T00:00:00Z") }, {"Type":"General"} ] } ).count()

返回 443(即该日期有 443 个文档,其中 Type="General")

以下是我的 MapReduce:

db.runCommand({ mapreduce: "errors", 
 map : function Map() {
    emit(
        this.cDate,//Holds a date value
        {
        count: 1,
        countGeneral: 1,
        Type: this.Type 
        }
    );
},

reduce : function Reduce(key, values) {
    var reduced = {count:0,countGeneral:0,Type:''};

    values.forEach(function(val) {
        reduced.count += val.count; 
        if (val.Type === 'General')
            reduced.countGeneral += val.countGeneral;
    });

return reduced; 
},

finalize : function Finalize(key, reduced) {
    return reduced;
},

query : { "cDate" : { "$gte" : ISODate("2012-11-20T00:00:00Z") } },

out : { inline : 1 }
});

对于日期 20-11-20,map reduce 返回:

count: 579

countGeneral: 60 (should be 443 according to the above find query)

现在,我知道 Reduce 的循环方式是不可预测的,那么我应该怎么做呢?谢谢

4

2 回答 2

1

我建议你仅仅因为你没有在你的 reduce 部分返回“General”而丢失你的其余值。

map对于部件中发出并从reduce函数返回的所有值,Reduce 运行不止一次。

例如,当 reduce 的第一次迭代运行时,您会得到包含以下内容的输出对象:

{count: 15, countGeneral: 3, Type: ''}

而reduce的其他迭代收集这个对象和其他类似的对象,看不到Type:'General'那里,也不再增加countGeneral

于 2012-11-27T14:42:57.833 回答
0

你的地图功能是错误的。你可以这样做:

function Map() {
    var cG=0;
    if (this.Type == 'General') { cG=1; }
    emit(
        this.cDate,//Holds a date value
        {
        count: 1,
        countGeneral: cG
        }
    );
}

如果 Type 是“General”,则发出 countGeneral 1,否则发出 0。

然后你可以完全从你的 emit 函数中删除类型检查,因为你无论如何都会在你的 reduce 函数中破坏它。目前,您的 reduce clobbers 类型信息在 reduce 阶段从 emit 传递。

于 2012-11-27T17:53:35.183 回答