我有一个大型集合,我正在运行聚合管道。我有MongoDB 2.4。我遇到了16 MB的限制。我知道我可以通过升级到2.6来解决这个问题,但这对我来说不是一个选择。
我可以达到16 MB限制以下的另一种方法是将聚合分解为几个部分,然后将部分结果合并到我的应用程序代码中。我需要拆分的字段是ObjectId。基本上,我想要的是我的$ match阶段使用类似的东西:
my_objid_field:{$ mod:[10,n]}
对于不同的n值,我将运行查询10次。但是,我无法弄清楚如何表达这一点。典型文档如下:
{
"_id" : ObjectId("514cf080358a7c3fd4113f84"),
"a" : 1,
"c" : "US",
"d" : ISODate("2013-03-23T00:00:00Z"),
"st" : ObjectId("4fcfa494c212e76b890004a2"),
"si" : 0,
"so" : ObjectId("4e9e58e62b28686b47e71cdf"),
"t" : ISODate("2013-03-23T00:00:00.779Z"),
"u" : ObjectId("4fe9845a8596aa3d990014cf"),
"se" : "dYJgW8w/kcCIJK08"
}
,来自db.currentOp()的管道是:
"pipeline" : [
{
"$match" : {
"$or" : [
{
"du" : {
"$gt" : 25
}
},
{
"du" : {
"$exists" : false
}
}
],
"bu" : {
"$exists" : false
},
"t" : {
"$gte" : ISODate("2013-03-23T00:00:00Z"),
"$lt" : ISODate("2013-03-24T00:00:00Z")
}
}
},
{
"$group" : {
"c" : {
"$sum" : 1
},
"_id" : {
"t" : "$st",
"o" : "$so"
}
}
}
]
查询匹配大约2000万个文档,结果大约有20万个文档。查询运行几分钟,然后失败,"聚合结果超出最大文档大小(16MB)"。
答案 0 :(得分:1)
您的结果太大,所以最好的办法是在管道的末尾实施$limit
:
db.collection.aggregate([
// same $match
// same $group
{ "$sort": { "_id": 1 } },
{ "$limit": 1000 } // or whatever you can go to without breaking
])
由于汇总结果,因此汇总结果$sort
并不保证按顺序排列,并且可能按发现顺序排列。您需要结果才能完成下一步的操作。
在下一次调用中,您将使用" last"来自聚合的_id
值并更改匹配管道,如下所示:
db.collection.aggregate([
{ "$match" : {
"st": { "$gte": ObjectId("4fcfa494c212e76b890004a2") }, // part of last result
"$or" : [
{ "du" : { "$gt" : 25 } },
{ "du" : { "$exists" : false } }
],
"bu" : { "$exists" : false },
"t" : {
"$gte" : ISODate("2013-03-23T00:00:00Z"),
"$lt" : ISODate("2013-03-24T00:00:00Z")
}
}},
{ "$group": {
"_id": { "t" : "$st", "o" : "$so" },
"c" : { "$sum" : 1 },
}},
{ "$match": {
"_id": { // Both elements of the last seen _id
"$ne": {
"t": ObjectId("4fcfa494c212e76b890004a2"),
"o": ObjectId("4e9e58e62b28686b47e71cdf")
}
}
}},
{ "$sort": { "_id": 1 } },
{ "$limit": 1000 }
])
因为你正在使用" st"在汇总结果中,提供的值是最后一组结果中显示的最后一个值,则排除所有小于该值的值。
最终的$match
就在那里,因为第一个{@ 1}}主要排除了结果"组合键"需要被排除在外。这就是为什么你不能在第一个$match
中进行$gt
的原因,因为组合中第二个元素的共享第一个元素的值仍然会更大。
每次迭代时仍然$sort
和$limit
并继续运行,直到返回的结果数小于您设置的限制为止。
聚合管道也有$skip
运算符,但这不是很有效,因为你会增加" skip"每1000份文件,直至处理您的200,000个结果。非常慢。
最好的方法是排除已经看到的值,然后一直切断管道结果。
这里的主要问题是_id组合本质上就是结果。这样就很难找到一个"分裂"两者的组合范围。因此,这里的妥协是每次迭代都会更快的查询。
最后,出于性能原因,现在重要的是包括" st"复合索引中的字段,因为它可以在$match
中使用,因为它是最有效的形式。
应尽快考虑迁移到MongoDB 2.6。