从 Google App Engine 数据存储区获取随机记录?

Posted

技术标签:

【中文标题】从 Google App Engine 数据存储区获取随机记录?【英文标题】:Fetching a random record from the Google App Engine Datastore? 【发布时间】:2011-03-01 11:41:43 【问题描述】:

我有一个模型中包含大约 1,000,000 个实体的数据存储。我想从中获取 10 个随机实体。

我不知道该怎么做?有人可以帮忙吗?

【问题讨论】:

Querying for N random records on Appengine datastore的可能重复 【参考方案1】:

为每个实体分配一个随机数并将其存储在实体中。然后查询随机数大于(或小于)某个其他随机数的十条记录。

然而,这并不是完全随机的,因为具有附近随机数的实体往往会一起出现。如果你想打败它,基于十个随机数做十次查询,但是这样效率会降低。

【讨论】:

完全正确。可能想提及随机数的范围(0..1 是标准)。 在不影响读取时间效率的情况下增加随机性的一种可能性是将任务排入队列以将新的随机数分配给您获取的实体,因此如果您再次点击其中一个,您将无法获得与它相同的邻居。 @NickJohnson 你能澄清一下标准范围吗?抱歉,我不明白您所说的 (0..1) 是什么意思?另外,对你们俩来说:我担心会用完我的一个不等式过滤器来执行这个操作(因为在某些查询中我需要它是随机的,但同时在另一个属性上运行一个等式过滤器)。做 10 次查询有多糟糕,成本基本是 10 倍吗? 不要忘记使“大于或小于”的选择也是随机的。否则,顶部或底部的项目将很少匹配。【参考方案2】:

Jason Hall 的回答和the one here 并不可怕,但正如他所提到的,它们也不是真正随机的。例如,如果随机数全部组合在一起,即使进行十次查询也不会是随机的。为了让事情真正随机化,这里有两种可能的解决方案:

解决方案 1

为每个数据存储对象分配一个索引,跟踪最大索引,每次想要得到随机记录时随机选择一个索引:

MyObject.objects.filter('index =', random.randrange(0, maxindex+1))

优势:真正随机。快。

缺点:在添加和删除对象时必须正确维护索引,这会使这两个操作都成为 O(N) 操作。

解决方案 2

在创建每个数据存储编号时为其分配一个随机数。然后,为了第一次获取随机记录,查询一个随机数大于其他随机数的记录,并按随机数排序(即MyObject.order('rand_num').filter('rand_num >=', random.random()))。然后将该查询保存为内存缓存中的游标。要在第一次之后获取随机记录,请从 memcache 中加载游标并转到下一项。如果第一个之后没有项目,请再次运行查询。

为防止对象序列重复,在每次读取数据存储区时,为您刚刚读取的实体提供一个新的随机数并将其保存回数据存储区。

向上:真正随机。无需维护复杂的索引。

下行:需要跟踪光标。每次获得随机记录时都需要进行一次 put。

【讨论】:

“例如,如果随机数全部组合在一起,即使进行十次查询也不会是随机的” - 我假设您正在谈论分配给数据存储行的随机数。这只是少量记录的问题 - 值之间的差距的标准偏差随着值数量的增加而缩小,达到统计上不显着的程度。您的解决方案 1 需要一个单调计数器,这在 App Engine 上是一项缓慢且昂贵的操作。解决方案 2 使用不替换的选择,这与 OP 的要求不同。 是的,如果记录不多或者您以很高的速度检索它们,那么简单的方法就会失效。此外,一旦设置了 rand_num 值,它们的分布就固定了。您将无法获得良好的均匀分布,并且某些记录很少会被选中。 不,那是我的观点 - 您拥有的记录数越多,间隔的标准偏差越小。也就是说,分配给它们的间隔异常小的实体将成比例地减少。 Wooble 建议在您选择记录后重新分配编号也有助于抵消这种情况。

以上是关于从 Google App Engine 数据存储区获取随机记录?的主要内容,如果未能解决你的问题,请参考以下文章

从 Google App Engine 中的数据存储区获取实体以在 iOS 应用中使用

python Google App Engine:将CSV导入数据存储区

数据存储区中的 Google App Engine 版本控制

Google App Engine 数据存储区中不精确查询的良好模式是啥?

在 Google App Engine 上的数据存储区中更新大量实体

连接到 Google App Engine 数据存储