如何在数据存储中获取随机内容(AppEngine)?

17 投票
4 回答
4468 浏览
提问于 2025-04-16 02:35

我现在用的是这样的代码:

    images = Image.all()
    count = images.count()
    random_numb = random.randrange(1, count)
    image = Image.get_by_id(random_numb)

但是我发现,在AppEngine的数据库里,图片的编号并不是从1开始的。我有两张图片,它们的编号分别是6001和7001。

有没有更好的方法来随机获取图片呢?

4 个回答

6

我觉得Drew Sears上面的回答(在创建时给每个实体附加一个随机浮点数)可能有个问题:每个项目被选中的机会并不相等。比如说,如果只有两个实体,一个的随机数是0.2499,另一个是0.25,那么0.25的那个几乎总是会被选中。这对你的应用来说可能有影响,也可能没有。你可以通过每次选中一个实体时改变它的随机数来解决这个问题,但这样每次读取都需要写入。

而pix的回答总是会选择第一个键。

这是我能想到的最好的通用解决方案:

num_images = Image.all().count()
offset = random.randrange(0, num_images)
image = Image.all().fetch(1, offset)[0]

这个方法不需要额外的属性,但缺点是如果图片数量很大,count()和fetch()的性能会受到影响。

10

还有一种解决方案(如果你不想添加额外的属性)。就是在内存中保持一组键。

import random

# Get all the keys, not the Entities
q = ItemUser.all(keys_only=True).filter('is_active =', True)
item_keys = q.fetch(2000) 

# Get a random set of those keys, in this case 20 
random_keys = random.sample(item_keys, 20)

# Get those 20 Entities
items = db.get(random_keys)

上面的代码展示了获取键的基本方法,然后用这些键创建一个随机集合来进行批量获取。你可以把这组键保存在内存里,随着你创建新的 ItemUser 实体而不断添加,然后再写一个方法来返回 n 个随机的实体。如果你想管理这些内存中的键,可能需要实现一些额外的操作。如果你经常需要查询随机元素,我觉得这个方法更好(我认为用批量获取 n 个实体比单独查询 n 个实体更高效)。

18

这个数据存储是分布式的,所以生成的ID不是按顺序来的:两个数据存储的节点需要能够同时生成一个ID,而不会产生冲突。

为了获取一个随机的实体,你可以在创建每个实体的时候,给它附加一个0到1之间的随机小数。然后在查询的时候,可以这样做:

rand_num = random.random()
entity = MyModel.all().order('rand_num').filter('rand_num >=', rand_num).get()
if entity is None:
  entity = MyModel.all().order('rand_num').get()

编辑:根据Nick的建议,更新了处理方式。

撰写回答