Google App Engine - Как мога да направя python ndb заявка за резултати, върнати от ndb заявка?

Използвам рамка на GAE python (webapp2) за проект и имам въпрос, свързан с ndb заявката. Нека дам пример, за да обясня това ясно:

Ето един ndb модел, който имам:

class Example(ndb.Model):
  userid = ndb.StringProperty()
  field1 = ndb.StringProperty()
  field2 = ndb.StringProperty()

Ето обектите, които създадох с помощта на горния модел:

[Example(key=Key('Example', '1~A~B'), field1=u'B', field2=u'A', userid=u'1'),
 Example(key=Key('Example', '1~C~D'), field1=u'D', field2=u'C', userid=u'1'),
 Example(key=Key('Example', '2~A~B'), field1=u'B', field2=u'A', userid=u'2'),
 Example(key=Key('Example', '2~C~D'), field1=u'D', field2=u'C', userid=u'2'),
 Example(key=Key('Example', '3~A~B'), field1=u'B', field2=u'A', userid=u'3'),
 Example(key=Key('Example', '3~X~Y'), field1=u'Y', field2=u'X', userid=u'3'),
 Example(key=Key('Example', '4~C~D'), field1=u'D', field2=u'C', userid=u'4'),
 Example(key=Key('Example', '4~E~F'), field1=u'F', field2=u'E', userid=u'4'),
 Example(key=Key('Example', '5~A~B'), field1=u'B', field2=u'A', userid=u'5'),
 Example(key=Key('Example', '5~X~Y'), field1=u'Y', field2=u'X', userid=u'5')
]

Предвид горните данни искам да намеря следното: - Намерете всички потребителски идентификатори, които имат изпълнени и двете от следните условия:

field1='B', field2='A'
and field1='D', field2='C'

В горния пример следните потребителски идентификатори ще отговарят на този критерий:

userid='1' 
userid='2'

Така че въпросът, който имам, е, възможно ли е да намерим горния резултат с помощта на една ndb заявка? Ако да как?

Методът, който знам в момента за това, може да бъде постигнат само с OR ndb заявка, където намираме всички записи, съответстващи

 Example.query(ndb.OR(ndb.AND(field1='B' AND field2='a'), ndb.AND(field1='D' AND field2='C')))

След това итерирайте резултатите (в python) и след това имайте логика за извличане само на онези потребителски идентификатори, които имат field1='B', field2='A' и field1='D', field2='C'

Това не изглежда ефикасен начин поради следната причина: - Ненужно извличаме повече от необходимите записи с комбинацията ИЛИ. - Ако ограничим резултатите с fetch_page, няма начин да разберем колко записа ще бъдат филтрирани чрез нашите критерии. Може дори да доведе до празни записи въз основа на нашия лимит.

ИЛИ ако има начин първо да намеря всички потребителски идентификатори с field1='B' и field2='A' и след това директно да направя заявка в този резултат, за да намеря всички потребителски идентификатори с field1='D' и field2='C', което ще също реши проблема. Така че това е запитване върху резултат от заявка.

Оценявам вашите приноси / предложения. Благодаря.


person jar kir ang 1    schedule 01.07.2017    source източник


Отговори (1)


Да, операцията ndb.OR не е много ефективна и може да причини комбинаторна експлозия, вижте дискусията в Комбиниране на операции И и ИЛИ.

Също така имайте предвид, че правите заявки за Example елементи, а не за потребителски идентификатори. Което означава, че не можете наистина да търсите field1='D' and field2='C' в резултатите за заявката field1='B' and field2='A' - резултатът винаги ще бъде празен, защото field1 не може едновременно да бъде 'D' и 'B'.

Така че наистина трябва да направите 2 отделни заявки, да извлечете наборите от потребителски идентификатори във всеки от резултатите и след това да проверите за пресичане на 2 набора.

Може да е възможно да използвате отделни заявки за проекция (експериментално!), за да получите списъка с потребители по-ефективно:

query_1 =  Example.query(ndb.AND(Example.field1='B' AND Example.field2='A'),
                         projection=[Example.userid], distinct=True))
query_2 =  Example.query(ndb.AND(Example.field1='D' AND Example.field2='C'),
                         projection=[Example.userid], distinct=True))

users_1 = set([example.userid for example in query_1.fetch()])
users_2 = set([example.userid for example in query_2.fetch()])

users_list = list(users_1 & users_2)

Забележка: Всъщност не опитах горния код, той се основава само на документацията.

person Dan Cornilescu    schedule 02.07.2017