Наиболее эффективный способ сопоставить определенное количество элементов в базе данных.Model ListProperty

StackOverflow https://stackoverflow.com/questions/1197330

Вопрос

В отношении это другой, но не несвязанный вопрос Я позаимствую примеры моделей.

class Foo(db.Model): bars = db.ListProperty(db.Key)

class Bar(db.Model): pass

Если у меня есть определенная сущность Foo, и я хочу получить все другие сущности foo, также содержащие определенный ключ bar в своем свойстве bars ListProperty , я бы использовал следующий запрос:

related_foos = Foo.all().filter('bars', bar_entity).fetch(fetch_count) 

Что делать, если я хочу найти все другие объекты модельного типа Foo, которые имеют по крайней мере N количество совпадающих объектов bar?Очевидный способ сделать это с помощью цикла for повлек бы за собой резкую неэффективность, и, возможно, было бы лучше на самом деле изменить саму модель, чтобы упростить это, но не кажется очевидным, как это сделать.

Это было полезно?

Решение

Учитывая запись 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)

Если вы не применяете к запросу никаких неравенств или порядков сортировки, хранилище данных сможет выполнять запросы, используя встроенные индексы и стратегию объединения слиянием, независимо от того, сколько фильтров вы примените.Однако, если вам нужно неравенство или порядок сортировки, вам нужно будет иметь индекс для каждого количества столбцов, по которым вы, возможно, захотите отфильтровать, что приводит к резкому увеличению индексов (и этого лучше избегать!).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top