Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
Esempi di semantica delle transazioni Neptune
I seguenti esempi illustrano diversi casi d'uso per la semantica delle transazioni in Amazon Neptune.
Argomenti
Esempio 1: Inserimento di una proprietà solo se non esiste
Supponi di volerti assicurare che una proprietà sia impostata solo una volta. Ad esempio, supponi che più query stiano tentando di assegnare a una persona un punteggio di credito simultaneamente. Desideri che venga inserita una sola un'istanza della proprietà e che le altre query non vadano a buon fine perché la proprietà è già stata impostata.
# 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 .} }
La fase property()
di Gremlin inserisce una proprietà con la chiave e il valore forniti. La fase coalesce()
esegue il primo argomento nella prima fase e se non va a buon fine, esegue la seconda fase:
Prima di inserire il valore per la proprietà creditScore
per un determinato vertice person1
, una transazione deve cercare di leggere il valore creditScore
possibilmente inesistente per person1
. Questa lettura tentata blocca l'intervallo SP
per S=person1
e P=creditScore
nell'indice SPOG
in cui il valore creditScore
esiste o verrà scritto.
L'uso di questo blocco di intervallo impedisce a qualsiasi transazione simultanea di inserire un valore creditScore
simultaneamente. Quando sono presenti più transazioni parallele, solo una alla volta può aggiornare il valore. Ciò esclude l'anomalia di creazione di più proprietà creditScore
.
Esempio 2: Affermare che il valore di una proprietà è univoco a livello globale
Supponi di voler inserire una persona con un numero di previdenza sociale come una chiave primaria. Desideri che la query di mutazione garantisca che, a livello globale, nessun altro nel database abbia lo stesso numero di previdenza sociale:
# 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 } }
Questo esempio è simile a quello precedente. La differenza principale è che il blocco dell'intervallo viene eseguito sull'indice POGS
anziché sull'indice SPOG
.
La transazione che esegue la query deve leggere il modello, ?person :ssn 123456789
, in cui le posizioni P
e O
sono vincolate. Il blocco dell'intervallo viene eseguito sull'indice POGS
per P=ssn
e O=123456789
.
Se il modello esiste, non viene eseguita alcuna operazione.
In caso contrario, il blocco impedisce a qualsiasi transazione simultanea di inserire anche tale numero di previdenza sociale
Esempio 3: Modifica di una proprietà se un'altra proprietà ha un valore specificato
Supponi che vari eventi in un gioco spostino una persona dal livello 1 al livello 2 e che venga loro assegnata una nuova proprietà level2Score
impostata su zero. Occorre accertarsi che più istanze simultanee di tale transazione non siano in grado di creare più istanze della proprietà score a livello due. Le interrogazioni in Gremlin e potrebbero essere simili alle seguenti. SPARQL
# 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 .}
In Gremlin, quando si specifica Cardinality.single
, la fase property()
aggiunge una nuova proprietà o sostituisce un valore di proprietà esistente con il nuovo valore specificato.
Qualsiasi aggiornamento a un valore di proprietà, ad esempio incrementando level
da 1 a 2, viene implementato come un'eliminazione del record corrente e l'inserimento di un nuovo record con il nuovo valore di proprietà. In questo caso, il record con il numero di livello 1 viene eliminato e un record con il numero di livello 2 viene reinserito.
Affinché la transazione sia in grado di aggiungere level2Score
e aggiornare level
da 1 a 2, è necessario innanzitutto verificare che il valore level
sia attualmente pari a 1. In questo modo, esegue un blocco dell'intervallo sul prefisso SPO
per S=person1
, P=level
e O=1
nell'indice SPOG
. Questo blocco impedisce alle transazioni simultanee di eliminare la tripla versione 1 e, di conseguenza, non possono verificarsi aggiornamenti simultanei in conflitto.
Esempio 4: Sostituzione di una proprietà esistente
Alcuni eventi potrebbero aggiornare il punteggio di credito di una persona a un nuovo valore (qui BBB
). Tuttavia, vuoi essere certo che gli eventi simultanei di tale tipo non possano creare più proprietà del punteggio di credito per una persona.
# 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 .}
Questo caso è simile all'esempio 3, tranne per il fatto che anziché bloccare il prefisso SPO
, Neptune blocca il prefisso SP
solo con S=person1
e P=creditScore
. Questo impedisce alle transazioni simultanee di inserire o eliminare triple con la proprietà creditScore
per il soggetto person1
.
Esempio 5: Evitare proprietà o archi pendenti
L'aggiornamento di un'entità non deve lasciare un elemento pendente, ovvero una proprietà o edge associata a un'entità per cui non è definito un tipo. Questo è solo un problemaSPARQL, perché Gremlin ha dei vincoli incorporati per evitare che gli elementi penzolino.
# SPARQL: tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person } tx2: DELETE { :person1 ?p ?o }
La query INSERT
deve leggere e bloccare il prefisso SPO
con S=person1
, P=rdf:type
e O=Person
nell'indice SPOG
. Il blocco impedisce che la query DELETE
vada a buon fine in parallelo.
Nel conflitto tra la query DELETE
che cerca di eliminare il record :person1 rdf:type :Person
e la query INSERT
che legge il record e crea un blocco dell'intervallo sul suo SPO
nell'indice SPOG
, sono possibili i seguenti risultati:
Se la query
INSERT
esegue il commit prima che la queryDELETE
legga ed elimini tutti i record per:person1
,:person1
viene rimosso completamente dal database, incluso il nuovo record inserito.Se la query
DELETE
esegue il commit prima che la queryINSERT
cerchi di leggere il record:person1 rdf:type :Person
, la lettura osserva la modifica sottoposta a commit. Ovvero, non trova alcun record:person1 rdf:type :Person
e quindi diventa un no-op.Se la
INSERT
query viene letta prima dellaDELETE
query, la:person1 rdf:type :Person
tripla viene bloccata e laDELETE
query viene bloccata fino al completamento della query, come nel INSERT primo caso precedente.Se
DELETE
legge prima della queryINSERT
e la queryINSERT
cerca di leggere e di eseguire un blocco sul prefissoSPO
per il record, viene rilevato un conflitto. Questo perché la tripla è stata contrassegnata per la rimozione eINSERT
non va a buon fine.
In tutte queste possibili sequenze di eventi, non viene creato alcun edge pendente.