Как я могу отфильтровать запрос по ключу или ключам в Python для Google App Engine?

У меня есть query, и я могу применить к ним filters. без каких-либо проблем. Это отлично работает:

query.filter('foo =', 'bar')

Но что, если я хочу отфильтровать свой запрос по key или по списку ключей?

У меня они есть как свойство Key() или как string, и, попробовав что-то вроде этого, это не сработало:

query.filter('key =', 'some_key')        #no success
query.filter('key IN', ['key1', 'key2']) #no success

person Lipis    schedule 08.02.2011    source источник
comment
возможный дубликат запроса модели по ключу   -  person Jason Hall    schedule 09.02.2011
comment
@ Джейсон, я не думаю, что это дубликат .. не решает мою проблему .. Я мог бы расширить свой вопрос ..   -  person Lipis    schedule 09.02.2011


Ответы (4)


Хотя можно фильтровать по ключу - см. ответ @dplouffe - это не очень хорошая идея. Предложения «IN» выполняют один запрос для каждого элемента в предложении, поэтому в конечном итоге вы выполняете столько запросов, сколько есть ключей, что является особенно неэффективным способом достижения вашей цели.

Вместо этого используйте операцию пакетной выборки, как документы @Luke, а затем отфильтруйте любые элементы, которые вам не нужны, из списка в вашем коде.

person Nick Johnson    schedule 09.02.2011
comment
Так что это плохая идея даже использовать (как предложил @Luke) models = MyModel.get(Key.from_path(...), ...), а затем фильтровать код? или это то, что вы подразумеваете под операцией выборки? - person Lipis; 09.02.2011
comment
@Lipis Это то, что я предлагаю использовать. операции get являются пакетными и выполняются быстрее, чем запросы. - person Nick Johnson; 09.02.2011
comment
Но если у меня много записей, и я хочу вернуть их частично, например, за 10. что нужные будут в моей первой выборке () .. я путаю? - person Lipis; 09.02.2011
comment
@Lipis Как вы получаете список ключей для извлечения? Несколько странно, что вы знаете точные ключи, которые хотите получить, но не знаете, принадлежат ли они к итоговому списку результатов или нет. - person Nick Johnson; 09.02.2011
comment
Пример: 1000 пользователей имеют по 1 файлу (1000 файлов), помеченных одним и тем же тегом. Этот тег содержит список файловых ключей (я использую класс taggable-mixin.. может быть, это корень всех зол.. но мне нужна функциональность тега).. Итак, я хочу отобразить файлы, которые имеют этот тег и belog конкретному Пользователю.. - person Lipis; 09.02.2011
comment
@Lipis Почему бы не смоделировать теги как список строк или ключей в самом файле, а не наоборот? Затем вы можете выполнить один запрос с фильтрами равенства для тега и пользователя. - person Nick Johnson; 09.02.2011
comment
@Nick Ник, у меня нет причин сомневаться в том, что вы говорите, но не могли бы вы объяснить мне немного больше, в чем разница между использованием и предложением IN и пакетным методом? Разве AppEngine не должен получать ключи из разных осколков данных независимо от того, как вы это запрашиваете? Дело в том, что пакетный метод объединяет все ключи с каждого сервера вместе, а затем запрашивает по сравнению с IN, который выполняет 1 запрос в зависимости от того, найден ли ключ на том же сервере или нет? - person dplouffe; 09.02.2011
comment
Запросы @dplouffe IN обрабатываются в коде Python и приводят к тому, что SDK выдает один запрос для каждого предложения. Запрос проходит через планировщик запросов, который, хотя и имеет оптимизацию для такого рода случаев, более сложен, чем просто выборка записей. В настоящее время также несколько запросов выполняются последовательно, а не параллельно. Пакетное получение, напротив, отправляется в хранилище данных как одна операция, и оно просто параллельно ищет все соответствующие сущности и возвращает их. - person Nick Johnson; 11.02.2011

Вы можете фильтровать запросы, выполнив запрос GQL следующим образом:


result = db.GqlQuery('select * from Model where __key__ IN :1', [db.Key.from_path('Model', 'Key1'), db.Key.from_path('Model', 'Key2')]).fetch(2)

or


result = Model.get([db.Key.from_path('Model', 'Key1'), db.Key.from_path('ProModelduct', 'Key2')])
person dplouffe    schedule 09.02.2011
comment
Я до сих пор не могу использовать result.filter('foo =', 'bar') ни в одном из них.. или каким-либо другим способом сделать фильтры возможными.. - person Lipis; 09.02.2011
comment
Я не хочу сразу писать весь запрос. Это проще сделать пошагово.. поскольку количество фильтров неизвестно.. Могу ли я добавить оператор where впоследствии на втором шаге? - person Lipis; 09.02.2011
comment
Можно ли комбинировать запрос __key__ IN с запросами по другим атрибутам? - person Luke Francl; 09.02.2011

Вы не можете фильтровать по ключу. К сожалению, я ошибался. Вы можете фильтровать ключ и другие свойства одновременно, если у вас настроен индекс для его обработки. Это будет выглядеть так:

key = db.Key.from_path('MyModel', 'keyname')
MyModel.all().filter("__key__ =", key).filter('foo = ', 'bar')

Вы также можете найти ряд моделей по их ключам, идентификаторам ключей или именам ключей с помощью семейства методов get.

# if you have the key already, or can construct it from its path
models = MyModel.get(Key.from_path(...), ...)

# if you have keys with names
models = MyModel.get_by_key_name('asdf', 'xyz', ...)

# if you have keys with IDs
models = MyModel.get_by_id(123, 456, ...)

Таким образом вы можете получить множество сущностей. Я не знаю точного предела. Если какой-либо из ключей не существует, вы получите None в списке для этого объекта.

Если вам нужно отфильтровать какое-либо свойство, а также ключ, вам придется сделать это в два этапа. Либо извлеките ключи и проверьте свойство, либо запросите свойство и проверьте ключи.

Вот пример фильтрации после выборки. Обратите внимание, что вы не используете метод filter класса Query. Вместо этого просто отфильтруйте список.

models = MyModels.get_by_key_name('asdf', ...)

filtered = itertools.ifilter(lambda x: x.foo == 'bar', models)
person Luke Francl    schedule 08.02.2011
comment
На самом деле я тоже так пробовал... но после получения по списку ключей я не смог filter. Когда я делаю это: models = MyModel.get(keys) models.filter('foo =', 'bar') возвращает ошибку: AttributeError: 'list' object has no attribute 'filter' - person Lipis; 09.02.2011
comment
Можете ли вы обновить свой ответ примером того, как я могу фильтровать после их получения по ключам? - person Lipis; 09.02.2011
comment
@Lipis Вам нужно вставить .filter() перед .fetch(). См. мой ответ, почему фильтрация по ключам - плохая идея. - person Nick Johnson; 09.02.2011
comment
Спасибо, @Luke, я тоже хотел посмотреть, как это работает... но в целом я думаю, что этот подход не сработает... - person Lipis; 09.02.2011

Взгляните на: https://developers.google.com/appengine/docs/python/ndb/entities?hl=de#multiple

list_of_entities = ndb.get_multi(list_of_keys)
person mattes    schedule 13.02.2014