非常有趣,mapreduce在单个实例中工作正常,但不在分片集合中工作。如下所示,您可能会看到我收集了一个简单的map-reduce 功能,
mongos> db.tweets.findOne()
{
"_id" : ObjectId("5359771dbfe1a02a8cf1c906"),
"geometry" : {
"type" : "Point",
"coordinates" : [
131.71778292855996,
0.21856835860911106
]
},
"type" : "Feature",
"properties" : {
"isflu" : 1,
"cell_id" : 60079,
"user_id" : 35,
"time" : ISODate("2014-04-24T15:42:05.048Z")
}
}
mongos> db.tweets.find({"properties.user_id":35}).count()
44247
mongos> map_flow
function () { var key=this.properties.user_id; var value={ "cell_id":1}; emit(key,value); }
mongos> reduce2
function (key,values){ var ros={flows:[]}; values.forEach(function(v){ros.flows.push(v.cell_id);});return ros;}
mongos> db.tweets.mapReduce(map_flow,reduce2, { out:"flows2", sort:{"properties.user_id":1,"properties.time":1} })
但结果不是我想要的
mongos> db.flows2.find({"_id":35})
{ "_id" : 35, "value" : { "flows" : [ null, null, null ] } }
我有很多空,有趣的都有三个。 mongodb mapreduce似乎不适合分片收集?
答案 0 :(得分:1)
MapReduce的首要规则是:
你破坏了这个规则,所以你的MapReduce只适用于小集合,其中reduce只对每个键调用一次(这是MapReduce的第二个规则 - reduce函数可以被称为零,一次或多次)。
您的地图功能会为每个文档准确发出此值{cell_id:1}
。
你的reduce函数如何使用这个值?好吧,您返回一个值,该值是一个带有数组的文档,您可以在其中推送cell_id
值。这已经很奇了,因为那个值是1,所以我不确定为什么你不会只发出1(如果你想数)。
但是看看当多个分片将一堆1推入这个流数组时会发生什么(无论它是你想要的,这就是你的代码正在做的事情),现在还会在几个已经减少的值上调用:
reduce(key, [ {flows:[1,1,1,1]},{flows:[1,1,1,1,1,1,1,1,1]}, etc ] )
您的reduce函数现在尝试获取values数组的每个成员(这是一个包含单个字段flows
的文档)并将v.cell_id
推送到您的流数组。这里没有cell_id字段,所以当然你最终会得到null
。三个空值可能是因为你有三个分片?
我建议你清楚地告诉自己你在这段代码中想要聚合的是什么,然后重写你的map和你的reduce以符合MongoDB中mapReduce希望你的代码遵循的规则。