App Engine predefinisce un indice semplice per ogni proprietà di un'entità.
Un'applicazione App Engine può definire ulteriori indici personalizzati in un
file di configurazione
dell'indice denominato datastore-indexes.xml
,
che viene generato nella directory /war/WEB-INF/appengine-generated
dell'applicazione.
Il server di sviluppo aggiunge automaticamente suggerimenti a questo file quando rileva query che non possono essere eseguite con gli indici esistenti.
Puoi ottimizzare gli indici manualmente modificando il file prima di caricare l'applicazione.
Nota: il meccanismo di query basato su indici supporta una vasta gamma di query ed è adatto per la maggior parte delle applicazioni. Tuttavia, non supporta alcuni tipi di query comuni in altre tecnologie di database: in particolare, le unioni e le query aggregate non sono supportate nel motore di query di Datastore. Consulta la pagina Query Datastore per informazioni sui limiti delle query Datastore.
Definizione e struttura dell'indice
Un indice è definito in un elenco di proprietà di un determinato tipo di entità, con un ordine corrispondente (crescente o decrescente) per ogni proprietà. Da utilizzare con delle query dei predecessori, l'indice può anche includere i predecessori di un'entità.
Una tabella dell'indice contiene una colonna per ogni proprietà denominata nella definizione di Kubernetes. Ogni riga della tabella rappresenta un'entità in Datastore che è un potenziale risultato per le query basate sul di Google. Un'entità viene inclusa nell'indice solo se ha un valore indicizzato per ogni proprietà utilizzata nell'indice. Se la definizione dell'indice fa riferimento a una proprietà per la quale l'entità non ha un valore, l'entità non verrà visualizzata nell'indice e, di conseguenza, non verrà mai restituita come risultato per qualsiasi query basata sull'indice.
Nota: Datastore distingue tra un'entità che non possiede una proprietà e un'entità che possiede la proprietà con un valore nullo (null
). Se assegni esplicitamente un valore nullo alla proprietà di un'entità, questa può essere inclusa nei risultati di una query che fa riferimento alla proprietà.
Nota: Gli indici composti da più proprietà richiedono che ogni singola proprietà non deve essere impostato su unindexed.
Le righe di una tabella di indice vengono ordinate prima per predecessore e poi per proprietà dei valori, nell'ordine specificato nella definizione dell'indice. L'indice perfetto per una query, che consente di eseguirla in modo più efficiente, è definito sulle seguenti proprietà, in ordine:
- Proprietà utilizzate nei filtri di uguaglianza
- Proprietà utilizzata in un filtro di disuguaglianza (di cui non può essercene più di uno).
- Proprietà utilizzate negli ordini di ordinamento
In questo modo, vengono visualizzati tutti i risultati per ogni possibile esecuzione della query in righe consecutive della tabella. Datastore esegue una query utilizzando un indice perfetto seguendo i seguenti passaggi:
- Identifica l'indice corrispondente al tipo, alle proprietà di filtro e operatori di filtro e ordinare gli ordini.
- Esegue la scansione dall'inizio dell'indice alla prima entità che soddisfa tutti i le condizioni di filtro della query.
- Continua a eseguire la scansione dell'indice, restituendo ogni entità in ordine fino a quando
- rileva un'entità che non soddisfa le condizioni di filtro
- raggiunge la fine dell'indice
- ha raccolto il numero massimo di risultati richiesti dalla query.
Ad esempio, considera la seguente query:
L'indice perfetto per questa query è una tabella di chiavi per entità di tipo
Person
, con colonne per i valori di
lastName
e
height
proprietà. L'indice
viene ordinato per primo in ordine crescente per
lastName
e poi in ordine decrescente per
height
.
Per generare questi indici, configurali nel seguente modo:
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="false">
<datastore-index kind="Person" ancestor="false" source="manual">
<property name="lastName" direction="asc"/>
<property name="height" direction="desc"/>
</datastore-index>
</datastore-indexes>
Due query dello stesso modulo, ma con valori di filtro diversi, utilizzano lo stesso di Google. Ad esempio, la seguente query utilizza lo stesso indice di quella precedente:
Anche le due query seguenti utilizzano lo stesso indice, nonostante i loro moduli:
e
Configurazione degli indici
Per impostazione predefinita, Datastore predefinisce automaticamente un indice per ogni proprietà di ogni tipo di entità. Questi indici predefiniti sono sufficienti per eseguire molte query semplici, ad esempio query solo di uguaglianza e query di semplice disuguaglianza. Per tutte le altre query, l'applicazione deve definire gli indici di cui ha bisogno
in una configurazione di indice
denominato datastore-indexes.xml
. Se l'applicazione tenta di eseguire una query
che non può essere eseguita con gli indici disponibili (predefiniti o
specificati nel file di configurazione dell'indice), la query non andrà a buon fine
con un DatastoreNeedIndexException
.
Datastore crea indici automatici per le query nei seguenti formati:
- Query Kindless che utilizzano solo filtri dei predecessori e delle chiavi
- Query che utilizzano solo filtri dei predecessori e di uguaglianza
- Query che utilizzano solo filtri di disuguaglianza (che sono limitati a un singolo proprietà)
- Query che utilizzano solo filtri dei predecessori, filtri di uguaglianza sulle proprietà e filtri di disuguaglianza nelle chiavi
- Query senza filtri e con un solo ordinamento per proprietà, crescente o decrescente
Altre forme di query richiedono che i rispettivi indici siano specificati nell'indice di configurazione del deployment, tra cui:
- Query con filtri dei predecessori e della disuguaglianza
- Query con uno o più filtri di disuguaglianza su una proprietà e uno o più filtri di uguaglianza su altre proprietà
- Query con un ordinamento delle chiavi in ordine decrescente
- Query con più ordini di ordinamento
Indici e proprietà
Di seguito sono riportate alcune considerazioni speciali da tenere presenti sugli indici e su come riguarda le proprietà delle entità in Datastore:
Proprietà con tipi di valori misti
Quando due entità hanno proprietà con lo stesso nome ma tipi di valori diversi,
dell'indice della proprietà ordina le entità prima per
tipo di valore seguito da un
ordine secondario
appropriati per ogni tipo. Ad esempio, se due entità hanno ciascuna una proprietà age
, una con un valore intero e una con un valore di stringa, l'entità con il valore intero precede sempre quella con il valore di stringa quando vengono ordinate in base alla proprietà age
, indipendentemente dai valori delle proprietà stesse.
Ciò è particolarmente degno di nota nel caso di numeri interi e rappresentazioni in virgola mobile.
numeri, che sono trattati come tipi separati da Datastore.
Poiché tutti i numeri interi vengono ordinati prima di tutti i numeri in virgola mobile, una proprietà con il valore intero 38
viene ordinata prima di una con il valore in virgola mobile 37.5
.
Proprietà non indicizzate
Se sai che non dovrai mai filtrare o ordinare i dati in base a una determinata proprietà, possiamo indicare a Datastore di non mantenere le voci di indice corrispondenti dichiarando la proprietà unindexed. Questo riduce i costi di gestione dell'applicazione diminuendo il numero di scritture di Datastore che deve eseguire. Un'entità con una proprietà non indicizzata si comporta come se la proprietà non erano impostati: le query con un filtro o un ordinamento nella proprietà non indicizzata verranno non corrisponderà mai a quell'entità.
Nota: se una proprietà viene visualizzata in un indice composto da più proprietà e impostandola su Non indicizzato, non verrà indicizzata nell'indice composto.
Ad esempio, supponiamo che un'entità abbia le proprietà a e b e
che tu voglia creare un indice in grado di soddisfare query come
WHERE a ="bike" and b="red"
. Supponiamo inoltre che le query WHERE a="bike"
e WHERE b="red"
non ti interessino.
Se imposti a su Non indicizzato e crei un indice per a e b, il datastore non creerà voci di indice per gli indici a e b e, di conseguenza, la query WHERE a="bike" and b="red"
non funzionerà. Affinché Datastore crei voci per gli indici a e
b, sia a che b devono essere indicizzati.
Nell'API Java Datastore di basso livello, le proprietà sono definite indicizzate o
non indicizzati in base alla singola entità, a seconda del metodo utilizzato per impostarli
(setProperty()
o
setUnindexedProperty()
):
Puoi modificare una proprietà indicizzata in non indicizzata reimpostando il suo valore con
setUnindexedProperty()
o da non indicizzato a indicizzato reimpostandolo con
setProperty()
.
Tieni presente, tuttavia, che la modifica di una proprietà da non indicizzata a indicizzata influire su eventuali entità esistenti create prima della modifica. Le query che filtrano in base alla proprietà non restituiranno queste entità esistenti, perché non sono state scritte nell'indice della query al momento della loro creazione. Per rendere le entità accessibili per query future, devi riscrivere a Datastore in modo che vengano inseriti nel indici di appartenenza. Ciò significa che devi procedere come segue per ciascuna di queste entità esistenti:
- Recupera (get) l'entità da Datastore.
- Scrivere (put) l'entità di nuovo in Datastore.
Analogamente, la modifica di una proprietà da indicizzata a non indicizzata interessa solo le entità successivamente scritte in Datastore. Le voci di indice per eventuali entità esistenti con quella proprietà continueranno a esistere finché le entità non vengono aggiornate o eliminate. Per evitare risultati indesiderati, devi eliminare definitivamente il codice di tutte le query che filtrano o ordinano in base alla proprietà (ora non indicizzata).
Limiti per gli indici
Datastore impone dei limiti al numero e la dimensione complessiva delle voci di indice che possono essere associate a una singola entità. Questi limiti sono elevati e la maggior parte delle applicazioni non ne è interessato. Tuttavia, potresti riscontrare questi limiti.
Come descritto sopra,
Datastore crea una voce in un indice predefinito per ogni
proprietà di ogni entità, tranne per le stringhe di testo lunghe (Text
), le stringhe di byte lunghe
(Blob
) e le entità incorporate
(EmbeddedEntity
)
e quelle che hai dichiarato esplicitamente come non indicizzate. La proprietà
possono anche essere inclusi in altri indici personalizzati dichiarati nel tuo
Configurazione di datastore-indexes.xml
un file YAML. Se un'entità non ha proprietà elenco, avrà al massimo una voce in ciascun indice personalizzato (per gli indici non predecessori) o una per ciascuno dei predecessori dell'entità (per gli indici dei predecessori). Ognuna di queste voci di indice va aggiornata
ogni volta che cambia il valore della proprietà.
Per una proprietà che ha un singolo valore per ogni entità, ogni valore possibile deve essere archiviato una sola volta per entità nell'indice predefinito della proprietà. Tuttavia, è possibile che un'entità con un numero elevato di proprietà con un solo valore superi il limite di dimensioni o di voci dell'indice. Analogamente, un'entità che può avere più valori per la stessa proprietà richiede una voce dell'indice distinta per ogni valore. Anche in questo caso, se il numero di valori possibili è elevato, un'entità di questo tipo può superare il limite di voci.
La situazione peggiora nel caso di entità con più proprietà, ognuno dei quali può assumere più valori. Per supportare un'entità di questo tipo, l'indice deve includere una voce per ogni possibile combinazione di valori delle proprietà. Gli indici personalizzati che fanno riferimento a più proprietà, ciascuna con più valori, possono "esplodere" in modo combinatorio, richiedendo un numero elevato di voci per un'entità con solo un numero relativamente ridotto di possibili valori delle proprietà. Tale l'esplosione degli indici può aumentare notevolmente il costo di scrittura di un'entità in Datastore, a causa dell'elevato numero di voci di indice che devono essere aggiornato e può anche causare facilmente il superamento della voce di indice o dimensioni massime consentite.
Considera la query
che fa sì che l'SDK suggerisca il seguente indice:
Questo indice richiederà un totale di|x|
*
|y|
*
|date|
voci per ogni
entità (dove |x|
indica il numero di valori associati all'entità per
proprietà x
). Ad esempio, il seguente codice
crea un'entità con quattro valori per la proprietà x
, tre valori per la proprietà
y
e date
impostati sulla data corrente. Richiede 12 voci di indice, una
per ogni possibile combinazione di valori delle proprietà:
(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 la stessa proprietà viene ripetuta più volte, Datastore può rilevare gli indici in crescita e suggerire un indice alternativo. Tuttavia, in tutte le altre (come la query definita in questo esempio), Datastore genererà un indice enorme. In questo caso, puoiaggirare l'indice esplosivo configurando manualmente un indice nel file di configurazione dell'indice:
In questo modo si riduce il numero di voci necessarie a solo(|x|
*
|date|
+
|y|
*
|date|)
oppure 7 voci invece di 12:
(1
, <now>
)
(2
, <now>
)
(3
, <now>
)
(4
, <now>
)
("red"
, <now>
)
("green"
, <now>
)
("blue"
, <now>
)
Qualsiasi operazione put che causerebbe il superamento del limite di dimensioni o voci dell'indice non andrà a buon fine con un messaggio IllegalArgumentException
. Il testo dell'eccezione descrive quale limite è stato superato ("Too many indexed properties"
o "Index entries too large"
) e quale indice personalizzato ne è la causa. Se crei un nuovo indice superando
limiti per qualsiasi entità quando viene creata, le query sull'indice avranno esito negativo
l'indice verrà visualizzato nello stato Error
nella console Google Cloud. A
risolvere gli indici nello stato Error
:
Rimuovi l'indice nello stato
Error
dal filedatastore-indexes.xml
.Esegui questo comando dalla directory in cui si trova
datastore-indexes.xml
per rimuovere quell'indice da Datastore:gcloud datastore indexes cleanup datastore-indexes.xml
Risolvi la causa dell'errore. Ad esempio:
- Riformula la definizione dell'indice e le query corrispondenti.
- Rimuovi le entità che causano l'esplosione dell'indice.
Aggiungi di nuovo l'indice al file
datastore-indexes.xml
.Esegui il seguente comando dalla directory in cui si trova
datastore-indexes.xml
per creare l'indice in Datastore:gcloud datastore indexes create datastore-indexes.xml
Per evitare l'esplosione degli indici, evita le query che richiederebbero una configurazione utilizzare una proprietà list. Come descritto sopra, sono incluse le query con più ordini di ordinamento o con una combinazione di filtri di uguaglianza e disuguaglianza.