【问题标题】:mongodb - aggregate failed with memory errormongodb - 聚合因内存错误而失败
【发布时间】: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”的集合中的唯一数据,我建议在它上面创建唯一索引。这是确保收集中唯一文档的最有效方式。

标签: mongodb aggregation-framework


【解决方案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
   }
)

让我知道这是否适合你。

【讨论】:

  • 抱歉,我刚刚试了一下,效果很好。谢谢。
猜你喜欢
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 2021-10-24
  • 1970-01-01
  • 2023-03-10
  • 2017-11-19
  • 1970-01-01
相关资源
最近更新 更多