Beispiele für die Neptune-Transaktionssemantik - Amazon Neptune

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Beispiele für die Neptune-Transaktionssemantik

Die folgenden Beispiele zeigen verschiedene Anwendungsfälle für die Transaktionssemantik in Amazon Neptune.

Beispiel 1 – Einfügen einer Eigenschaft nur in dem Fall, dass sie nicht vorhanden ist

Angenommen, Sie möchten sicherstellen, dass eine Eigenschaft nur einmal angegeben wird. Nehmen Sie beispielsweise an, mehrere Abfragen versuchen, einer Person gleichzeitig eine Kreditbewertung zuzuweisen. Sie möchten nur eine Instance der Eigenschaft einfügen und die anderen Abfragen fehlschlagen lassen, da die Eigenschaft bereits festgelegt wurde.

# GREMLIN: g.V('person1').hasLabel('Person').coalesce(has('creditScore'), property('creditScore', 'AAA+')) # SPARQL: INSERT { :person1 :creditScore "AAA+" .} WHERE { :person1 rdf:type :Person . FILTER NOT EXISTS { :person1 :creditScore ?o .} }

Der Gremlin property()-Schritt fügt eine Eigenschaft mit dem angegebenen Schlüssel und Wert ein. Der coalesce()-Schritt führt das erste Argument im ersten Schritt aus, und wenn dies fehlschlägt, wird der zweite Schritt ausgeführt:

Bevor der Wert für die creditScore-Eigenschaft für einen bestimmten person1-Eckpunkt eingefügt wird, muss eine Transaktion versuchen, den möglicherweise nicht vorhandenen creditScore-Wert für person1 zu lesen. Dieser versuchte Lesevorgang sperrt den SP- Bereich für S=person1 und P=creditScore im SPOG-Index, in dem der creditScore-Wert entweder vorhanden ist oder geschrieben werden wird.

Durch diese Bereichssperre wird verhindert, dass gleichzeitige Transaktionen gleichzeitig einen creditScore- Wert einfügen. Wenn es mehrere parallele Transaktionen gibt, kann höchstens eine von ihnen den Wert zu einem bestimmten Zeitpunkt aktualisieren. Dies schließt die Anomalie der Erstellung mehr als einer creditScore-Eigenschaft aus.

Beispiel 2 – Feststellung, dass ein Eigenschaftswert global eindeutig ist

Angenommen, Sie möchten eine Person mit einer Sozialversicherungsnummer als Primärschlüssel einfügen. Sie möchten, dass Ihre Mutationsabfrage sicherstellt, dass auf globaler Ebene niemand sonst in der Datenbank dieselbe Sozialversicherungsnummer hat:

# GREMLIN: g.V().has('ssn', 123456789).fold() .coalesce(__.unfold(), __.addV('Person').property('name', 'John Doe').property('ssn', 123456789')) # SPARQL: INSERT { :person1 rdf:type :Person . :person1 :name "John Doe" . :person1 :ssn 123456789 .} WHERE { FILTER NOT EXISTS { ?person :ssn 123456789 } }

Dieses Beispiel ähnelt dem vorherigen. Der Hauptunterschied besteht darin, dass die Bereichssperre für den POGS-Index und nicht für den SPOG-Index gesetzt wird.

Die Transaktion, die die Abfrage ausführt, muss das Muster, ?person :ssn 123456789, lesen, in dem die Positionen P und O gebunden sind. Die Bereichssperre wird für den POGS-Index für P=ssn und O=123456789 gesetzt.

  • Wenn das Muster vorhanden ist, wird keine Aktion ausgeführt.

  • Wenn es nicht vorhanden ist, verhindert die Sperre, dass gleichzeitige Transaktionen auch diese Sozialversicherungsnummer einfügen.

Beispiel 3 – Ändern einer Eigenschaft, wenn eine andere Eigenschaft einen bestimmten Wert hat

Nehmen wir an, dass verschiedene Ereignisse in einem Spiel eine Person von Level 1 auf Level 2 verschieben und ihr eine neue level2Score-Eigenschaft zuweisen, die auf Null gesetzt ist. Sie müssen sicherstellen, dass nicht mehrere gleichzeitige Instances einer solchen Transaktion mehrere Instances der Score-Eigenschaft von Level 2 erstellen können. Die Abfragen in Gremlin und SPARQL können wie folgt aussehen.

# GREMLIN: g.V('person1').hasLabel('Person').has('level', 1) .property('level2Score', 0) .property(Cardinality.single, 'level', 2) # SPARQL: DELETE { :person1 :level 1 .} INSERT { :person1 :level2Score 0 . :person1 :level 2 .} WHERE { :person1 rdf:type :Person . :person1 :level 1 .}

Wenn in Gremlin Cardinality.single angegeben ist, fügt der property()- Schritt entweder eine neue Eigenschaft hinzu oder ersetzt einen vorhandenen Eigenschaftswert durch den neuen angegebenen Wert.

Jede Aktualisierung eines Eigenschaftswerts, z. B. das Erhöhen level von 1 auf 2, wird als Löschung des aktuellen Datensatzes und Einfügen eines neuen Datensatzes mit dem neuen Eigenschaftswert implementiert. In diesem Fall wird der Datensatz für Level 1 gelöscht, und ein Datensatz für Level 2 wird neu gesetzt.

Damit die Transaktion level2Score hinzufügen und level von 1 auf 2 aktualisieren kann, muss sie zunächst überprüfen, ob der level-Wert derzeit gleich 1 ist. Dafür wird eine Bereichssperre für das SPO-Präfix für S=person1, P=level, und O=1 im SPOG-Index gesetzt. Diese Sperre verhindert, dass gleichzeitige Transaktionen das Version 1-Tripel löschen. Daher können keine widersprüchlichen gleichzeitigen Aktualisierungen stattfinden.

Beispiel 4 – Ersetzen einer vorhandenen Eigenschaft

Bestimmte Ereignisse können die Kreditbewertungen einer Person auf einen neuen Wert aktualisieren (hier BBB). Sie möchten jedoch sicherstellen, dass gleichzeitige Ereignisse dieses Typs nicht mehrere Kreditbewertungseigenschaften für eine Person erstellen können.

# GREMLIN: g.V('person1').hasLabel('Person') .sideEffect(properties('creditScore').drop()) .property('creditScore', 'BBB') # SPARQL: DELETE { :person1 :creditScore ?o .} INSERT { :person1 :creditScore "BBB" .} WHERE { :person1 rdf:type :Person . :person1 :creditScore ?o .}

Dieser Fall ist Beispiel 3 ähnlich, mit der Ausnahme, dass Neptune nicht das SPO-Präfixe sperrt, sondern das Präfix SP nur bei S=person1 und P=creditScore sperrt. Dadurch wird verhindert, dass gleichzeitige Transaktionen Tripel mit der creditScore-Eigenschaft für das person1-Subjekt einfügen oder löschen.

Beispiel 5 – Vermeiden hängender Eigenschaften oder Kanten

Die Aktualisierung einer Entität sollte kein hängendes Element zurücklassen, d. h. eine Eigenschaft oder Grenze, die einer nicht typisierten Entität zugeordnet ist. Dies ist nur ein Problem in SPARQL, da Gremlin über integrierte Einschränkungen verfügt, die hängende Elemente verhindern.

# SPARQL: tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person } tx2: DELETE { :person1 ?p ?o }

Die INSERT-Abfrage muss das SPO-Präfix mit S=person1, P=rdf:type und O=Person im SPOG-Index lesen und sperren. Diese Sperre verhindert, dass die DELETE-Abfrage parallel erfolgreich ist.

Beim „Rennen“ zwischen dem Versuch der DELETE- Abfrage, den :person1 rdf:type :Person-Datensatz zu löschen, und dem der INSERT-Abfrage, den Datensatz zu lesen und eine Bereichssperre für ihren SPO im SPOG-Index zu setzen, sind die folgenden Ergebnisse möglich:

  • Wenn die INSERT-Abfrage ein Commit durchführt, bevor die DELETE-Abfrage alle Datensätze für :person1 liest und löscht, wird :person1 vollständig aus der Datenbank entfernt, einschließlich des neu eingefügten Datensatzes.

  • Wenn die DELETE-Abfrage ein Commit durchführt, bevor die INSERT-Abfrage versucht, den :person1 rdf:type :Person-Datensatz zu lesen, beachtet der Lesevorgang die festgeschriebene Änderung. Das heißt, er findet keinen :person1 rdf:type :Person-Datensatz und wird daher nicht aktiv („No-op“).

  • Wenn die INSERT-Abfrage liest, bevor die DELETE-Abfrage dies tut, wird das :person1 rdf:type :Person-Tripel gesperrt, und die DELETE- Abfrage wird blockiert, bis die INSERT-Abfrage ein Commit durchführt, wie im ersten Fall zuvor.

  • Wenn DELETE vor der INSERT-Abfrage liest und die INSERT-Abfrage versucht, zu lesen und eine Sperre auf das SPO-Präfix für den Datensatz zu setzen, wird ein Konflikt erkannt. Der Grund hierfür ist, dass das Tripel zum Entfernen markiert wurde und der INSERT dann fehlschlägt.

Alle diese verschiedenen möglichen Ereignissequenzen führen nicht zum Erstellen hängender Grenzen.