Effizienteste Weg, eine bestimmte Anzahl von Elementen in einem db.Model Listproperty Übereinstimmen
-
20-09-2019 - |
Frage
In Bezug auf diese verschiedene, aber nicht unabhängig Frage werde ich leihen, um die Beispielmodelle.
class Foo(db.Model): bars = db.ListProperty(db.Key)
class Bar(db.Model): pass
Wenn ich eine bestimmte Foo Einheit haben und ich möchte alle anderen foo Einheiten erhalten auch eine bestimmte Bar Key in seinen Bars Listproperty enthält, würde ich die folgende Abfrage verwenden:
related_foos = Foo.all().filter('bars', bar_entity).fetch(fetch_count)
Was ist, wenn ich will alle anderen Einheiten des Modells Art Foo finden, die zumindest eine Anzahl von N Anpassungs bar Einheiten haben? Der offensichtliche Weg, dies mit einer for-Schleife zu tun drastische Ineffizienzen beinhalten würde, und es könnte am besten tatsächlich sein, um das Modell zu ändern sich diese leichter zu machen, aber es scheint nicht klar, wie dies zu tun.
Lösung
ein foo Datensatz gegeben, die mit 10 bar_entities hat und auf der Suche für alle foo Datensätze, die mindestens zwei dieser 10 Einheiten haben 10 in 45 mögliche Gleichheit Werte ergeben würde! / (2! * (10-2)!) = 45.
Dies kann in 10_C_ abgeleitet werden (2-1) = 10 liest.
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.
Dieses Lese auf einen reduzieren würde erfordern, dass, wenn ein foo Datensatz hinzugefügt Sie eine separate Tabelle zu füllen, die für einen bestimmten Datensatz alle zwei Kombinationen hatte.
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
Auf diese Weise kann in jede Explosion Index Probleme bekommen würde nicht.
Wenn Sie auch alle 3 oder 4 beliebige Einheiten tun wollte, als für jede dieser Sie eine foo_combo_n_table erstellen müssten oder eine 10_C_ tun (n-1) Anzahl der liest.
Andere Tipps
Sie können einfach die gleichen Filter anwenden wiederholt:
related_foos = Foo.all().filter('bars', bar_entity).filter('bars', bar_entity_2).fetch(fetch_count)
Oder datengetriebener:
q = Foo.all()
for bar in bar_entities:
q.filter('bars', bar)
related_foos = q.fetch(fetch_count)
Wenn Sie gelten keine Ungleichheiten oder Sortierreihenfolgen auf die Abfrage, wird der Datenspeicher der Lage, die Abfragen auszuführen unter Verwendung der in Indizes erstellt und der Merge-Strategie verbinden, unabhängig davon, wie viele Filter, die Sie anwenden. Wenn Sie eine Ungleichheit oder Sortierreihenfolge benötigen, jedoch müssen Sie einen Index für jede Anzahl von Bars haben Sie gefiltert werden könnten wollen, was zu explodierenden Indizes (und so ist am besten vermieden werden!)