Projektionsabfragen

Die meisten Datastore-Abfragen geben ganze Entitäten als Ergebnisse zurück, häufig benötigt eine Anwendung jedoch nur einige wenige Attribute einer Entität. Mit Projektionsabfragen können Sie Datastore nur auf die Attribute einer Entität abfragen, die Sie wirklich benötigen, und zwar mit einer geringeren Latenz und niedrigeren Kosten als beim Abrufen der ganzen Entität.

Projektionsabfragen ähneln SQL-Abfragen der folgenden Form:

SELECT name, email, phone FROM CUSTOMER

Sie können alle Filter- und Sortierfunktionen, die für Standardentitätsabfragen verfügbar sind, innerhalb der unten beschriebenen Einschränkungen verwenden. Die Abfrage gibt gekürzte Ergebnisse zurück, wobei nur die angegebenen Attribute (im Beispiel name, email und phone) mit Werten gefüllt sind. Alle anderen Attribute enthalten keine Daten.

Projektionsabfragen in Java 8 verwenden

Für eine Projektionsabfrage erstellen Sie ein Query-Objekt und fügen ihm mit der Methode addProjection() Attribute hinzu:

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

Der Typ, den Sie für jedes Attribut angeben, muss mit dem übereinstimmen, den Sie bei der anfänglichen Definition des Attributs mit Entity.setProperty() verwendet haben. Das folgende Beispiel veranschaulicht die Verarbeitung der Abfrageergebnisse, bei der die Liste der zurückgegebenen Entitäten durchlaufen wird und die einzelnen Property-Werte in den erwarteten Typ umgewandelt werden:

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());
  }
}

Gruppierung(experimentell)

Projektionsabfragen können mit der Methode setDistinct() dafür sorgen, dass wirklich nur einmal vorkommende Ergebnisse in einer Ergebnismenge zurückgegeben werden. So wird nur das erste Ergebnis für Entitäten zurückgegeben, die für die projizierten Attribute dieselben Werte haben.

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");

Einschränkungen bei Projektionen

Projektionsabfragen unterliegen folgenden Einschränkungen:

  • Nur indexierte Attribute können projiziert werden.

    Projektion wird für Properties, die nicht explizit oder implizit indexiert sind, nicht unterstützt. Lange Textstrings (Text) und lange Bytestrings (Blob) werden nicht indexiert.

  • Ein Attribut kann nicht mehr als einmal projiziert werden.

  • Attribute, auf die in einem Gleichheitsfilter (EQUAL) oder Zugehörigkeitsfilter (IN) verwiesen wird, können nicht projiziert werden.

    Beispiel:

    SELECT A FROM kind WHERE B = 1
    

    ist gültig (projiziertes Attribut nicht im Gleichheitsfilter verwendet), wie auch

    SELECT A FROM kind WHERE A > 1
    

    (kein Gleichheitsfilter), aber

    SELECT A FROM kind WHERE A = 1
    

    (projizierte Property in Gleichheitsfilter verwendet) ist nicht gültig.

  • Von einer Projektionsabfrage zurückgegebene Ergebnisse sollten nicht wieder in Datastore gespeichert werden.

    Da die Abfrage Ergebnisse zurückgibt, die nur teilweise ausgefüllt sind, sollten sie nicht zurück in Datastore geschrieben werden.

Projektionen und mehrwertige Attribute

Bei der Projektion eines Attributs mit mehreren Werten werden nicht alle Werte dieses Attributs ausgefüllt. Stattdessen wird eine separate Entität für jede nur einmal vorkommende Kombination von projizierten Werten zurückgegeben, die mit der Abfrage übereinstimmen. Angenommen, Sie haben eine Entität vom Typ Foo mit den beiden mehrwertigen Attributen A und B:

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

dann gibt die Projektionsabfrage

SELECT A, B FROM Foo WHERE A < 3

vier Entitäten mit den folgenden Wertekombinationen zurück:

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

Bei einer Entität mit einem mehrwertigen Attribut ohne Werte werden keine Einträge in den Index aufgenommen und keine Ergebnisse für diese Entität von einer Projektionsabfrage mit diesem Attribut zurückgegeben.

Indexe für Projektionen

Bei Projektionsabfragen müssen alle in der Projektion angegebenen Attribute in einem Datastore-Index enthalten sein. Der App Engine-Entwicklungsserver generiert automatisch die benötigten Indexe in der Indexkonfigurationsdatei datastore-indexes-auto.xml, die mit Ihrer Anwendung hochgeladen wird.

Die Anzahl der benötigten Indexe können Sie beispielsweise durch konstantes Projizieren derselben Attribute reduzieren, auch wenn nicht immer alle benötigt werden. Diese Abfragen benötigen beispielsweise zwei getrennte Indexe:

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

Wenn Sie immer die Attribute A, B und C projizieren, auch wenn C nicht benötigt wird, ist nur ein Index erforderlich.

Wenn Sie eine bestehende Abfrage in eine Projektionsabfrage umwandeln, müssen Sie gegebenenfalls einen neuen Index erstellen, wenn die Attribute für die Projektion nicht bereits in einem anderen Teil der Abfrage enthalten sind. Angenommen, Sie haben diese bestehende Abfrage:

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

Sie benötigt diesen Index:

Index(Kind, A, B)

Wenn diese in eine dieser Projektionsabfragen konvertiert wird:

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

wird ein neues Attribut (C) eingeführt. Dies erfordert die Erstellung eines neuen Indexes Index(Kind, A, B, C). Die Projektionsabfrage

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

ändert den erforderlichen Index nicht, da die projizierten Attribute A und B bereits in der vorhandenen Abfrage enthalten sind.