我正在尝试使用map reduce来了解什么时候这会有所帮助。
所以我有一个名为"动作"的集合,里面有10万个这样的文档:
{
"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做点什么?
是的,你可以使用它,但更精细的回应是,可能有更好的工具来做你想做的事情。
MapReduce对于某些任务很方便,但通常最适合在其他任务不适用时使用。在MongoDB中包含mapReduce早于聚合框架的引入,这通常是您应该在可能的时候使用的:
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一次。事实上,它将以"块"的形式处理输出,从而"减少"该输出的一部分,并将其放回以相对于其他输出再次"减少",直到该键只有一个值为止。
因此,重要的是从reduce函数发出与从"map"函数发送的数据类型相同的数据。当你不理解函数的这一部分时,这是一个棘手的问题,可能会导致奇怪的结果。事实上,这是mapReduce处理单个键值的大值结果并减少它们的基本方式。
但一般来说,您应该在可能的情况下使用聚合框架,如果问题需要一些特殊的计算,而这些计算在那里是不可能的,或者有一些复杂的文档遍历,需要使用JavaScript进行检查,那么这就是您使用mapReduce的地方。
您不想对操作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的计数。该计数可以通过访问action_ids
数组的length
来获得,但我想我会将其分开以使示例更清晰。