Exemples de sémantique des transactions Neptune - Amazon Neptune

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.

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ête DELETE 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ête INSERT 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 la DELETE requête, le :person1 rdf:type :Person triple est verrouillé et la DELETE requête est bloquée jusqu'à ce qu'elle soit validée, comme dans le premier cas précédent. INSERT

  • Si la requête DELETE est lue avant la requête INSERT et que la requête INSERT tente de lire et de verrouiller le préfixe SPO 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ête INSERT a ensuite échoué.

Dans toutes ces différentes séquences d'événements possibles, aucun arc sans pendant n'est créé.