我想从一个巨大的集合(1亿条记录)中获得一个随机记录。
最快最有效的方法是什么?
数据已经在那里,没有字段可以生成随机数并获得随机行。
我想从一个巨大的集合(1亿条记录)中获得一个随机记录。
最快最有效的方法是什么?
数据已经在那里,没有字段可以生成随机数并获得随机行。
当前回答
使用Map/Reduce,您当然可以获得一个随机记录,只是不一定非常有效,这取决于您最终使用的过滤集合的大小。
我已经用5万个文档测试了这个方法(过滤器将其减少到大约3万个),它在Intel i3、16GB ram和SATA3 HDD上执行大约400毫秒……
db.toc_content.mapReduce(
/* map function */
function() { emit( 1, this._id ); },
/* reduce function */
function(k,v) {
var r = Math.floor((Math.random()*v.length));
return v[r];
},
/* options */
{
out: { inline: 1 },
/* Filter the collection to "A"ctive documents */
query: { status: "A" }
}
);
Map函数简单地创建一个数组,其中包含所有与查询匹配的文档的id。在我的例子中,我测试了5万个可能的文档中的大约3万个。
Reduce函数只是在数组中从0到项数(-1)之间选择一个随机整数,然后从数组中返回该_id。
400ms听起来是一段很长的时间,而且确实如此,如果您有5000万条记录而不是5万条记录,这可能会增加开销,以至于在多用户情况下无法使用。
MongoDB在核心中包含这个功能有一个悬而未决的问题…https://jira.mongodb.org/browse/SERVER-533
如果将这种“随机”选择构建到索引查找中,而不是将id收集到一个数组中然后选择一个,这将非常有帮助。(去投票吧!)
其他回答
如果你有一个简单的id键,你可以将所有的id存储在一个数组中,然后随机选择一个id。(Ruby回答):
ids = @coll.find({},fields:{_id:1}).to_a
@coll.find(ids.sample).first
我最简单的解决办法是……
db.coll.find()
.limit(1)
.skip(Math.floor(Math.random() * 500))
.next()
你至少有500件收藏品
使用Map/Reduce,您当然可以获得一个随机记录,只是不一定非常有效,这取决于您最终使用的过滤集合的大小。
我已经用5万个文档测试了这个方法(过滤器将其减少到大约3万个),它在Intel i3、16GB ram和SATA3 HDD上执行大约400毫秒……
db.toc_content.mapReduce(
/* map function */
function() { emit( 1, this._id ); },
/* reduce function */
function(k,v) {
var r = Math.floor((Math.random()*v.length));
return v[r];
},
/* options */
{
out: { inline: 1 },
/* Filter the collection to "A"ctive documents */
query: { status: "A" }
}
);
Map函数简单地创建一个数组,其中包含所有与查询匹配的文档的id。在我的例子中,我测试了5万个可能的文档中的大约3万个。
Reduce函数只是在数组中从0到项数(-1)之间选择一个随机整数,然后从数组中返回该_id。
400ms听起来是一段很长的时间,而且确实如此,如果您有5000万条记录而不是5万条记录,这可能会增加开销,以至于在多用户情况下无法使用。
MongoDB在核心中包含这个功能有一个悬而未决的问题…https://jira.mongodb.org/browse/SERVER-533
如果将这种“随机”选择构建到索引查找中,而不是将id收集到一个数组中然后选择一个,这将非常有帮助。(去投票吧!)
在Python中使用pymongo:
import random
def get_random_doc():
count = collection.count()
return collection.find()[random.randrange(count)]
我的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
]
];