Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Exemples de sémantique des transactions Neptune
Les exemples suivants illustrent différents cas d'utilisation de la sémantique des transactions dans Amazon Neptune.
Rubriques
Exemple 1 : insertion d'une propriété uniquement si elle n'existe pas
Supposons que vous souhaitiez vous assurer qu'une propriété ne sera définie qu'une seule fois. Par exemple, supposons que plusieurs requêtes tentent simultanément d'attribuer une cote de crédit à une personne. Vous souhaitez n'insérer qu'une seule instance de la propriété et que les autres requêtes échouent, car la propriété a déjà été définie.
# 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 .} }
L'étape Gremlin property()
insère une propriété avec la clé et la valeur données. L'étape coalesce()
exécute le premier argument de la première étape, et si elle échoue, elle exécute la deuxième étape :
Avant d'insérer la valeur de la propriété creditScore
pour un sommet person1
donné, une transaction doit essayer de lire la valeur creditScore
potentiellement inexistante pour person1
. Cette tentative de lecture verrouille la plage SP
pour S=person1
et P=creditScore
dans l'index SPOG
où la valeur creditScore
se trouve ou sera écrite.
Le fait d'effectuer ce verrouillage de plage empêche toute transaction simultanée d'insérer simultanément une valeur creditScore
. Lorsqu'il y a plusieurs transactions parallèles, une seule d'entre elles peut mettre à jour la valeur à un moment donné. Cela exclut l'anomalie consistant en la création de plusieurs propriétés creditScore
.
Exemple 2 : assertion selon laquelle une valeur de propriété est globalement unique
Supposons que vous souhaitiez insérer une personne avec un numéro de sécurité sociale comme clé primaire. Vous souhaitez que votre requête de mutation garantisse que, au niveau global, personne d'autre dans la base de données n'a le même numéro de sécurité 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 } }
Cet exemple est similaire au précédent. La principale différence est que le verrouillage de plage est effectué sur l'index POGS
au lieu de l'index SPOG
.
La transaction qui exécute la requête doit lire le modèle, ?person :ssn 123456789
, dans lequel les positions O
et P
sont liées. Le verrouillage de plage est effectué sur l'index POGS
pour P=ssn
et O=123456789
.
Si le modèle existe, aucune action n'est effectuée.
S'il n'existe pas, le verrouillage empêche toute transaction simultanée d'insérer également ce numéro de sécurité sociale.
Exemple 3 : modification d'une propriété si une autre propriété a une valeur spécifiée
Supposons que divers événements d'un jeu déplacent une personne du niveau 1 au niveau 2 et lui attribue une nouvelle propriété level2Score
définie sur zéro. Vous devez vous assurer que plusieurs instances simultanées de cette transaction ne puissent pas créer plusieurs instances de la propriété de score de niveau 2. Les requêtes dans Gremlin et SPARQL peuvent ressembler à ce qui suit.
# 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 .}
Dans Gremlin, lorsque Cardinality.single
est spécifié, l'étape property()
ajoute une nouvelle propriété ou remplace une valeur de propriété existante par la nouvelle valeur spécifiée.
Toute mise à jour d'une valeur de propriété, telle que le passage de la valeur de level
de 1 à 2, est implémentée sous la forme d'une suppression de l'enregistrement actuel et de l'insertion d'un nouvel enregistrement avec la nouvelle valeur de propriété. Dans ce cas, l'enregistrement avec le numéro de niveau 1 est supprimé et un enregistrement avec le numéro de niveau 2 est réinséré.
Pour que la transaction puisse ajouter level2Score
et mettre à jour la valeur de level
de 1 à 2, elle doit d'abord valider le fait que la valeur de level
est actuellement égale à 1. Pour ce faire, elle effectue un verrouillage de plage sur le préfixe SPO
pour S=person1
, P=level
et O=1
dans l'index SPOG
. Ce verrouillage empêche les transactions simultanées de supprimer le triplet de version 1. Par conséquent, aucune mise à jour simultanée conflictuelle ne peut se produire.
Exemple 4 : remplacement d'une propriété existante
Certains événements peuvent mettre à jour la cote de crédit d'une personne en la remplaçant par une nouvelle valeur (ici, BBB
). Mais vous voulez vous assurer que les événements simultanés de ce type ne puissent pas créer plusieurs propriétés de cote de crédit pour une personne.
# 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 .}
Ce cas est similaire à l'exemple 3, sauf qu'au lieu de verrouiller le préfixe SPO
, Neptune verrouille le préfixe P=creditScore
avec SP
et S=person1
uniquement. Cela empêche les transactions simultanées d'insérer ou de supprimer des triplets avec la propriété creditScore
pour le sujet person1
.
Exemple 5 : éviter les propriétés ou les arêtes sans pendant
La mise à jour d'une entité ne doit pas laisser un élément sans pendant, c'est-à-dire une propriété ou un arc associé à une entité inexistante. Cela ne pose problème que dans le cas de GremlinSPARQL, car Gremlin possède des contraintes intégrées pour empêcher les éléments de pendre.
# SPARQL: tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person } tx2: DELETE { :person1 ?p ?o }
La requête INSERT
doit lire et verrouiller le préfixe SPO
avec S=person1
, P=rdf:type
et O=Person
dans l'index SPOG
. Le verrouillage empêche la requête DELETE
de réussir en parallèle.
Dans la course entre la requête DELETE
qui tente de supprimer l'enregistrement :person1 rdf:type :Person
et la requête INSERT
qui lit l'enregistrement et crée un verrouillage de plage sur son élément SPO
dans l'index SPOG
, les résultats possibles sont les suivants :
Si la requête
INSERT
est validée avant que la requêteDELETE
ne lise et supprime tous les enregistrements pour:person1
,:person1
est entièrement supprimé de la base de données, y compris l'enregistrement nouvellement inséré.Si la requête
DELETE
est validée avant que la requêteINSERT
n'essaie de lire l'enregistrement:person1 rdf:type :Person
, la lecture constate que la modification est validée. Autrement dit, elle ne trouve aucun enregistrement:person1 rdf:type :Person
et devient donc un instruction non-opérationnelle.Si la
INSERT
requête est lue avant laDELETE
requête, le:person1 rdf:type :Person
triple est verrouillé et laDELETE
requête est bloquée jusqu'à ce qu'elle soit validée, comme dans le premier cas précédent. INSERTSi la requête
DELETE
est lue avant la requêteINSERT
et que la requêteINSERT
tente de lire et de verrouiller le préfixeSPO
de l'enregistrement, un conflit est détecté. Cela est dû au fait que le triplet a été marqué pour suppression et que la requêteINSERT
a ensuite échoué.
Dans toutes ces différentes séquences d'événements possibles, aucun arc sans pendant n'est créé.