【问题标题】:MongoDB MapReduce: Not working as expected for more than 1000 recordsMongoDB MapReduce:超过 1000 条记录无法按预期工作
【发布时间】:2013-01-03 11:49:06
【问题描述】:

我编写了一个 mapreduce 函数,其中记录以下列格式发出

{userid:<xyz>, {event:adduser, count:1}}
{userid:<xyz>, {event:login, count:1}}
{userid:<xyz>, {event:login, count:1}}
{userid:<abc>, {event:adduser, count:1}}

其中 userid 是键,其余的是该键的值。 在 MapReduce 函数之后,我想得到以下格式的结果

{userid:<xyz>,{events: [{adduser:1},{login:2}], allEventCount:3}}

为了实现这一点,我编写了以下 reduce 函数 我知道这可以通过 group by.. 在聚合框架和 mapreduce 中实现,但是对于复杂的场景,我们需要类似的功能。所以,我采用了这种方法。

var reducefn = function(key,values){
var result = {allEventCount:0, events:[]};
values.forEach(function(value){
    var notfound=true;
    for(var n = 0; n < result.events.length; n++){
        eventObj = result.events[n];
        for(ev in eventObj){
            if(ev==value.event){
                result.events[n][ev] += value.allEventCount;
                notfound=false;
                break;
            }
        }
    }
    if(notfound==true){ 
        var newEvent={}
        newEvent[value.event]=1; 
        result.events.push(newEvent);
    }
    result.allEventCount += value.allEventCount;
});
return result;

}

这运行完美,当我运行 1000 条记录时,当有 3k 或 10k 条记录时,我得到的结果是这样的

{ "_id" : {...}, "value" :{"allEventCount" :30, "events" :[ { "undefined" : 1},
{"adduser" : 1 }, {"remove" : 3 }, {"training" : 1 }, {"adminlogin" : 1 }, 
{"downgrade" : 2 } ]} }

无法理解此undefined 来自何处,并且各个事件的总和小于 allEventCount。集合中的所有文档都有非空字段event,因此没有机会未定义。

Mongo DB 版本 -- 2.2.1 环境 -- 本地机器,无分片。

在reduce函数中,当类似的操作result.allEventCount += value.allEventCount;通过时,为什么这个操作会失败result.events[n][ev] += value.allEventCount;

johnyHK建议的正确答案

减少功能:

    var reducefn = function(key,values){
    var result = {totEvents:0, event:[]};
    values.forEach(function(value){
        value.event.forEach(function(eventElem){
            var notfound=true;
            for(var n = 0; n < result.event.length; n++){
                eventObj = result.event[n];
                for(ev in eventObj){
                for(evv in eventElem){
                    if(ev==evv){
                        result.event[n][ev] += eventElem[evv];
                        notfound=false;
                        break;
                    }
                }}
            }
            if(notfound==true){ 
                result.event.push(eventElem);
            }
        });
        result.totEvents += value.totEvents;
    });
    return result;
}

【问题讨论】:

    标签: mongodb mapreduce


    【解决方案1】:

    emit 来自map 函数的对象的形状必须与从reduce 函数返回的对象相同,因为reduce 的结果可以在以下情况下反馈到reduce处理大量文档(如本例)。

    因此,您需要更改您的 emit 以发出这样的文档:

    {userid:<xyz>, {events:[{adduser: 1}], allEventCount:1}}
    {userid:<xyz>, {events:[{login: 1}], allEventCount:1}}
    

    然后相应地更新您的reduce 函数。

    【讨论】:

    • 谢谢@JohnyHK。原来是这个问题,已经解决了。
    猜你喜欢
    • 2019-04-11
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    相关资源
    最近更新 更多