O App Engine predefine um índice simples em cada propriedade de uma entidade.
Uma aplicação do App Engine pode definir mais índices personalizados num
ficheiro de configuração de índices denominado
index.yaml
. O servidor de programação adiciona automaticamente sugestões a este ficheiro à medida que encontra consultas que não podem ser executadas com os índices existentes.
Pode ajustar os índices manualmente editando o ficheiro antes de carregar a aplicação.
Nota: o mecanismo de consulta baseado em índice suporta uma vasta gama de consultas e é adequado para a maioria das aplicações. No entanto, não suporta alguns tipos de consultas comuns noutras tecnologias de bases de dados. Em particular, as junções e as consultas agregadas não são suportadas no motor de consultas do Datastore. Consulte a página Consultas do Datastore para ver as limitações das consultas do Datastore.
Definição e estrutura do índice
É definido um índice numa lista de propriedades de um determinado tipo de entidade, com uma ordem correspondente (ascendente ou descendente) para cada propriedade. Para utilização com consultas de antepassados, o índice também pode incluir opcionalmente os antepassados de uma entidade.
Uma tabela de índice contém uma coluna para cada propriedade com nome na definição do índice. Cada linha da tabela representa uma entidade no Datastore que é um resultado potencial para consultas baseadas no índice. Uma entidade só é incluída no índice se tiver um valor indexado definido para cada propriedade usada no índice. Se a definição do índice se referir a uma propriedade para a qual a entidade não tem valor, essa entidade não aparece no índice e, por isso, nunca é devolvida como resultado de qualquer consulta baseada no índice.
As linhas de uma tabela de índice são ordenadas primeiro pelo antepassado e, em seguida, pelos valores das propriedades, na ordem especificada na definição do índice. O índice perfeito para uma consulta, que permite que a consulta seja executada da forma mais eficiente, é definido nas seguintes propriedades, por ordem:
- Propriedades usadas em filtros de igualdade
- Propriedade usada num filtro de desigualdade (do qual não pode haver mais do que um)
- Propriedades usadas em ordens de ordenação
Isto garante que todos os resultados de todas as execuções possíveis da consulta aparecem em linhas consecutivas da tabela. O Datastore executa uma consulta usando um índice perfeito através dos seguintes passos:
- Identifica o índice correspondente ao tipo, às propriedades de filtro, aos operadores de filtro e às ordens de ordenação da consulta.
- Faz a análise a partir do início do índice até à primeira entidade que cumpre todas as condições de filtro da consulta.
- Continua a analisar o índice, devolvendo cada entidade por sua vez, até que
- Encontra uma entidade que não cumpre as condições do filtro ou
- Chega ao fim do índice ou
- Recolheu o número máximo de resultados pedidos pela consulta.
Por exemplo, considere a seguinte consulta:
O índice perfeito para esta consulta é uma tabela de chaves para entidades do tipo
Person
, com colunas para os valores das propriedades
LastName
e
Height
. O índice é ordenado primeiro por ordem ascendente por LastName
e, em seguida, por ordem descendente por Height
.
Para gerar estes índices, configure os seus índices da seguinte forma:
indexes:
- kind: Person
properties:
- name: LastName
direction: asc
- name: Height
direction: desc
Duas consultas do mesmo formulário, mas com valores de filtro diferentes, usam o mesmo índice. Por exemplo, a seguinte consulta usa o mesmo índice que o acima:
As duas consultas seguintes também usam o mesmo índice, apesar das suas formas diferentes:
e
Configuração do índice
Por predefinição, o Datastore predefine automaticamente um índice para cada propriedade de cada tipo de entidade. Estes índices predefinidos são suficientes para executar muitas consultas simples, como consultas apenas de igualdade e consultas simples de desigualdade. Para todas as outras consultas, a aplicação tem de definir os índices de que precisa num ficheiro de configuração de índice denominado index.yaml
. Se a aplicação tentar executar uma consulta que não pode ser executada com os índices disponíveis (predefinidos ou especificados no ficheiro de configuração do índice), a consulta falha.
O Datastore cria índices automáticos para consultas dos seguintes formulários:
- Consultas sem tipo que usam apenas filtros de antepassados e chaves
- Consultas que usam apenas filtros de igualdade e antecessores
- Consultas que usam apenas filtros de desigualdade (que estão limitados a uma única propriedade)
- Consultas que usam apenas filtros de antepassados, filtros de igualdade em propriedades e filtros de desigualdade em chaves
- Consultas sem filtros e apenas uma ordem de ordenação numa propriedade, seja ascendente ou descendente
Outras formas de consulta requerem que os respetivos índices sejam especificados no ficheiro de configuração do índice, incluindo:
- Consultas com filtros de desigualdade e antecessores
- Consultas com um ou mais filtros de desigualdade numa propriedade e um ou mais filtros de igualdade noutras propriedades
- Consultas com uma ordem de ordenação nas chaves por ordem descendente
- Consultas com várias ordens de ordenação
Índices e propriedades
Seguem-se algumas considerações especiais a ter em conta sobre os índices e a respetiva relação com as propriedades das entidades no Datastore:
Propriedades com tipos de valores mistos
Quando duas entidades têm propriedades com o mesmo nome, mas tipos de valores diferentes, um índice da propriedade ordena as entidades primeiro por tipo de valor e, em seguida, por uma ordenação secundária adequada a cada tipo. Por exemplo, se duas entidades tiverem cada uma uma propriedade com o nome age
, uma com um valor inteiro e outra com um valor de string, a entidade com o valor inteiro precede sempre a entidade com o valor de string quando ordenadas pela propriedade age
, independentemente dos valores das propriedades em si.
Isto é especialmente importante no caso de números inteiros e de vírgula flutuante, que são tratados como tipos separados pelo Datastore.
Uma vez que todos os números inteiros são ordenados antes de todos os números de vírgula flutuante, uma propriedade com o valor inteiro 38
é ordenada antes de uma com o valor de vírgula flutuante 37.5
.
Propriedades não indexadas
Se souber que nunca vai ter de filtrar nem ordenar por uma determinada propriedade, pode indicar ao Datastore que não mantenha entradas de índice para essa propriedade declarando-a como não indexada. Isto reduz o custo de execução da sua aplicação, diminuindo o número de gravações do Datastore que tem de realizar. Uma entidade com uma propriedade não indexada comporta-se como se a propriedade não estivesse definida: as consultas com um filtro ou uma ordem de ordenação na propriedade não indexada nunca corresponderão a essa entidade.
Nota:
se uma propriedade aparecer num índice composto por várias propriedades, a definição
da mesma como não indexada impede que seja indexada no índice composto.
Por exemplo, suponhamos que uma entidade tem propriedades a e b e que quer criar um índice capaz de satisfazer consultas como WHERE a ="bike" and b="red"
. Suponhamos também que não se importa com as consultas WHERE a="bike"
e WHERE b="red"
.
Se definir a como não indexado e criar um índice para a e b, o Datastore não cria entradas de índice para o índice a e b e, por isso, a consulta WHERE a="bike" and b="red"
não funciona. Para o Datastore criar entradas para os índices a e b, ambos os índices a e b têm de ser indexados.
Declara uma propriedade não indexada definindo noindex
na etiqueta do campo struct:
No entanto, tenha em atenção que a alteração de uma propriedade de não indexada para indexada não afeta as entidades existentes que possam ter sido criadas antes da alteração. As consultas que filtram a propriedade não devolvem essas entidades existentes, porque as entidades não foram escritas no índice da consulta quando foram criadas. Para tornar as entidades acessíveis por consultas futuras, tem de as reescrever no Datastore para que sejam introduzidas nos índices adequados. Ou seja, tem de fazer o seguinte para cada entidade existente:
- Obter a entidade do Datastore.
- Escreva (coloque) a entidade novamente no Datastore.
Da mesma forma, a alteração de uma propriedade de indexada para não indexada só afeta as entidades escritas posteriormente no Datastore. As entradas de índice para quaisquer entidades existentes com essa propriedade continuam a existir até as entidades serem atualizadas ou eliminadas. Para evitar resultados indesejados, tem de limpar o código de todas as consultas que filtram ou ordenam pela propriedade (agora não indexada).
Limites de índice
O Datastore impõe limites ao número e ao tamanho geral das entradas de índice que podem ser associadas a uma única entidade. Estes limites são elevados e a maioria das aplicações não é afetada. No entanto, existem circunstâncias em que pode atingir os limites.
Conforme descrito acima, o Datastore cria uma entrada num índice predefinido para cada propriedade de cada entidade, exceto para os campos []byte
e os que declarou explicitamente como não indexados. A propriedade também pode ser incluída em índices personalizados adicionais declarados no seu ficheiro de configuração index.yaml
. Desde que uma entidade não tenha propriedades de lista, terá, no máximo, uma entrada em cada índice personalizado (para índices não antepassados) ou uma para cada um dos antepassados da entidade (para índices de antepassados). Cada uma destas entradas de índice tem de ser atualizada
sempre que o valor da propriedade muda.
Para uma propriedade que tem um único valor para cada entidade, cada valor possível tem de ser armazenado apenas uma vez por entidade no índice predefinido da propriedade. Mesmo assim, é possível que uma entidade com um grande número de propriedades de valor único exceda a entrada de índice ou o limite de tamanho. Da mesma forma, uma entidade que pode ter vários valores para a mesma propriedade requer uma entrada de índice separada para cada valor. Mais uma vez, se o número de valores possíveis for elevado, essa entidade pode exceder o limite de entradas.
A situação agrava-se no caso de entidades com várias propriedades, cada uma das quais pode assumir vários valores. Para acomodar essa entidade, o índice tem de incluir uma entrada para cada combinação possível de valores de propriedades. Os índices personalizados que se referem a várias propriedades, cada uma com vários valores, podem "explodir" combinatoriamente, o que requer um grande número de entradas para uma entidade com apenas um número relativamente pequeno de valores de propriedades possíveis. Estes índices em expansão podem aumentar drasticamente o custo de escrever uma entidade no Datastore, devido ao grande número de entradas de índice que têm de ser atualizadas, e também podem fazer com que a entidade exceda facilmente a entrada de índice ou o limite de tamanho.
Considere a consulta
que faz com que o SDK sugira o seguinte índice:
Este índice requer um total de|X|
*
|Y|
*
|Date|
entradas para cada entidade (em que |X|
indica o número de valores associados à entidade para a propriedade X
). Por exemplo, o seguinte código
cria uma entidade com quatro valores para a propriedade x
, três valores para a propriedade y
e date
definida para a data atual. Isto requer 12 entradas de índice, uma para cada combinação possível de valores de propriedades:
(1
, "red"
, <now>
)
(1
, "green"
, <now>
)
(1
, "blue"
, <now>
)
(2
, "red"
, <now>
)
(2
, "green"
, <now>
)
(2
, "blue"
, <now>
)
(3
, "red"
, <now>
)
(3
, "green"
, <now>
)
(3
, "blue"
, <now>
)
(4
, "red"
, <now>
)
(4
, "green"
, <now>
)
(4
, "blue"
, <now>
)
Quando a mesma propriedade é repetida várias vezes, o Datastore pode detetar índices em expansão e sugerir um índice alternativo. No entanto, em todas as outras circunstâncias (como a consulta definida neste exemplo), o Datastore gera um índice em expansão. Neste caso, pode contornar o índice em expansão configurando manualmente um índice no ficheiro de configuração do índice:
Isto reduz o número de entradas necessárias para apenas(|X|
*
|Date|
+
|Y|
*
|Date|)
, ou 7 entradas em vez de 12:
(1
, <now>
)
(2
, <now>
)
(3
, <now>
)
(4
, <now>
)
("red"
, <now>
)
("green"
, <now>
)
("blue"
, <now>
)
Qualquer operação de colocação que faça com que um índice exceda a entrada de índice ou o limite de tamanho falha com um erro. O texto do erro descreve que limite foi excedido ("Too many indexed properties"
ou "Index entries too large"
) e que índice personalizado foi a causa. Se criar um novo índice que exceda os limites de qualquer entidade quando for criado, as consultas ao índice vão falhar e o índice vai aparecer no estado Error
na Google Cloud consola. Para resolver os índices no estado Error
:
Remova o índice no estado
Error
do ficheiroindex.yaml
.Execute o seguinte comando a partir do diretório onde o ficheiro
index.yaml
se encontra para remover esse índice do Datastore:gcloud datastore indexes cleanup index.yaml
Resolva a causa do erro. Por exemplo:
- Reformule a definição do índice e as consultas correspondentes.
- Remova as entidades que estão a causar a explosão do índice.
Adicione o índice novamente ao ficheiro
index.yaml
.Execute o seguinte comando a partir do diretório onde o ficheiro
index.yaml
se encontra para criar o índice no Datastore:gcloud datastore indexes create index.yaml
Pode evitar a explosão de índices evitando consultas que exijam um índice personalizado através de uma propriedade de lista. Conforme descrito acima, isto inclui consultas com várias ordens de ordenação ou consultas com uma combinação de filtros de igualdade e desigualdade.