【问题标题】:Random Sampling from Mongo来自 Mongo 的随机抽样
【发布时间】:2012-09-30 20:23:03
【问题描述】:

我有一个带有文档的 mongo 集合。每个文档中有一个字段为 0 或 1。我需要从数据库中随机抽样 1000 条记录,并将具有该字段的文档数计算为 1。我需要进行 1000 次抽样。我该怎么做?

【问题讨论】:

标签: mongodb sampling database


【解决方案1】:

对于想要回答的人,您现在应该使用新的 $sample 聚合函数,这是 3.2 中的新功能。

https://docs.mongodb.org/manual/reference/operator/aggregation/sample/

db.collection_of_things.aggregate(
   [ { $sample: { size: 15 } } ]
)

然后添加另一个步骤以使用$group 计算0s 和1s 以获取计数。 Here is an example from the MongoDB docs.

【讨论】:

    【解决方案2】:

    对于 MongoDB 3.0 及之前的版本,我使用了 SQL 时代的一个老技巧(我认为 Wikipedia 将其用于他们的随机页面功能)。我在需要随机化的每个对象中存储一个介于 0 和 1 之间的随机数,我们称该字段为“r”。然后在“r”上添加一个索引。

    db.coll.ensureIndex(r: 1);
    

    现在要获取随机 x 个对象,您可以使用:

    var startVal = Math.random();
    db.coll.find({r: {$gt: startVal}}).sort({r: 1}).limit(x);
    

    这会在单个查找查询中为您提供随机对象。根据您的需要,这可能有点过头了,但如果您要随着时间的推移进行大量采样,这是一种非常有效的方法,不会给您的后端增加负担。

    【讨论】:

    • 每次都给你相同的样本。
    • @Sklavit 如果您每次生成一个新的随机数,您的样本会有所不同
    【解决方案3】:

    这是mongo shell 中的一个示例。假设collname 的集合和thefield 中的一个感兴趣的值:

    var total = db.collname.count();
    var count = 0;
    var numSamples = 1000;
    
    for (i = 0; i < numSamples; i++) {
        var random = Math.floor(Math.random()*total);
        var doc = db.collname.find().skip(random).limit(1).next();
        if (doc.thefield) {
            count += (doc.thefield == 1);
        }
    }
    

    【讨论】:

    • 这也回答了另一个问题:与 SQL 不同,MongoDB 实际上并没有内置函数。此外,对于较大的随机值,跳过可能(...可能)变得很麻烦,但这取决于。
    【解决方案4】:

    我打算用这个来编辑我对@Stennies 答案的评论,但如果您要跳过大量记录(在这里说大话),您也可以在此处使用单独的自动递增 ID 索引作为替代方案。

    我为另一个问题写了另一个答案,很像这个问题,有人试图找到集合的第 n 条记录:

    php mongodb find nth entry in collection

    我的回答的后半部分基本上描述了一种解决此问题的潜在方法。当然,您仍然需要循环 1000 次才能获得随机行。

    【讨论】:

      【解决方案5】:

      如果您使用的是 mongoengine,则可以使用 SequenceField 来生成增量计数器。

      class User(db.DynamicDocument):
          counter = db.SequenceField(collection_name="user.counters")
      

      然后要获取 100 个随机列表,请执行以下操作

      def get_random_users(number_requested):
          users_to_fetch = random.sample(range(1, User.objects.count() + 1), min(number_requested, User.objects.count()))
          return User.objects(counter__in=users_to_fetch)
      

      你会打电话的地方

      get_random_users(100)
      

      【讨论】:

        猜你喜欢
        • 2020-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多