我尝试使用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可以实现的吗?
答案 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
来获得计数,但我认为我会将其分开以使示例更清晰。