La façon la plus efficace pour correspondre à un certain nombre d'éléments dans un db.Model ListProperty

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

Question

En ce qui concerne cette question différente, mais pas sans rapport je vais emprunter les modèles par exemple.

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

class Bar(db.Model): pass

Si j'ai une certaine entité Foo et je veux obtenir toutes les autres entités foo contenant également un certain bar clé dans ses bars ListProperty, j'utiliser la requête suivante:

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

Qu'en est-il si je veux trouver toutes les autres entités de Foo type de modèle qui ont au moins nombre N d'appariement des entités de bar? La façon évidente de le faire avec une boucle for impliquerait l'inefficacité drastiques, et il pourrait être préférable de changer réellement le modèle lui-même pour rendre cela plus facile, mais il ne semble pas évident de le faire.

Était-ce utile?

La solution

Étant donné un dossier foo qui a 10 bar_entities et la recherche de tous les enregistrements foo qui ont au moins 2 de ces 10 entités entraînerait 45 valeurs possibles égalité 10! / (2! * (10-2)!) = 45.

Ceci peut être déduit dans 10_C_ (2-1) = 10 se lit comme suit.

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.

Pour réduire à une lecture, il faudrait que lorsqu'un enregistrement foo est ajouté que vous remplissez une table séparée qui avait toutes les 2 combinaisons pour un enregistrement donné.

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

De cette façon, vous obtenez l'habitude dans toutes les questions d'index explosant.

Si vous voulez aussi faire des 3 ou 4 les entités que pour chacun d'entre eux, vous devez créer un foo_combo_n_table ou faire un 10_C_ (n-1) nombre de lectures.

Autres conseils

Vous pouvez simplement appliquer le même filtre à plusieurs reprises:

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

Ou, basée sur les données:

q = Foo.all()
for bar in bar_entities:
  q.filter('bars', bar)
related_foos = q.fetch(fetch_count)

Si vous n'appliquez pas d'inégalités ou les ordres de tri à la requête, le magasin de données sera en mesure d'exécuter les requêtes en utilisant le construit dans les index et la fusion stratégie de jointure, quel que soit le nombre de filtres que vous appliquez. Si vous avez besoin d'un ordre d'inégalité ou de tri, cependant, vous aurez besoin d'avoir un index pour chaque nombre de barres que vous pourriez vouloir filtrer, ce qui conduit à des indices d'exploser (et donc il vaut mieux éviter!)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top