所以我认为可能有一些 mongodb 命令根据它们在索引中的位置通过索引键获取文档。关键是我可以像这样创建覆盖的复合索引:
不,MongoDB 中没有这样的功能,尽管能够随机化结果集是个好主意。同时这里有一个 JIRA:https ://jira.mongodb.org/browse/SERVER-533
由于无法从索引位置进行选择,因此它可以使用索引并因此进行单次往返,因此您别无选择,只能打开多个游标。
当前的解决方案取决于结果集中有多少文档。
如果您的结果集中有少量文档,您可以轻松解决此问题skip(rand())
,limit(1)
但是您必须注意这两者skip()
并且limit()
不能有效地使用索引。
这并不意味着它会扫描整个 Btree 它意味着它会扫描到你skip()
。
这意味着,如果您的结果集变大并且rand()
数量变得很大,您将看到严重的性能问题,就像许多人一样。
可能解决此问题的一种好方法是维护:
并使用该新字段“跳过”使用其余查询,例如:
var arr = db.articles.find({topic: 3, rand: rand()}, {_id:1}).limit(7).toArray();
0
将使用to 的1
想法得到 7 个随机行。
这种随机排序能力依赖于不断变化的数据集来帮助在排序中创建随机性。当然,如果结果集是连续静态的,这将不起作用。
至于使用batchSize,它在这里变得无关紧要,事实上通常也是如此。例如,您使用 BatchSize 来获取所有结果的逻辑并不完全有意义,因为 BatchSize 通常具有 16MB 的绝对最大大小。这意味着,如果您的文件很大,您可能无法获得您认为的单次往返。
这也只规定服务器将一次发送所有这些数据,它并不表示放置在服务器上的工作量,只是一次通过网络发送的数据量。
因此,考虑到您必须使用多个游标(我推荐的方式)来执行此操作,您可以运行:
var arr = db.articles.find({topic: 3, rand: {$gte:rand()}}).sort({rand:1}).limit(1);
几次,或者无论你需要多少次,都会重复。这与游标的正常迭代没有太大区别,只要您拥有正确的索引,应该会非常快。
还有另一种方法,但我不推荐它。你可以运行一个 MR,比如说,每小时一次或者创建另一个集合的东西,_id
这rand()
意味着你可以执行我展示的第一个查询:
var arr = db.articles.find({topic: 3, rand: rand()}, {_id:1}).limit(7).toArray();
并且真的得到7个随机记录,因为rand()
会,当然会有所不同。但这不是实时的,对于大型数据集上的服务器也不是很好,因此我不推荐这样的事情。
编辑
还有另一种方式。使用自动递增的 id,您可以执行一个$or
语句来一次挑选出 7 rand()
s。然而,这引入了另一个问题,删除。
如果您删除任何行,您可能会遇到rand()
不存在的行,因此不会返回任何行。由于不维护自动递增的 id 以对抗删除服务器端,因此您必须自己执行此操作。这不是一件容易或可扩展的事情。
要添加到此$or
语句中不能limit()
ed on 子句,这意味着您无法通过执行 sub select type$or
来解决此问题,以使 MongoDB 仅$or
使用$gte
.
这同样适用于rand()
between0
和1
。$or
如果你可以限制子句,这将适用。