Query di proiezione

La maggior parte delle query di Datastore restituisce entità intere come risultati, ma spesso un'applicazione è in realtà interessata solo ad alcune proprietà dell'entità. Le query di proiezione ti consentono di eseguire query su Datastore solo per quelle specifiche proprietà di un'entità di cui hai effettivamente bisogno, con latenza e costi inferiori rispetto al recupero dell'intera entità.

Le query di proiezione sono simili alle query SQL del formato:

SELECT name, email, phone FROM CUSTOMER

Puoi utilizzare tutte le funzionalità di filtro e ordinamento disponibili per le query standard delle entità, fatte salve le limitazioni descritte di seguito. La query restituisce risultati ridotti con solo le proprietà specificate (name, email e phone nell'esempio) compilate con valori. tutte le altre proprietà non hanno dati.

Utilizzo di query di proiezione in Java 8

Per creare una query di proiezione, puoi creare un oggetto Query a cui aggiungere proprietà utilizzando il metodo addProjection():

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

Il tipo specificato per ogni proprietà deve corrispondere a quello utilizzato quando hai definito la proprietà con Entity.setProperty(). L'esempio seguente mostra come elaborare i risultati della query eseguendo l'iterazione dell'elenco di entità restituite e trasmettendo ciascun valore di proprietà al tipo previsto:

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

Raggruppamento (sperimentale)

Per le query di proiezione è possibile utilizzare il metodo setDistinct() per garantire che in un set di risultati vengano restituiti solo risultati completamente univoci. Verrà restituito solo il primo risultato per le entità che hanno gli stessi valori per le proprietà previste.

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

Limitazioni delle proiezioni

Le query di proiezione sono soggette alle seguenti limitazioni:

  • È possibile prevedere solo le proprietà indicizzate.

    La proiezione non è supportata per le proprietà che non sono indicizzate, in modo esplicito o implicito. Le stringhe di testo lunghe (Text) e le stringhe di byte lunghi (Blob) non vengono indicizzate.

  • Non è possibile prevedere la stessa proprietà più di una volta.

  • Non è possibile prevedere le proprietà a cui viene fatto riferimento in un filtro di uguaglianza (EQUAL) o appartenenza (IN).

    Ad esempio,

    SELECT A FROM kind WHERE B = 1
    

    sia valida (proprietà proiettata non utilizzata nel filtro di uguaglianza), così com'è

    SELECT A FROM kind WHERE A > 1
    

    (non un filtro di uguaglianza), ma

    SELECT A FROM kind WHERE A = 1
    

    (proprietà prevista utilizzata nel filtro di uguaglianza) non lo è.

  • I risultati restituiti da una query di proiezione non devono essere salvati in Datastore.

    Poiché la query restituisce risultati compilati solo parzialmente, non devi riscriverli in Datastore.

Proiezioni e proprietà con più valori

La proiezione di una proprietà con più valori non completerà tutti i valori per quella proprietà. Verrà invece restituita un'entità separata per ogni combinazione univoca di valori previsti corrispondenti alla query. Ad esempio, supponiamo che tu abbia un'entità di tipo Foo con due proprietà a più valori, A e B:

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

La query di proiezione

SELECT A, B FROM Foo WHERE A < 3

restituirà quattro entità con le seguenti combinazioni di valori:

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

Tieni presente che se un'entità ha una proprietà a più valori senza valori, nessuna voce verrà incluso nell'indice e non verranno restituiti risultati per l'entità in questione da una query di proiezione che include questa proprietà.

Indici per le proiezioni

Le query di proiezione richiedono che tutte le proprietà specificate nella proiezione siano incluse in un indice Datastore. Il server di sviluppo di App Engine genera automaticamente gli indici necessari nel file di configurazione dell'indice, datastore-indexes-auto.xml, che viene caricato con la tua applicazione.

Un modo per ridurre al minimo il numero di indici richiesti è proiettare le stesse proprietà in modo coerente, anche quando non tutti sono sempre necessari. Ad esempio, queste query richiedono due indici separati:

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

Tuttavia, se progetti sempre le proprietà A, B e C, anche quando C non è obbligatorio, sarà necessario un solo indice.

La conversione di una query esistente in una query di proiezione può richiedere la creazione di un nuovo indice se le proprietà della proiezione non sono già incluse in un'altra parte della query. Ad esempio, supponiamo che tu abbia una query esistente

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

che richiede l'indice

Index(Kind, A, B)

Conversione in una delle query di proiezione in corso...

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

introduce una nuova proprietà (C) e pertanto richiederà la creazione di un nuovo indice Index(Kind, A, B, C). Tieni presente che la query di proiezione

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

non cambierebbe l'indice richiesto, poiché le proprietà proiettate A e B erano già incluse nella query esistente.