我想从一个巨大的集合(1亿条记录)中获得一个随机记录。

最快最有效的方法是什么?

数据已经在那里,没有字段可以生成随机数并获得随机行。


当前回答

没有一个解决方案对我有效。尤其是当缝隙多、集小的时候。 这对我来说很好(在php中):

$count = $collection->count($search);
$skip = mt_rand(0, $count - 1);
$result = $collection->find($search)->skip($skip)->limit(1)->getNext();

其他回答

使用Python (pymongo),聚合函数也可以工作。

collection.aggregate([{'$sample': {'size': sample_size }}])

这种方法比对随机数(例如collection.find([random_int]))运行查询要快得多。对于大型收藏来说尤其如此。

我的PHP/MongoDB排序/顺序随机解决方案。希望这对大家有所帮助。

注意:我在我的MongoDB集合中有数字ID,引用一个MySQL数据库记录。

首先,我用10个随机生成的数字创建一个数组

    $randomNumbers = [];
    for($i = 0; $i < 10; $i++){
        $randomNumbers[] = rand(0,1000);
    }

在我的聚合中,我使用$addField管道操作符结合$arrayElemAt和$mod(模)。模数运算符将给我一个从0到9的数字,然后我用它从随机生成的数字数组中选择一个数字。

    $aggregate[] = [
        '$addFields' => [
            'random_sort' => [ '$arrayElemAt' => [ $randomNumbers, [ '$mod' => [ '$my_numeric_mysql_id', 10 ] ] ] ],
        ],
    ];

在此之后,您可以使用Pipeline排序。

    $aggregate[] = [
        '$sort' => [
            'random_sort' => 1
        ]
    ];

我最简单的解决办法是……

db.coll.find()
    .limit(1)
    .skip(Math.floor(Math.random() * 500))
    .next()

你至少有500件收藏品

我建议给每个对象添加一个随机的int字段。然后你就可以做

findOne({random_field: {$gte: rand()}}) 

随机选择一个文档。只要确保你ensureIndex({random_field:1})

如果您使用的是mongoid(文档到对象的包装器),您可以执行以下操作 Ruby。(假设你的模型是User)

User.all.to_a[rand(User.count)]

在我的。irbrc,我有

def rando klass
    klass.all.to_a[rand(klass.count)]
end

所以在rails控制台,我可以做,例如,

rando User
rando Article

从任何集合中随机获取文件。