Как получить что-то случайное в хранилище данных (AppEngine)? - PullRequest
17 голосов
/ 10 августа 2010

В настоящее время я использую что-то вроде этого:

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

Но оказывается, что идентификаторы в хранилище данных в AppEngine не начинаются с 1. У меня есть два изображения в хранилище данных, и их идентификаторы6001 и 7001.

Есть ли лучший способ получения случайных изображений?

Ответы [ 4 ]

18 голосов
/ 10 августа 2010

Хранилище данных распределено, поэтому идентификаторы не являются последовательными: два узла хранилища данных должны иметь возможность генерировать идентификатор одновременно, не вызывая конфликта.

Чтобы получить случайный объект, вы можете прикрепить случайное число от 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()

Редактировать: Обновлен падеж для случая с предложением Ника.

10 голосов
/ 23 мая 2011

Другое решение (если вы не хотите добавлять дополнительное свойство).Сохраните набор ключей в памяти.

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 сущностей).

6 голосов
/ 22 февраля 2012

Я думаю, что ответ Дрю Сирса выше (прикрепление случайного числа к каждой сущности при создании) имеет потенциальную проблему: у каждого предмета нет равных шансов быть выбранным.Например, если существует только 2 сущности, и одна получает значение rand_num, равное 0,2499, а другая получает 0,25, то одна единица, равная 0,25, будет выбрана почти все время.Это может иметь или не иметь значения для вашего приложения.Вы можете исправить это, изменяя rand_num объекта каждый раз, когда он выбирается, но это означает, что для каждого чтения также требуется запись.

И ответ пикс всегда будет выбирать первую клавишу.

Вотлучшее универсальное решение, которое я мог бы придумать:

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

Никаких дополнительных свойств не требуется, но недостатком является то, что count () и fetch () оба влияют на производительность, если число изображений велико.

1 голос
/ 09 сентября 2010

Другой (менее эффективный) метод, который не требует настройки:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...