Query Datastore

Una query Datastore recupera entità . da Cloud Datastore che soddisfano un insieme specificato di condizioni.

Una query tipica include quanto segue:

  • Un tipo di entità a cui si applica la query
  • Filtri facoltativi in base al set di dati delle entità, valori delle proprietà, chiavi e predecessori
  • Ordini facoltativi per sequenziare i risultati
di Gemini Advanced. Quando viene eseguita, una query recupera tutte le entità del tipo specificato che soddisfano tutti i filtri specificati, ordinati nell'ordine specificato. Le query vengono eseguite in sola lettura.

Questa pagina descrive la struttura e i tipi di query utilizzati in App Engine per per recuperare i dati da Cloud Datastore.

Filtri

I filtri di una query impostano vincoli su proprietà, chiavi e antenati delle entità da recuperare.

Filtri proprietà

Un filtro proprietà specifica

  • Il nome di una proprietà
  • Un operatore di confronto
  • Valore di una proprietà
di Gemini Advanced. Ad esempio:

Filter propertyFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);
Query q = new Query("Person").setFilter(propertyFilter);

Il valore della proprietà deve essere fornito dall'applicazione. a cui non può fare riferimento calcolato in termini di altre proprietà. Un'entità soddisfa il filtro se ha una proprietà del nome specificato il cui valore è confrontato con quello specificato il filtro nel modo descritto dall'operatore di confronto.

L'operatore di confronto può essere uno dei seguenti (definito come costanti enumerate nella classe nidificata) Query.FilterOperator):

Operatore Significato
EQUAL Uguale a
LESS_THAN Minore di
LESS_THAN_OR_EQUAL Minore o uguale a
GREATER_THAN Maggiore di
GREATER_THAN_OR_EQUAL Maggiore o uguale a
NOT_EQUAL Diverso da
IN Membro di (uguale a uno qualsiasi dei valori in un elenco specificato)

La NOT_EQUAL esegue due query: una in cui tutti gli altri filtri vengono senza modifiche NOT_EQUAL viene sostituito da un LESS_THAN e uno in cui è sostituito da un GREATER_THAN filtro. I risultati vengono quindi uniti, in ordine. Una query può avere al massimo NOT_EQUAL e una query con uno non può avere altri filtri di disuguaglianza.

L'operatore IN esegue anche query: una per ogni elemento nell'elenco specificato, con tutti gli altri filtri non modificato e il filtro IN è stato sostituito con EQUAL filtro. I risultati vengono uniti in base agli elementi nell'elenco. Se una query ha più di un filtro IN, viene eseguito più query, una per ogni possibile combinazione di valori IN elenchi.

Una singola query contenente NOT_EQUAL o IN è limitato a un massimo di 30 sottoquery.

Per ulteriori informazioni NOT_EQUAL e IN vengono tradotte in più query in un framework JDO/JPA; consulta l'articolo . Query con filtri != e IN.

Filtri principali

Per filtrare in base al valore della chiave di un'entità, utilizza la proprietà speciale Entity.KEY_RESERVED_PROPERTY:

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query("Person").setFilter(keyFilter);

È supportato anche l'ordinamento crescente in Entity.KEY_RESERVED_PROPERTY.

Quando confronti la disuguaglianza, le chiavi vengono ordinate in base ai seguenti criteri, in ordine:

  1. Percorso predecessore
  2. Tipo di entità
  3. Identificatore (nome chiave o ID numerico)

Gli elementi del percorso predecessore vengono confrontati in modo simile: per tipo (stringa), quindi per nome della chiave o ID numerico. Tipi e nomi di chiavi sono stringhe e sono ordinati per valore byte; Gli ID numerici sono numeri interi e sono ordinati numericamente. Se le entità con lo stesso padre e tipo, usano una combinazione di stringhe di nomi chiave e ID numerici, quelli con ID numerici precedono quelli con i nomi delle chiavi.

Le query sulle chiavi utilizzano gli indici esattamente come le query sulle proprietà e richiedono indici personalizzati negli stessi casi, con un paio di eccezioni: i filtri o un ordinamento crescente sulla chiave non richiedono un indice personalizzato, un ordinamento decrescente sulla chiave. Come per tutte le query, il server web di sviluppo crea voci appropriate nel file di configurazione dell'indice quando viene testata una query che richiede un indice personalizzato.

Filtri predecessori

Puoi filtrare le query Datastore in base a un predecessore specificato, in modo che i risultati restituiti includano solo le entità discendenti da tale predecessore:

Query q = new Query("Person").setAncestor(ancestorKey);

Tipi di query speciali

Alcuni tipi specifici di query meritano una menzione speciale:

Query gentili

Una query senza filtro di tipo e senza predecessore recupera tutte le entità di un'applicazione da Datastore. Sono incluse le entità create e gestite da altre funzionalità di App Engine, come entità statistiche ed entità metadati Blobstore (se presenti). Queste query senza tipo non possono includere filtri o ordinamento in base ai valori delle proprietà. Tuttavia, possono filtrare in base alle chiavi entità specificando Entity.KEY_RESERVED_PROPERTY come nome della proprietà:

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query().setFilter(keyFilter);

Query predecessore

Una query con un filtro predecessore limita i risultati all'entità specificata e ai suoi discendenti:

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity tom = new Entity("Person", "Tom");
Key tomKey = tom.getKey();
datastore.put(tom);

Entity weddingPhoto = new Entity("Photo", tomKey);
weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg");

Entity babyPhoto = new Entity("Photo", tomKey);
babyPhoto.setProperty("imageURL", "http://domain.com/some/path/to/baby_photo.jpg");

Entity dancePhoto = new Entity("Photo", tomKey);
dancePhoto.setProperty("imageURL", "http://domain.com/some/path/to/dance_photo.jpg");

Entity campingPhoto = new Entity("Photo");
campingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/camping_photo.jpg");

List<Entity> photoList = Arrays.asList(weddingPhoto, babyPhoto, dancePhoto, campingPhoto);
datastore.put(photoList);

Query photoQuery = new Query("Photo").setAncestor(tomKey);

// This returns weddingPhoto, babyPhoto, and dancePhoto,
// but not campingPhoto, because tom is not an ancestor
List<Entity> results =
    datastore.prepare(photoQuery).asList(FetchOptions.Builder.withDefaults());

Query predecessori Kindless

Una query senza tipo che include un filtro predecessore recupererà predecessore e tutti i suoi discendenti, indipendentemente dal tipo. Questo tipo di query non richiedono indici personalizzati. Come per tutte le query senza tipo, non può includere filtri oppure ordinare in base ai valori delle proprietà, ma puoi applicare filtri in base alla chiave dell'entità:

Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey);
Query q = new Query().setAncestor(ancestorKey).setFilter(keyFilter);

L'esempio seguente illustra come recuperare tutte le entità discendenti da un dato predecessore:

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity tom = new Entity("Person", "Tom");
Key tomKey = tom.getKey();
datastore.put(tom);

Entity weddingPhoto = new Entity("Photo", tomKey);
weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg");

Entity weddingVideo = new Entity("Video", tomKey);
weddingVideo.setProperty("videoURL", "http://domain.com/some/path/to/wedding_video.avi");

List<Entity> mediaList = Arrays.asList(weddingPhoto, weddingVideo);
datastore.put(mediaList);

// By default, ancestor queries include the specified ancestor itself.
// The following filter excludes the ancestor from the query results.
Filter keyFilter =
    new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, tomKey);

Query mediaQuery = new Query().setAncestor(tomKey).setFilter(keyFilter);

// Returns both weddingPhoto and weddingVideo,
// even though they are of different entity kinds
List<Entity> results =
    datastore.prepare(mediaQuery).asList(FetchOptions.Builder.withDefaults());

Query basate solo su chiavi

Una query solo chiavi restituisce solo le chiavi delle entità dei risultati anziché sulle entità stesse, con latenza e costi inferiori rispetto al recupero intere entità:

Query q = new Query("Person").setKeysOnly();

Spesso è più economico eseguire prima una query basata solo su chiavi e poi recuperare un sottoinsieme di entità dai risultati, anziché eseguire una query generica che potrebbe recuperare più entità di quelle di cui hanno davvero bisogno.

Query di proiezione

A volte tutto ciò di cui hai davvero bisogno dai risultati di una query sono i valori di un alcune proprietà specifiche. In questi casi, puoi utilizzare una query di proiezione per recuperare solo le proprietà che ti interessano davvero, con una latenza inferiore e costi aggiuntivi rispetto al recupero dell'intera entità; consulta la pagina Query di proiezione per maggiori dettagli.

Ordina

Un ordinamento di query specifica

  • Il nome di una proprietà
  • Una direzione di ordinamento (crescente o decrescente)

Ad esempio:

// Order alphabetically by last name:
Query q1 = new Query("Person").addSort("lastName", SortDirection.ASCENDING);

// Order by height, tallest to shortest:
Query q2 = new Query("Person").addSort("height", SortDirection.DESCENDING);

Se una query include più ordinamenti, questi vengono applicati nella sequenza specificato. Nell'esempio seguente viene ordinato prima in base al cognome in ordine crescente e poi per altezza decrescente:

Query q =
    new Query("Person")
        .addSort("lastName", SortDirection.ASCENDING)
        .addSort("height", SortDirection.DESCENDING);

Se non viene specificato alcun ordinamento, i risultati vengono restituiti nell'ordine in cui recuperate da Datastore.

Nota: per via del modo Datastore esegue le query, se una query specifica filtri di disuguaglianza su una proprietà e ordina le altre, la proprietà utilizzata nella I filtri di disuguaglianze devono essere ordinati prima delle altre proprietà.

Indici

Ogni query Datastore calcola i risultati utilizzando uno o più indici contenenti chiavi di entità in una sequenza specificata dalle proprietà dell'indice e, facoltativamente, i predecessori dell'entità. Gli indici vengono aggiornati in modo incrementale per riflettere qualsiasi modifica apportata dall'applicazione alle sue entità, in modo che i risultati corretti di tutte le query siano disponibili senza ulteriori calcoli necessaria.

App Engine predefinisce un indice semplice su ogni proprietà di un'entità. Un'applicazione App Engine può definire ulteriori indici personalizzati in un indice di configurazione del deployment denominato datastore-indexes.xml, generato nella directory /war/WEB-INF/appengine-generated dell'applicazione di Google. Il server di sviluppo esegue automaticamente aggiunge suggerimenti a questo file quando rileva query che non possono essere eseguite con gli indici esistenti. Puoi ottimizzare manualmente gli indici modificando il file prima di caricare l'applicazione.

Esempio di interfaccia di query

L'API Java Datastore di basso livello fornisce la classe Query per la costruzione di query e l'interfaccia PreparedQuery per il recupero di entità da Datastore:

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Filter heightMinFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);

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

// Use CompositeFilter to combine multiple filters
CompositeFilter heightRangeFilter =
    CompositeFilterOperator.and(heightMinFilter, heightMaxFilter);

// Use class Query to assemble a query
Query q = new Query("Person").setFilter(heightRangeFilter);

// Use PreparedQuery interface to retrieve results
PreparedQuery pq = datastore.prepare(q);

for (Entity result : pq.asIterable()) {
  String firstName = (String) result.getProperty("firstName");
  String lastName = (String) result.getProperty("lastName");
  Long height = (Long) result.getProperty("height");

  out.println(firstName + " " + lastName + ", " + height + " inches tall");
}

Nota l'utilizzo di FilterPredicate e CompositeFilter per creare i filtri. Se imposti un solo filtro per una query, puoi utilizzare FilterPredicate da solo:

Filter heightMinFilter =
    new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight);

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

Tuttavia, se vuoi impostare più di un filtro per una query, devi utilizzare CompositeFilter, che richiede almeno due filtri. Nell'esempio precedente viene utilizzato l'helper per la scorciatoia CompositeFilterOperator.and. l'esempio seguente mostra un modo per creare un filtro OR composto:

Filter tooShortFilter = new FilterPredicate("height", FilterOperator.LESS_THAN, minHeight);

Filter tooTallFilter = new FilterPredicate("height", FilterOperator.GREATER_THAN, maxHeight);

Filter heightOutOfRangeFilter = CompositeFilterOperator.or(tooShortFilter, tooTallFilter);

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

Passaggi successivi