Python DB-Clientbibliothek für Cloud Datastore

Hinweis: Entwicklern von neuen Anwendungen wird dringend empfohlen, die NDB-Clientbibliothek zu verwenden. Sie bietet im Vergleich zur vorliegenden Clientbibliothek mehrere Vorteile, beispielsweise das automatische Caching von Entitäten über die Memcache API. Wenn Sie derzeit die ältere DB-Clientbibliothek verwenden, lesen Sie die Anleitung zur Migration von DB zu NDB.

In diesem Artikel wird das Datenmodell für in Cloud Datastore gespeicherte Objekte beschrieben. Außerdem erfahren Sie, wie Sie Abfragen mithilfe der API strukturieren und Transaktionen verarbeiten.

Entitäten

Objekte in Cloud Datastore werden als Entitäten bezeichnet. Eine Entität verfügt über eine oder mehrere benannte Properties, von denen jede einen oder mehrere Werte haben kann. Die Property-Werte unterstützen eine Vielzahl von Datentypen, darunter Ganzzahlen, Gleitkommazahlen, Strings, Datumsangaben und Binärdaten. Mit einer Abfrage für eine Property mit mehreren Werten wird getestet, ob einer der Werte die Abfragekriterien erfüllt. Diese Attribute eignen sich daher zum Testen von Mitgliedschaften.

Typen, Schlüssel und Kennungen

Jede Cloud Datastore-Entität ist von einer bestimmten Art. Mit dieser kann die Entität für Abfragen kategorisiert werden. In einer Personalanwendung kann beispielsweise jeder Mitarbeiter eines Unternehmens mit einer Entität der Art Employee dargestellt werden. Darüber hinaus wird jede Entität durch einen eigenen Schlüssel eindeutig identifiziert. Der Schlüssel besteht aus den folgenden Komponenten:

  • Dem Typ der Entität
  • Einer Kennung, die Folgendes sein kann:
    • ein Schlüsselnamen-String
    • eine ganzzahlige ID
  • Einem optionalen Ancestor-Pfad zur Entität innerhalb der Cloud Datastore-Hierarchie

Die Kennung wird beim Erstellen der Entität zugewiesen. Weil die Kennung Teil des Schlüssels der Entität ist, wird sie permanent mit der Entität verknüpft und kann nicht geändert werden. Es gibt zwei Möglichkeiten für die Zuweisung:

  • Die Anwendung kann ihren eigenen Schlüsselnamen-String für die Entität angeben.
  • Cloud Datastore kann der Entität automatisch eine ganzzahlige numerische ID zuweisen.

Ancestor-Pfade

Entitäten in Cloud Datastore sind hierarchisch organisiert, ähnlich der Verzeichnisstruktur eines Dateisystems. Wenn Sie eine Entität erstellen, können Sie optional eine weitere Entität als übergeordnetes Element angeben. Die neue Entität ist dann ein untergeordnetes Element der übergeordneten Entität. Im Gegensatz zu einem Dateisystem muss die übergeordnete Entität nicht tatsächlich vorhanden sein. Eine Entität ohne übergeordnetes Element wird als Stammentität bezeichnet. Die Verknüpfung zwischen einer Entität und ihrer übergeordneten Entität ist dauerhaft und kann nicht geändert werden, nachdem die Entität erstellt wurde. Cloud Datastore weist zwei Entitäten mit derselben übergeordneten Entität oder zwei Stammentitäten (Entitäten ohne übergeordnete Entität) niemals dieselbe numerische ID zu.

Alle übergeordneten Elemente einer Entität werden als ihre Ancestors bezeichnet und alle untergeordneten Entitäten sind ihre Nachfolger. Eine Stammentität und alle ihre Nachfolger gehören zu derselben Entitätengruppe. Die Abfolge der Entitäten, von einer Stammentität über die untergeordneten Elemente bis zu einer bestimmten Entität, bildet den Ancestor-Pfad. Der vollständige Schlüssel, der die Entität identifiziert, besteht aus einer Abfolge von Art/Kennungs-Paaren, die den Ancestor-Pfad angeben und mit dem Paar der Entität selbst enden:

[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]

Bei einer Stammentität ist der Ancestor-Pfad leer und der Schlüssel besteht ausschließlich aus der eigenen Art und der eigenen Kennung der Entität:

[Person:GreatGrandpa]

Dieses Konzept wird anhand des folgenden Diagramms veranschaulicht:

Darstellung der Beziehung der Stammentität zu den untergeordneten Entitäten in der Entitätengruppe

Abfragen und Indexe

Neben dem direkten Abrufen von Entitäten aus Cloud Datastore über die entsprechenden Schlüssel kann eine Anwendung die Entitäten auch über eine Abfrage nach den Werten ihrer Attribute abrufen. Diese Abfrage wird für Entitäten einer bestimmten Art ausgeführt. Sie kann Filter für die Attributwerte, Schlüssel und Ancestors der Entitäten enthalten und null oder mehr Entitäten als Ergebnisse zurückgeben. Außerdem lassen sich mit einer Abfrage Sortierfolgen festlegen, die die Ergebnisse nach den Attributwerten sortieren. Die Ergebnisse umfassen alle Entitäten mit mindestens einem Wert (ggf. auch null) für jedes Attribut, das in den Filtern und Sortierfolgen angegeben wird, und deren Attributwerte alle angegebenen Filterkriterien erfüllen. Die Abfrage kann ganze Entitäten, projizierte Entitäten oder einfach Schlüssel von Entitäten zurückgeben.

Eine typische Abfrage umfasst

  • Eine Entitätsart, auf die die Abfrage angewendet wird
  • Null oder mehr Filter, die auf Attributwerten, Schlüsseln und Ancestors der Entitäten basieren
  • Null oder mehr Sortierfolgen zum Anordnen der Ergebnisse
Bei der Ausführung ruft die Abfrage alle Entitäten des angegebenen Typs ab, die alle in der angegebenen Reihenfolge sortierten Filter erfüllen. Abfragen werden schreibgeschützt ausgeführt.

Hinweis: Um Arbeitsspeicher zu sparen und die Leistung zu verbessern, sollte eine Abfrage, wenn möglich, einen Grenzwert für die Anzahl von zurückgegebenen Ergebnissen angeben.

Eine Abfrage kann auch einen Ancestor-Filter enthalten, der die Ergebnisse auf die Entitätengruppe beschränkt, die aus Nachfolgern eines angegebenen Ancestors besteht. Eine solche Abfrage wird als Ancestor-Abfrage bezeichnet. Standardmäßig liefern Ancestor-Abfragen Ergebnisse mit strikter Konsistenz, die verlässlich die neuesten Änderungen an den Daten widerspiegeln. Nicht-Ancestor-Abfragen können sich im Gegensatz dazu auf den gesamten Cloud Datastore und nicht nur auf eine einzelne Entitätengruppe beziehen. Sie sind jedoch nur letztendlich konsistent und können veraltete Ergebnisse liefern. Wenn Strong Consistency für Ihre Anwendung wichtig ist, sollten Sie dies beim Strukturieren der Daten gegebenenfalls berücksichtigen und verwandte Entitäten in derselben Entitätengruppe platzieren. Sie können dadurch mit einer Ancestor-Abfrage anstatt einer Nicht-Ancestor-Abfrage abgerufen werden. Weitere Informationen finden Sie unter Daten für Strong Consistency strukturieren.

App Engine gibt für jedes Attribut einer Entität einen einfachen Index vor. Eine App Engine-Anwendung kann weitere, benutzerdefinierte Indexe in einer Indexkonfigurationsdatei namens index.yaml festlegen. Der Entwicklungsserver fügt dieser Datei automatisch Vorschläge hinzu, wenn er Abfragen ermittelt, die mit den vorhandenen Indexen nicht ausgeführt werden können. Sie können die Indexe vor dem Hochladen der Anwendung von Hand optimieren.

Eine ausführliche Erläuterung von Indexen und Abfragen finden Sie unter Indexauswahl und erweiterte Suche.

Hinweis: Der indexbasierte Abfragemechanismus unterstützt ein breites Spektrum an Abfragen und ist für die meisten Anwendungen geeignet. Allerdings werden einige in anderen Datenbanktechnologien übliche Abfragetypen nicht von dem Cloud Datastore-Abfragemodul unterstützt, insbesondere Join- und Aggregate-Abfragen. Weitere Informationen zu Einschränkungen bei Cloud Datastore-Abfragen finden Sie auf der Seite Datastore-Abfragen.

Transaktionen

Jeder Versuch, eine Entität zu erstellen, zu aktualisieren oder zu löschen, findet im Kontext einer Transaktion statt. Eine einzelne Transaktion kann eine beliebige Anzahl solcher Vorgänge umfassen. Zur Wahrung der Datenkonsistenz sorgt die Transaktion dafür, dass alle enthaltenen Vorgänge auf Cloud Datastore als Einheit angewendet werden oder keiner der Vorgänge angewendet wird, falls einer der Vorgänge fehlschlägt.

Sie können innerhalb einer einzelnen Transaktion mehrere Aktionen für eine Entität ausführen. Wenn Sie beispielsweise den Wert eines Zählerfelds in einem Objekt erhöhen möchten, lesen Sie den Wert des Zählers ab, berechnen den neuen Wert und speichern diesen. Ohne eine Transaktion kann es passieren, dass ein anderer Prozess den Zähler zwischen dem Zeitpunkt, zu dem Sie den Wert ablesen, und dem Zeitpunkt, zu dem Sie ihn aktualisieren, erhöht. Der aktualisierte Wert wird in diesem Fall von Ihrer Anwendung überschrieben. Wenn das Lesen, Berechnen und Schreiben in einer einzigen Transaktion erfolgt, kann die Inkrementierung von keinem anderen Prozess gestört werden.

Transaktionen und Entitätengruppen

Innerhalb einer Transaktion sind nur Ancestor-Abfragen zulässig. Jede Transaktionsabfrage muss somit auf eine einzelne Entitätengruppe beschränkt sein. Die Transaktion selbst lässt sich auf mehrere Entitäten anwenden. Diese können entweder zu einer einzelnen Entitätengruppe oder, bei einer gruppenübergreifenden Transaktion, zu maximal 25 verschiedenen Entitätengruppen gehören.

Cloud Datastore verwendet zur Verwaltung von Transaktionen Optimistic Concurrency. Wenn durch zwei oder mehr Transaktionen gleichzeitig versucht wird, eine Entitätengruppe zu ändern (indem vorhandene Entitäten aktualisiert oder neue Entitäten erstellt werden), ist nur die erste mit Commit gespeicherte Transaktion erfolgreich. Bei allen anderen schlägt der Commit fehl. Diese anderen Transaktionen können dann mit den aktualisierten Daten wiederholt werden. Beachten Sie, dass dadurch die Anzahl gleichzeitiger Schreibvorgänge begrenzt wird, die Sie für eine Entität in einer bestimmten Entitätengruppe ausführen können.

Gruppenübergreifende Transaktionen

Eine Transaktion für Entitäten, die zu verschiedenen Entitätengruppen gehören, wird als gruppenübergreifende (XG-)Transaktion bezeichnet. Die Transaktion kann auf maximal 25 Entitätengruppen angewendet werden und ist erfolgreich, solange sich keine weitere gleichzeitige Transaktion auf eine der relevanten Entitätengruppen bezieht. So erhalten Sie mehr Flexibilität bei der Organisation Ihrer Daten: Sie sind nicht gezwungen, verschiedenartige Daten unter demselben Ancestor zu gruppieren, nur um atomare Schreibvorgänge für sie durchzuführen.

In XG-Transaktionen ist es ebenso wenig wie in Einzelgruppentransaktionen möglich, Nicht-Ancestor-Abfragen auszuführen. Sie können jedoch Ancestor-Abfragen für separate Entitätengruppen durchführen. Bei nicht-transaktionalen Abfragen (Nicht-Ancestor-Abfragen) können alle, einige oder gar keine Ergebnisse einer zuvor mit Commit durchgeführten Transaktion angezeigt werden. Weitere Informationen zu diesem Thema finden Sie unter Cloud Datastore-Schreibvorgänge und Datentransparenz. Bei solchen nicht-transaktionalen Abfragen ist es jedoch wahrscheinlicher, dass die Ergebnisse einer teilweise mit Commit ausgeführten XG-Transaktion angezeigt werden, als die einer teilweise mit Commit ausgeführten Einzelgruppentransaktion.

Die Leistung und Kosten einer XG-Transaktion, die nur eine einzige Entitätengruppe betrifft, sind genauso hoch wie bei einer Nicht-XG-Einzelgruppentransaktion. Bei einer XG-Transaktion, die mehrere Entitätengruppen betrifft, sind die Betriebskosten genauso hoch wie bei einer Nicht-XG-Transaktion, die Latenz kann jedoch höher sein.

Cloud Datastore-Schreibvorgänge und Datentransparenz

Daten werden in zwei Phasen in Cloud Datastore geschrieben:

  1. In der Commit-Phase werden die Entitätsdaten in den Transaktions-Logs einer Mehrzahl von Replikaten erfasst. Alle Replikate, in denen sie nicht erfasst wurden, werden markiert, damit erkennbar ist, dass ihre Logs nicht aktuell sind.
  2. Die Apply-Phase findet in jedem Replikat unabhängig statt und besteht aus zwei parallel ausgeführten Aktionen:
    • Die Entitätsdaten werden in dieses Replikat geschrieben.
    • Die Indexzeilen für die Entität werden in dieses Replikat geschrieben. Hinweis: Dies kann länger dauern als das Schreiben der Daten selbst.

Der Schreibvorgang wird unmittelbar nach der Commit-Phase wieder aufgenommen. Die Apply-Phase findet dann asynchron statt, möglicherweise zu verschiedenen Zeiten in jedem Replikat und möglicherweise mit Verzögerungen von ein paar hundert Millisekunden oder mehr nach Abschluss der Commit-Phase. Tritt während der Commit-Phase ein Fehler auf, werden automatische Wiederholungen durchgeführt. Wenn Fehler jedoch weiterhin auftreten, gibt Cloud Datastore eine Fehlermeldung aus, dass für Ihre Anwendung eine Ausnahme auftritt. Wenn die Commit-Phase erfolgreich ist, die Apply-Phase jedoch bei einem bestimmten Replikat fehlschlägt, wird in diesem Replikat ein Rollforward für den Apply-Vorgang bis zum Abschluss ausgeführt, wenn eine der beiden folgenden Situationen eintritt:

  • Periodische Cloud Datastore-Sweeps prüfen auf nicht abgeschlossene Commit-Jobs und wenden sie an.
  • Bestimmte Vorgänge (get, put, delete und Ancestor-Abfragen), die die betroffene Entitätengruppe nutzen, bewirken, dass mit Commit bestätigte aber noch nicht angewendete Änderungen in dem Replikat, in dem sie ausgeführt werden, abgeschlossen werden. Erst dann wird mit dem nächsten Vorgang fortgefahren.

Dieses Schreibverhalten kann verschiedene Auswirkungen darauf haben, wie und wann Daten für Ihre Anwendung bei verschiedenen Teilen der Commit- und Apply-Phasen sichtbar sind:

  • Wenn ein Schreibvorgang einen Zeitüberschreitungsfehler meldet, kann (ohne zu versuchen, die Daten zu lesen) nicht ermittelt werden, ob der Vorgang erfolgreich war oder fehlgeschlagen ist.
  • Da Cloud Datastore ausstehende Änderungen abruft und Ancestor-Abfragen die Änderungen auf das Replikat anwenden, auf dem sie ausgeführt werden, erhalten diese Vorgänge immer eine konsistente Übersicht aller vorherigen erfolgreichen Transaktionen. Das bedeutet, dass bei einem get-Vorgang (Suchen einer aktualisierten Entität anhand ihres Schlüssels) garantiert die neueste Version dieser Entität angezeigt wird.
  • Nicht-Ancestor-Abfragen können veraltete Ergebnisse liefern, da sie möglicherweise auf einem Replikat ausgeführt werden, auf dem die neuesten Transaktionen noch nicht angewendet wurden. Das kann auch beim Ausführen eines Vorgangs auftreten, bei dem ausstehende Transaktionen garantiert angewendet werden, da die Abfrage möglicherweise auf einem anderen Replikat als der vorherige Vorgang ausgeführt wird.
  • Das Timing von gleichzeitigen Änderungen kann sich auf die Ergebnisse von Nicht-Ancestor-Abfragen auswirken. Wenn eine Entität anfangs eine Abfrage erfüllt, dies aber aufgrund einer Änderung später nicht mehr der Fall ist, kann die Entität dennoch in den Ergebnissen der Abfrage enthalten sein, wenn die Änderungen noch nicht auf die Indexe des Replikats angewendet wurden, auf dem die Abfrage ausgeführt wurde.

Cloud Datastore-Statistik

Cloud Datastore erfasst Statistiken der für eine Anwendung gespeicherten Daten, wie die Anzahl der Entitäten pro Dateityp oder wie viel Speicherplatz für Property-Werte eines bestimmten Typs verwendet wird. Sie können diese Statistiken in der GCP Console auf der Seite Cloud Datastore-Dashboard aufrufen. Sie können mit der Cloud Datastore API auch programmgesteuert innerhalb der Anwendung auf diese Werte zugreifen, indem Sie Abfragen nach bestimmten Entitäten ausführen. Weitere Informationen finden Sie unter Datastore-Statistiken in Python 2.

Datastore-Beispiel für Python 2

In der Python API wird anhand eines Modells ein Entitätenart einschließlich der Typen und Konfiguration der zugehörigen Attribute beschrieben. Eine Anwendung definiert ein Modell mithilfe einer Python-Klasse. Zum Beschreiben der Properties werden Klassenattribute verwendet. Der Entitätstyp erhält den Namen der Klasse. Entitäten des angegebenen Typs werden durch Instanzen der Modellklasse dargestellt, wobei Instanzattribute die Property-Werte darstellen. Wenn Sie eine neue Entität erstellen möchten, konstruieren Sie ein Objekt der gewünschten Klasse, legen dessen Attribute fest und speichern das Objekt, beispielsweise durch Aufrufen der Methode put():

import datetime
from google.appengine.ext import db
from google.appengine.api import users

class Employee(db.Model):
  name = db.StringProperty(required=True)
  role = db.StringProperty(required=True,
                           choices=set(["executive", "manager", "producer"]))
  hire_date = db.DateProperty()
  new_hire_training_completed = db.BooleanProperty(indexed=False)
  email = db.StringProperty()

e = Employee(name="John",
             role="manager",
             email=users.get_current_user().email())
e.hire_date = datetime.datetime.now().date()
e.put()

Die Cloud Datastore API bietet zwei Schnittstellen für Abfragen: eine Abfrageobjektschnittstelle und die SQL-ähnliche Abfragesprache GQL. Eine Abfrage gibt Entitäten in Form von Instanzen der Modellklassen zurück:

training_registration_list = ["Alfred.Smith@example.com",
                              "jharrison@example.com",
                              "budnelson@example.com"]
employees_trained = db.GqlQuery("SELECT * FROM Employee WHERE email IN :1",
                                training_registration_list)
for e in employees_trained:
  e.new_hire_training_completed = True
  db.put(e)
Hat Ihnen diese Seite weitergeholfen? Teilen Sie uns Ihr Feedback mit:

Feedback geben zu...

App Engine-Standardumgebung für Python 2