10

我想要来自 mongoDB 集合的单个随机文档。现在我的 mongoDB 集合包含超过 10 亿个集合。如何从该集合中获取单个随机文档?

4

5 回答 5

21

我从未在 Python 中使用过 MongoDB,但是对于您的问题有一个通用的解决方案。这是一个用于获取单个随机文档的 MongoDB shell 脚本:

N = db.collection.count(condition)
db.collection.find(condition).limit(1).skip(Math.floor(Math.random()*N))

condition这是一个 MongoDB 查询。如果要查询整个集合,请使用query = null.

这是一个通用解决方案,因此它适用于任何 MongoDB 驱动程序。


更新

我运行了一个基准测试来测试几个实现。首先,我创建了包含 5567249 个带有索引随机字段的文档的测试集合rnd

我选择了三种方法相互比较:

第一种方法:

db.collection.find().limit(1).skip(Math.floor(Math.random()*N))

第二种方法:

db.collection.find({rnd: {$gte: Math.random()}}).sort({rnd:1}).limit(1)

第三种方法:

db.collection.findOne({rnd: {$gte: Math.random()}})

我将每种方法运行了 10 次,得到了它的平均计算时间:

method 1: 882.1 msec
method 2: 1.2 msec
method 3: 0.6 msec

这个基准表明我的解决方案不是最快的。

但是第三种解决方案也不是一个好的解决方案,因为它找到了数据库中的第一个元素(按自然顺序排序rnd > random()。因此,它的输出并不是真正随机的。

我认为第二种方法是经常使用的最佳方法。但它有一个缺陷:它需要更改整个数据库并确保附加索引。

于 2012-11-23T07:30:54.563 回答
6

为您的集合添加一个名为的附加列random,并使其中的值介于 0 到 1 之间。您可以通过 为每条记录分配 0 到 1 之间的随机浮点到此列中[random.random() for _ in range(0, 10)]

然后:-

import random

collection = mongodb["collection_name"]

rand = random.random()  # rand will be a floating point between 0 to 1.
random_record = collection.find_one({ 'random' => { '$gte' => rand } })

MongoDB 将在适当的时候有它的本地实现。在此处提交功能 - https://jira.mongodb.org/browse/SERVER-533

在撰写本文时尚未实施。

于 2012-11-23T07:32:19.040 回答
6

由于MongoDB 3.2,它可以使用aggregate带有$sample运算符的函数来完成,如docs中所述。它超级快。以下代码将从集合中随机选择 20 个文档。

db.collection.aggregate( [ { $sample: {size: 20} } ] )

如果您需要选择具有特定标准的随机文档,您可以将其与$match操作员一起使用

db.collection.aggregate([ 
    { $sample: {size: 20} }, 
    { $match:{"yourField": value} } 
  ])

当心订单!如果我在我的小型数据库中搜索大约 100k 个文档,上面的这个命令需要 15 毫秒,而当你切换顺序时,它是 1750 毫秒(慢了 100 倍以上)。原因当然很明显。此外,通过这个顺序,您可以获得那些随机 20 个文档的子集......

于 2016-04-27T08:32:18.620 回答
2

以高效的方式?至少可以说,如果不更改您的数据,这很难。

想象一下,您尝试从 1b 文档中获取 1,000,000 的 rand()。那会很慢,非常慢。这是因为 MongoDB 在跳过时没有有效利用索引。

正如@Calvin 所说,MongoDB 有一个获取随机文档的功能请求,但尚未实现。

如果您要定期执行此操作,atm 执行此操作的最高效方法是在您的记录中添加一个自动递增的 id:http ://www.mongodb.org/display/DOCS/How+to+Make+an+ Auto+Incrementing+Field并使用它来rand()打开。

编辑

澄清; 使用自动递增 id 时,您最初需要执行一个查询(除非您以另一种方式跟踪它)以获得该字段的最高值。您可以查询计数器集合或集合本身并反向排序 ( sort({field:-1})) 并limit(1)获得 的最大值rand()

您还需要考虑数据的变化,这意味着您实际上想要$gte那个随机位置。

我的想法可以在这里得到更多解释:php mongodb find nth entry in collection

于 2012-11-23T08:14:02.967 回答
1

如果您的对象上有 int id,您可以执行类似的操作

findOne({id: {$gte: rand()}}) 
于 2012-11-23T07:28:52.353 回答