mongodb - 聚合因内存错误而失败

Posted

技术标签:

【中文标题】mongodb - 聚合因内存错误而失败【英文标题】:mongodb - aggregate failed with memory error 【发布时间】:2016-06-02 09:14:25 【问题描述】:

我正在尝试使用 id 字段在我的分片集合中查找重复项,该字段属于这种模式 -

"id" : 
        "idInner" : 
            "k1" : "v1",
            "k2" : "v2",
            "k3" : "v3",
            "k4" : "v4"
        

我使用了以下查询,但收到“异常:超过 $group 的内存限制,但不允许外部排序。通过 allowDiskUse:true 来选择加入。”错误,即使我在查询中使用了“allowDiskUse:true”。

db.collection.aggregate([
   $group: 
    _id:  id: "$id" ,
    uniqueIds:  $addToSet: "$_id" ,
    count:  $sum: 1  
   , 
   $match:  
    count:  $gte: 2  
   ,
   $sort :  count : -1 ,
   $limit : 10 
], 
 
    allowDiskUse : true
);

有没有其他方法可以得到我想要的,或者我应该在上面的查询中传递什么?谢谢。

【问题讨论】:

_id 字段本身始终使用“唯一”约束进行索引。它不能包含重复项。 这不是“_id”字段,在我的情况下,我默认让 mongo 填充。我有自己的“id”(不带下划线),其中包含我的密钥。 您的群组中真的需要uniqueIds: $addToSet: "$_id" 吗?这可能会缓解一些内存问题。 我的收藏中有大约 200 万个文档。注释掉 'uniqueIds: $addToSet: "$_id" ' 以及使用 '_id: "$id.idInner"' 仍然会出现同样的错误。 如果你想要基于你自己的“id”的集合中的唯一数据,我建议在它上面创建唯一索引。这是确保收集中唯一文档的最有效方式。 【参考方案1】:

首先在管道中运行$match,以仅保留某个范围之间的文档,例如id.idiInner.k1,以便您仅获取该范围的结果。由于您对 id 键上的重复项感兴趣,因此所有重复的文档都将满足此条件。看看你应该缩小这个范围多少,然后在下一个范围内运行它等等,直到你覆盖所有文档。

如果这是您必须经常做的事情,请通过声明范围、循环输入它们、保留每次运行的重复项并最终合并结果来实现自动化。

另一个快速破解/技巧是绕过 mongos 并直接在每个 shard 中运行聚合。这样做会将您的文档粗略地(假设分片平衡良好)限制为 docs/number_of_shards,并且您可能会克服内存限制。在第二种方法中,我假设您的分片键是 id 键,但是如果不是,那么这种方法将不起作用,因为相同的重复文档将分散在分片中。

【讨论】:

感谢您建议使用 $match 来缩小结果范围。这帮助我得到了我想要的。【参考方案2】:

请在运行命令中使用allowDiskTrue。

db.runCommand(
    aggregate: "collection",
     pipeline: [
   $group: 
    _id:  id: "$id" ,
    uniqueIds:  $addToSet: "$_id" ,
    count:  $sum: 1  
   , 
   $match:  
    count:  $gte: 2  
   ,
   $sort :  count : -1 ,
   $limit : 10 
],
     allowDiskUse: true
   
)

让我知道这是否适合你。

【讨论】:

抱歉,我刚刚试了一下,效果很好。谢谢。

以上是关于mongodb - 聚合因内存错误而失败的主要内容,如果未能解决你的问题,请参考以下文章

如果程序因错误而提前退出,那么释放动态分配的内存的正确方法是啥?

MongoDB 聚合操作

MongoDB 聚合操作(转)

Mongodb聚合操作之读书笔记

获取 ios 8 自定义键盘扩展的“因内存错误而终止”

当图像保存在核心数据的集合视图中时,应用程序因内存错误而崩溃