mongodb - 无法理解为什么/如何使用map-reduce

时间:2014-09-23 01:02:19

标签: javascript mongodb mapreduce mongodb-query aggregation-framework

我尝试使用map-reduce来了解何时可以提供帮助。

所以我有一个名为" actions"这样的100k文档:

{
    "profile_id":1111,
    "action_id":2222
}

现在我尝试做map-reduce示例。我试图获取"所有用户和所有用户的总操作列表" 。这可能吗?我的代码:

db.fbooklikes.mapReduce(
    function(){
        emit(this.profile_id, this.action_id);
    },
    function(keyProfile, valueAction){
        return Array.sum(valueAction);
    },
    {
        out:"example"
    }
)

..这不起作用。结果是:

"counts" : {
    "input" : 100000,
    "emit" : 100000,
    "reduce" : 1146,
    "output" : 13
},
"ok" : 1,
"_o" : {
    "result" : "map_reduce_example",
    "timeMillis" : 2539,
    "counts" : {
        "input" : 100000,
        "emit" : 100000,
        "reduce" : 1146,
        "output" : 13
    },
    "ok" : 1
},

我尝试做的事情是map-reduce可以实现的吗?

2 个答案:

答案 0 :(得分:3)

嗯,是的,你可以使用它,但更精确的反应是,有可能更好的工具来做你想要的。

MapReduce对某些任务很方便,但通常最适合其他不适用的东西。在MongoDB中包含mapReduce会导致引入aggregation framework,这通常是您应该使用的内容:

db.fbooklikes.aggregate([
    { "$group": {
        "_id": "$profile_id",
        "count": { "$sum": 1 }
    }}
])

这将简单地返回按“profile_id”的每个值分组的集合中的所有文档的计数。

MapReduce需要JavaScript评估,因此运行速度比聚合框架实现的本机代码函数慢得多。有时您必须使用它,但在最简单的情况下,最好不要使用它,并且您需要了解一些怪癖:

db.fbooklikes.mapReduce(
    function(){
        emit(this.profile_id, 1);
    },
    function(key,values){
        return Array.sum(values);
    },
    {
        out: { "inline": 1 }
    }
)

人们对mapReduce错过的最大的事情是,reducer几乎从未被称为每次发射一次。事实上,它将以“块”处理输出,从而“减少”该输出的一部分,并将其放回到其他输出的“减少”,直到该键只有一个值。

因此,从“map”函数发送的reduce函数发出相同类型的数据非常重要。当你不理解这部分功能时,这是一个棘手的结果,可能导致奇怪的结果。事实上,mapReduce可以处理单个键值的大值结果并减少它们的基本方式。

但一般来说,你应该尽可能使用聚合框架,如果问题需要一些在那里不可能的特殊计算,或者在需要用JavaScript检查的地方进行一些复杂的文档遍历,那么你在哪里使用mapReduce。

答案 1 :(得分:2)

您不想总结动作ID,您想要计算它们。所以你需要类似下面的内容

var map = function () {
    emit(this.profile_id, { action_ids : [this.action_id], count : 1  });
}

var reduce  = function(profile_id, values) {
    var value = { action_ids: [], count: 0 };

    for (var i = 0; i < values.length; i++) {
        value.count += values[i].count;
        value.action_ids.push.apply(value.action_ids, values[i].action_ids);
    }

    return value;
}

db.fbooklikes.mapReduce(map, reduce, { out:"example" });

这将为您提供一系列操作ID以及每个配置文件ID的计数。可以通过访问length数组的action_ids来获得计数,但我认为我会将其分开以使示例更清晰。