Ухудшается ли производительность запроса членства NDB (операция IN) при большом количестве возможных значений?

В документации для операции запроса IN указано, что эти запросы реализованы. как большой запрос на равенство с ИЛИ:

qry = Article.query(Article.tags.IN(['python', 'ruby', 'php']))

эквивалентно:

qry = Article.query(ndb.OR(Article.tags == 'python',
                           Article.tags == 'ruby',
                           Article.tags == 'php'))

В настоящее время я моделирую некоторые объекты для проекта GAE и планирую использовать эти запросы на членство с множеством возможных значений:

qry = Player.query(Player.facebook_id.IN(list_of_facebook_ids))

где list_of_facebook_ids может иметь тысячи элементов.

Будет ли этот тип запроса хорошо работать с тысячами возможных значений в списке? Если нет, то какой рекомендуемый подход для моделирования?


person Pascal Bourque    schedule 13.08.2012    source источник


Ответы (2)


Это не будет работать с тысячами значений (на самом деле я уверен, что оно начинает ухудшаться с более чем 10 значениями). Единственная альтернатива, о которой я могу думать, - это некоторая форма предварительного вычисления. Вам придется изменить схему.

person Guido van Rossum    schedule 13.08.2012
comment
Спасибо. Я думаю об использовании 'facebook_id' в качестве ключа для моих сущностей и использовании ndb.get_multi() для получения всех сущностей, которые есть в моем списке возможных значений. Будет ли это работать? - person Pascal Bourque; 13.08.2012
comment
get_multi() отлично работает с сотнями ключей; Я бы поколебался с тысячами, хотя, если объекты маленькие или вы ожидаете, что многие из них не существуют, вы можете это сделать. - person Guido van Rossum; 15.08.2012
comment
Спасибо! Есть ли способ сделать ключи только get_multi()? Я действительно не заинтересован в извлечении целых сущностей, я просто хочу ответить на вопрос среди этого списка ключей, которые присутствуют в хранилище данных? Есть ли что-то адаптированное для такого рода запросов? - person Pascal Bourque; 15.08.2012
comment
Нет, у нас нет такой функции. Если ваши сущности большие, подумайте о том, чтобы разбить их на две части: упрощенную сводку и необязательную часть, содержащую более редко используемые, более крупные свойства. Вы можете сделать последний дочерним элементом первого, чтобы вы могли читать и записывать их атомарно. - person Guido van Rossum; 16.08.2012

Один из способов сделать это — создать новую модель под названием FacebookPlayer, которая является индексом. Это будет ключом facebook_id. Вы будете обновлять его всякий раз, когда добавляете нового игрока. Это выглядит примерно так:

class FacebookUser(ndb.Model):
    player = ndb.KeyProperty(kind='Player', required=True)

Теперь вы можете вообще избежать запросов. Ты можешь это сделать:

# Build keys from facebook ids.
facebook_id_keys = []
for facebook_id in list_of_facebook_ids:
    facebook_id_keys.append(ndb.Key('FacebookPlayer', facebook_id))

keysOfUsersMatchedByFacebookId = []
for facebook_player in ndb.get_multi(facebook_id_keys):
    if facebook_player:
        keysOfUsersMatchedByFacebookId.append(facebook_player.player)
usersMatchedByFacebookId = ndb.get_multi(keysOfUsersMatchedByFacebookId)

Если list_of_facebook_ids содержит тысячи элементов, вы должны делать это партиями.

person Robert Do    schedule 03.03.2014