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 Python 2 verwenden

Betrachten Sie das folgende Modell:

class Article(ndb.Model):
    title = ndb.StringProperty()
    author = ndb.StringProperty()
    tags = ndb.StringProperty(repeated=True)

Sie geben eine Projektion auf folgende Weise an:

def print_author_tags():
    query = Article.query()
    articles = query.fetch(20, projection=[Article.author, Article.tags])
    for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

Sie verarbeiten die Ergebnisse dieser Abfragen genauso wie bei einer Standardentitätsabfrage, z. B., durch Iteration über die Ergebnisse.

for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

Sie können indexierte Unter-Attribute von einem strukturierten Attribut projizieren. Sie können eine Projektion wie die folgende verwenden, um nur das Attribut city des strukturierten Attributs address eines Kontakts zu erhalten:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
Contact.query().fetch(projection=["name", "addresses.city"])
Contact.query().fetch(projection=[Contact.name, Contact.addresses.city])

Gruppierung(experimentell)

Projektionsabfragen können mit dem Suchbegriff distinct dafür sorgen, dass wirklich nur ein einziges Mal vorkommende Ergebnisse zurückgegeben werden. Dadurch wird nur das erste Ergebnis für Entitäten zurückgegeben, die dieselben Werte für die projizierten Attribute haben.

Article.query(projection=[Article.author], group_by=[Article.author])
Article.query(projection=[Article.author], distinct=True)

Beide Abfragen sind gleichwertig und generieren den Namen jedes Autors nur einmal.

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 (=) 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
    

    (projiziertes Attribut in Gleichheitsfilter verwendet) ist nicht gültig.

  • Von einer Projektionsabfrage zurückgegebene Ergebnisse können nicht wieder in Datastore gespeichert werden.

    Da die Abfrage Ergebnisse zurückgibt, die nur teilweise ausgefüllt sind, können diese Ergebnisse nicht wieder 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 index.yaml, 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.