&引用;“随机”;来自MongoDB的样本返回严重扭曲的结果

&引用;“随机”;来自MongoDB的样本返回严重扭曲的结果,mongodb,random,aggregation-framework,pymongo,Mongodb,Random,Aggregation Framework,Pymongo,我在MongoDB收集了约600000份文件。其中,有一半的字段设置为0,而另一半的字段设置为1。当我尝试使用聚合管道中的操作(通过PyMongo)从这个集合中获取随机样本时,它严重地向1值倾斜 在25000条记录样本中,字段为0时可能有300-400条记录,而字段为1时可能有24000多条记录 如果初始收集是均匀分布的,为什么使用$sample返回的结果分布差异如此之大,我如何从收集中获得具有代表性的样本 以下是我用于查询的PyMongo行: cursor = foo_database.bar

我在MongoDB收集了约600000份文件。其中,有一半的字段设置为0,而另一半的字段设置为1。当我尝试使用聚合管道中的操作(通过PyMongo)从这个集合中获取随机样本时,它严重地向1值倾斜

在25000条记录样本中,字段为0时可能有300-400条记录,而字段为1时可能有24000多条记录

如果初始收集是均匀分布的,为什么使用
$sample
返回的结果分布差异如此之大,我如何从收集中获得具有代表性的样本

以下是我用于查询的PyMongo行:

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

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

目前有两个更好的
$sample
机制的功能要求,即和

话虽如此,如果您需要一个真正无偏见的数据样本,在这一点上滚动您自己的
$sample
-样的解决方案可能是最好的方法。比如:

  • 获取集合中所有
    \u id
    的列表
  • 在此列表上执行随机抽样(例如,使用Python)
  • 使用抽样的
    \u id
    获取所有相关文档,这将根据您想要的样本大小合理执行,因为
    \u id
    始终被索引
  • 是在服务器上实现的,因此语言实现没有效果。除了
    大小
    之外,没有其他参数选项,因此它在很大程度上是一个“黑盒子”,只在实现时起作用。如果您希望它对某些值“均匀分布”,那么实际上您需要“两个”或更多的操作,对于您希望均匀分布的每个值都是一个操作。否则,它只是“随机的”,正如预期的那样。