Наиболее эффективный способ сопоставить определенное количество элементов в db.Model ListProperty
В связи с этим другим, но не связанным с этим вопросом, я заимствую примеры моделей.
class Foo(db.Model): bars = db.ListProperty(db.Key)
class Bar(db.Model): pass
Если у меня есть определенная сущность Foo, и я хочу получить все другие сущности foo, которые также содержат определенный ключ Key в его барах ListProperty, я бы использовал следующий запрос:
related_foos = Foo.all().filter('bars', bar_entity).fetch(fetch_count)
Как насчет того, чтобы найти все другие объекты модели типа Foo, которые имеют по крайней мере N подходящих столбцов? Очевидный способ сделать это с помощью цикла for связан с серьезной неэффективностью, и, возможно, было бы лучше на самом деле изменить саму модель, чтобы сделать это проще, но не кажется очевидным, как это сделать.
2 ответа
Учитывая запись foo, которая имеет 10 bar_entities и поиск всех записей foo, которые имеют как минимум 2 из этих 10 сущностей, приведет к 45 возможным значениям равенства 10!/(2!*(10-2)!)=45.
Это может быть выведено в 10_C_(2-1)=10 чтений.
SELECT * from table WHERE bar="1" AND bar in ["2", "3", "4", "5", "6", "7", "8", "9", "0"]
SELECT * from table WHERE bar="2" AND bar in ["3", "4", "5", "6", "7", "8", "9", "0"]
SELECT * from table WHERE bar="3" AND bar in ["4", "5", "6", "7", "8", "9", "0"]
etc.
Чтобы сократить это до одного чтения, потребуется, чтобы при добавлении записи foo вы заполняли отдельную таблицу, в которой были все 2 комбинации для данной записи.
Say you had
foo_table
foo1 [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
foo2 [1, 3, 4]
foo3 [1, 2, a]
foo4 [b, 6, c]
foo_combo_2_table
Parent Combination
foo1 12
foo1 13
... and all 45 foo1 combinations each in its own row
foo2 13
foo2 14
foo2 34
foo3 12
foo3 1a
foo3 2a
etc.
Now you can do a
indexes = SELECT __KEY__ from foo_combo_2_table WHERE combination IN [12, 13, 14, 15, ... all 45]
keys = [k.parent() for k in indexes] # you would need to filter for duplicates
Таким образом, вы не будете сталкиваться с какими-либо проблемами с индексами.
Если вы также хотите сделать какие-либо 3 или 4 сущности, чем для каждой из них, вам нужно создать foo_combo_n_table или сделать 10_C_ (n-1) чтений.
Вы можете просто применить один и тот же фильтр несколько раз:
related_foos = Foo.all().filter('bars', bar_entity).filter('bars', bar_entity_2).fetch(fetch_count)
Или, управляемый данными:
q = Foo.all()
for bar in bar_entities:
q.filter('bars', bar)
related_foos = q.fetch(fetch_count)
Если вы не примените к запросу неравенства или порядки сортировки, хранилище данных сможет выполнять запросы, используя встроенные индексы и стратегию объединения слиянием, независимо от того, сколько фильтров вы применили. Однако если вам нужно неравенство или порядок сортировки, вам потребуется индекс для каждого числа баров, по которым вы можете фильтровать данные, что приводит к взрыву индексов (и поэтому лучше избегать!)