【问题标题】:"Random" sample from MongoDB returning heavily skewed results来自 MongoDB 的“随机”样本返回严重偏差的结果
【发布时间】:2017-10-23 11:19:26
【问题描述】:

我在 MongoDB 中有一个包含约 600,000 个文档的集合。其中,恰好一半的字段设置为 0,而其他字段的字段设置为 1。当我尝试使用聚合管道中的 sample 操作(通过 PyMongo)从该集合中获取随机样本时,它严重偏向 1 值。

在 25,000 条记录样本中,可能有 300-400 条记录的字段为 0,然后有 24,000 多条记录的字段为 1。

如果初始集合是均匀分布的,为什么使用$sample 返回的结果分布如此不同,我如何从集合中获得有代表性的样本?

这是我用于查询的 PyMongo 行:

cursor = foo_database.bar_collection.aggregate( [ { "$sample": { "size": 25000} } ])

【问题讨论】:

  • $sample是在服务端实现的,所以语言实现没有效果。除了size 之外,没有其他参数选项,因此它非常像一个“黑匣子”,只是按照实现的方式运行。如果您希望它对于某些值“均匀分布”,那么您实际上需要“两个”或更多操作,对于您希望均匀分布的每个值一个。否则,它只是“随机”的,正如预期的那样。

标签: mongodb random aggregation-framework pymongo


【解决方案1】:

从 MongoDB 3.4.9 开始,您观察到的偏差的部分原因是 $sample 几乎完全依赖于存储引擎的随机游标实现(请参阅 SERVER-19183)。这样做是为了在集合包含大量数据时$sample 可以执行。但是,由于存储引擎使用 B-tree 类型实现按排序顺序存储文档,因此并不总是可以创建真正随机的结果。

目前有两个功能要求更好的$sample 机制,即SERVER-22069SERVER-22068

话虽如此,如果您需要真正无偏见的数据样本,那么滚动您自己的类似$sample 的解决方案可能是目前进行的最佳方式。比如:

  1. 获取集合中所有_id 的列表。
  2. 对此列表执行随机抽样(例如,使用 Python 的 random.choice)。
  3. 使用采样的_id 获取所有相关文档,这将根据您想要的样本大小合理执行,因为_id 始终被索引。

【讨论】:

    猜你喜欢
    • 2020-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    相关资源
    最近更新 更多