Limitazioni per le query

Questa pagina illustra le limitazioni relative all'esecuzione di query su Datastore da Google App Engine. Di seguito sono riportate alcune restrizioni comuni che incontrerai durante lo sviluppo per Datastore.

Le entità prive di una proprietà denominata nella query vengono ignorate

Le entità dello stesso tipo non devono avere le stesse proprietà. Per essere idonea come risultato di una query, un'entità deve possedere un valore (possibilmente nullo) per ogni proprietà denominata nei filtri e negli ordini di ordinamento della query. In caso contrario, l'entità viene omessa dagli indici utilizzati per eseguire la query e di conseguenza non sarà inclusa nei risultati della query.

L'applicazione di filtri in base a proprietà non indicizzate non restituisce risultati

Una query non può trovare valori di proprietà che non sono indicizzati, né può ordinarli in base a queste proprietà. Consulta la pagina Indici di Datastore per una discussione dettagliata sulle proprietà non indicizzate.

I filtri di disuguaglianza sono limitati a una sola proprietà

Per evitare di dover analizzare l'intero indice, il meccanismo di query si basa sul fatto che tutti i potenziali risultati di una query siano adiacenti l'uno all'altro nell'indice. Per soddisfare questo vincolo, una singola query non può utilizzare confronti di disuguaglianza (LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, NOT_EQUAL) su più di una proprietà tra tutti i suoi filtri. Ad esempio, la seguente query è valida, perché entrambi i filtri di disuguaglianza si applicano alla stessa proprietà:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter birthYearRangeFilter =
    CompositeFilterOperator.and(birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(birthYearRangeFilter);

Tuttavia, questa query non è valida perché utilizza filtri di disuguaglianza su due proprietà diverse:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter heightMaxFilter =
    new FilterPredicate("height", FilterOperator.LESS_THAN_OR_EQUAL, maxHeight);

Filter invalidFilter = CompositeFilterOperator.and(birthYearMinFilter, heightMaxFilter);

Query q = new Query("Person").setFilter(invalidFilter);

Tieni presente che una query può combinare filtri di uguaglianza (EQUAL) per proprietà diverse, insieme a uno o più filtri di disuguaglianza su una singola proprietà. Di conseguenza, la query è valida:

Filter lastNameFilter = new FilterPredicate("lastName", FilterOperator.EQUAL, targetLastName);

Filter cityFilter = new FilterPredicate("city", FilterOperator.EQUAL, targetCity);

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter validFilter =
    CompositeFilterOperator.and(
        lastNameFilter, cityFilter, birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(validFilter);

L'ordine dei risultati delle query non è definito se non è specificato alcun ordinamento

Quando una query non specifica un ordinamento, i risultati vengono restituiti nell'ordine in cui sono stati recuperati. Con l'evoluzione dell'implementazione di Datastore (o se gli indici di un'applicazione cambiano), questo ordine potrebbe cambiare. Pertanto, se la tua applicazione richiede i risultati della query in un ordine particolare, assicurati di specificare tale ordinamento in modo esplicito nella query.

Gli ordini vengono ignorati nelle proprietà con filtri di uguaglianza

Le query che includono un filtro di uguaglianza per una determinata proprietà ignorano qualsiasi ordinamento specificato per quella proprietà. Questa è una semplice ottimizzazione per evitare l'elaborazione inutile per le proprietà con valore singolo, poiché tutti i risultati hanno lo stesso valore per la proprietà e quindi non è necessario un ulteriore ordinamento. Le proprietà a più valori, tuttavia, possono avere valori aggiuntivi oltre a quello corrispondente dal filtro di uguaglianza. Poiché questo caso d'uso è raro e l'applicazione dell'ordinamento sarebbe costosa e richiederà indici aggiuntivi, lo strumento di pianificazione delle query di Datastore ignora l'ordinamento anche nel caso con più valori. Di conseguenza, i risultati della query potrebbero essere restituiti in un ordine diverso rispetto a quello che sembra suggerire.

Le proprietà utilizzate nei filtri di disuguaglianza devono essere ordinate per prime

Per recuperare tutti i risultati che corrispondono a un filtro di disuguaglianza, una query esegue la scansione dell'indice alla ricerca della prima riga corrispondente al filtro, quindi esegue la scansione in avanti fino a quando non rileva una riga non corrispondente. Affinché le righe consecutive comprendano l'intero set di risultati, devono essere ordinate in base alla proprietà utilizzata nel filtro di disuguaglianza prima di qualsiasi altra proprietà. Pertanto, se una query specifica uno o più filtri di disuguaglianza insieme a uno o più ordini, il primo ordinamento deve fare riferimento alla stessa proprietà indicata nei filtri di disuguaglianza. Quella che segue è una query valida:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("birthYear", SortDirection.ASCENDING)
        .addSort("lastName", SortDirection.ASCENDING);

Questa query non è valida perché non esegue un ordinamento in base alla proprietà utilizzata nel filtro di disuguaglianza:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Missing sort on birthYear.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING);

Allo stesso modo, questa query non è valida perché la proprietà utilizzata nel filtro di disuguaglianza non è la prima ordinata:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Sort on birthYear needs to be first.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING)
        .addSort("birthYear", SortDirection.ASCENDING);

Le proprietà con più valori possono comportarsi in modi sorprendenti

A causa del modo in cui vengono indicizzati, le entità con più valori per la stessa proprietà a volte possono interagire con i filtri delle query e ordinare gli ordini in modi inaspettati e sorprendenti.

Se una query ha più filtri di disuguaglianza su una determinata proprietà, un'entità corrisponderà alla query solo se almeno uno dei suoi singoli valori per la proprietà soddisfa tutti i filtri. Ad esempio, se un'entità di tipo Widget ha valori 1 e 2 per la proprietà x, non corrisponderà alla query:

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.GREATER_THAN, 1),
                new FilterPredicate("x", FilterOperator.LESS_THAN, 2)));

Ciascun valore x dell'entità soddisfa uno dei filtri, ma nessuno dei due valori soddisfa entrambi. Tieni presente che questo non vale per i filtri di uguaglianza. Ad esempio, la stessa entità soddisfa la query

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.EQUAL, 1),
                new FilterPredicate("x", FilterOperator.EQUAL, 2)));

anche se nessuno dei singoli valori x dell'entità soddisfa entrambe le condizioni di filtro.

L'operatore NOT_EQUAL funziona come test "il valore è diverso da". Quindi, ad esempio, la query

Query q = new Query("Widget").setFilter(new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1));

corrisponde a qualsiasi entità Widget con un valore x diverso da 1.

In Java, puoi utilizzare anche query come

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1),
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 2)));

che agisce come

x < 1 OR (x > 1 AND x < 2) OR x > 2

pertanto, un'entità Widget con valori x 1, 2 e 3 corrisponde, ma non un'entità con valori 1 e 2.

Analogamente, l'ordinamento per le proprietà con più valori è insolito. Poiché queste proprietà vengono visualizzate una volta nell'indice per ogni valore univoco, il primo valore visualizzato nell'indice determina l'ordinamento di un'entità:

  • Se i risultati della query sono ordinati in ordine crescente, per l'ordinamento viene utilizzato il valore più piccolo della proprietà.
  • Se i risultati sono ordinati in ordine decrescente, viene utilizzato il valore più alto per l'ordinamento.
  • Gli altri valori non influiscono sull'ordinamento, né sul numero di valori.

Ciò ha l'insolita conseguenza che un'entità con valori di proprietà 1 e 9 preceda una con i valori 4, 5, 6 e 7 sia in ordine crescente che in ordine decrescente.

Le query all'interno delle transazioni devono includere filtri dei predecessori

Le transazioni Datastore operano solo su entità che appartengono allo stesso gruppo di entità (discendenti da un predecessore comune). Per mantenere questa limitazione, tutte le query eseguite all'interno di una transazione devono includere un filtro predecessore che specifichi un predecessore nello stesso gruppo di entità delle altre operazioni nella transazione.