最有效的方法来匹配db.Model ListProperty中的特定数量的项目

时间:2009-07-28 23:40:00

标签: google-app-engine django-models scalability gql

参考this different but not unrelated question我将借用示例模型。

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

class Bar(db.Model): pass

如果我有一个特定的Foo实体,并且我想让所有其他foo实体在其栏ListProperty中也包含某个条形键,我会使用以下查询:

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

如果我想找到至少有N个匹配条实体的所有其他模型Foo实体怎么样?使用for循环执行此操作的显而易见的方法将涉及严重的低效率,并且最好实际更改模型本身以使其更容易,但是如何这样做似乎并不明显。

2 个答案:

答案 0 :(得分:2)

您可以重复应用相同的过滤器:

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)

如果您不对查询应用任何不等式或排序顺序,则数据存储区将能够使用内置索引和合并连接策略执行查询,无论您应用多少过滤器。但是,如果您需要不等式或排序顺序,则需要为可能要过滤的每个条形数量设置索引,这会导致索引爆炸(最好避免!)

答案 1 :(得分:1)

给定具有10个bar_entities的foo记录并且查找具有这10个实体中的至少2个的所有foo记录将导致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)次读取。