Pergunta

Em referência a Esta pergunta diferente, mas não não relacionada Vou emprestar os modelos de exemplo.

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

class Bar(db.Model): pass

Se eu tiver uma certa entidade Foo e quero obter todas as outras entidades Foo também contendo uma certa chave de barra em suas barras ListProperty, eu usaria a seguinte consulta:

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

E se eu quiser encontrar todas as outras entidades do tipo modelo Foo que têm pelo menos n número de entidades de barra correspondentes? A maneira óbvia de fazer isso com um loop for envolveu ineficiências drásticas, e pode ser melhor mudar o próprio modelo para facilitar isso, mas não parece óbvio como fazê-lo.

Foi útil?

Solução

Dado um registro Foo que possui 10 bar_entities e procurar todos os registros Foo que possuem pelo menos 2 dessas 10 entidades resultariam em 45 possíveis valores de igualdade 10!/(2!*(10-2)!) = 45.

Isso pode ser deduzido em 10_C_ (2-1) = 10 leituras.

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.

Para reduzir isso a uma leitura, exigiria que, quando um registro Foo for adicionado, você preencha uma tabela separada que tinha todas as duas combinações para um determinado registro.

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

Dessa forma, você não entrará em nenhum problema de índice explosivo.

Se você também quis fazer 3 ou 4 entidades, para cada uma delas, precisaria criar um foo_combo_n_table ou fazer um número 10_C_ (n-1) de leituras.

Outras dicas

Você pode simplesmente aplicar o mesmo filtro repetidamente:

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

Ou, orientado a dados:

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

Se você não aplicar desigualdades ou pedidos de classificação na consulta, o DataStore poderá executar as consultas usando os índices embutidos e a estratégia de junção de mesclagem, independentemente de quantos filtros você aplicar. Se você precisar de uma desigualdade ou ordem de classificação, no entanto, precisará ter um índice para cada número de barras em que você pode querer filtrar, o que leva a índices explodindo (e, portanto, é melhor evitado!)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top