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

时间:2010-08-10 15:59:23

标签: python google-app-engine

目前我正在使用这样的东西:

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

但事实证明,AppEngine数据存储区中的ID不是从1开始。 我在数据存储区中有两个图像,它们的ID是6001和7001。

有没有更好的方法来检索随机图像?

4 个答案:

答案 0 :(得分: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()

编辑:根据尼克的建议更新了堕落案例。

答案 1 :(得分: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 随机实体的方法。您将不得不实施一些管理memcached密钥的开销。如果你经常对随机元素执行查询,我更喜欢这个解决方案(我假设使用批量获取 n 实体比 n 实体的查询更有效) 。

答案 2 :(得分:6)

我认为Drew Sears上面的回答(在创建时为每个实体附加一个随机浮动)有一个潜在的问题:每个项目都没有相同的机会被选中。例如,如果只有2个实体,并且一个获得0.2499的rand_num,另一个获得0.25,那么0.25将逐渐被选中。这可能对您的应用程序有效,也可能无关紧要您可以通过每次选择实体的rand_num来修复此问题,但这意味着每次读取也需要写入。

pix的答案将始终选择第一个键。

这是我能提出的最佳通用解决方案:

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

不需要其他属性,但缺点是如果Images的数量很大,count()和fetch()都会对性能产生影响。

答案 3 :(得分:1)

另一种(效率较低)方法,无需设置:

query = MyModel.all(keys_only=True)

# query.filter("...")

selected_key = None
n = 0
for key in query:
  if random.randint(0,n)==0:
    selected_key = key
  n += 1

# just in case the query is empty
if selected_key is None:
  entry = None
else:
  entry = MyModel.get(selected_key)