Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Ejemplos de semántica de transacciones de Neptune
Los siguientes ejemplos muestran diferentes casos de uso de semántica de transacciones en Amazon Neptune.
Temas
Ejemplo 1: inserción de una propiedad solo si no existe
Supongamos que desea asegurarse de que una propiedad se establezca solo una vez. Por ejemplo, suponga que varias consultas intentan asignar a una persona una puntuación de crédito de forma simultánea. Solo desea que se inserte una instancia de la propiedad y que las demás consultas devuelvan un error, ya que la propiedad ya se ha establecido.
# 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 .} }
El el paso property()
de Gremlin, se inserta una propiedad con la clave y el valor determinados. En el paso coalesce()
, se ejecuta el primer argumento del primer paso y, si se produce un error, se ejecuta el segundo paso:
Antes de insertar el valor de la propiedad creditScore
para un vértice person1
determinado, una transacción debe intentar leer el posible valor creditScore
inexistente de person1
. Este intento de lectura bloquea el rango SP
de S=person1
y P=creditScore
en el índiceSPOG
, donde el valor creditScore
existe o se va a sobrescribir.
Si se utiliza este bloqueo de rango, se impide que cualquier transacción simultánea inserte un valor creditScore
de forma simultánea. Cuando hay varias transacciones en paralelo, como máximo una de ellas puede actualizar el valor a la vez. Esto descarta la anomalía de más de una propiedad creditScore
que se crea.
Ejemplo 2: afirmación de que el valor de una propiedad es único de forma global
Supongamos que desea insertar una persona con un número de la Seguridad Social como clave principal. Desea que su consulta de mutación garantice que, a nivel global, nadie más de la base de datos tenga el mismo número de Seguridad Social:
# 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 } }
Este ejemplo es similar al anterior. La principal diferencia es que el bloqueo de rango se realiza en el índice POGS
en lugar de en el índice SPOG
.
La transacción que ejecuta la consulta debe leer el patrón, ?person :ssn 123456789
, en el que están vinculadas las posiciones P
y O
. El bloqueo de rango se realiza en el índice POGS
para P=ssn
y O=123456789
.
Si el patrón existe, no se realiza ninguna acción.
Si no existe, el bloqueo impide que cualquier transacción simultánea inserte también ese número de Seguridad Social.
Ejemplo 3: cambio de una propiedad si otra propiedad tiene un valor específico
Supongamos que varios eventos de un juego mueven a una persona del nivel uno al nivel dos y les asignan una nueva propiedad level2Score
establecida en cero. Debe asegurarse de que varias instancias simultáneas de dicha transacción no puedan crear varias instancias de la propiedad de puntuación de nivel dos. Las consultas están en Gremlin y SPARQL podrían tener el siguiente aspecto.
# 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 .}
En Gremlin, cuando se especifica Cardinality.single
, el paso property()
añade una nueva propiedad o sustituye un valor de propiedad existente por el nuevo valor que se especifica.
Cualquier actualización de un valor de propiedad, como aumentar level
de 1 a 2, se implementa como una eliminación del registro actual y la inserción de un nuevo registro con el nuevo valor de propiedad. En este caso, se elimina el registro con el número de nivel 1 y se vuelve a insertar un registro con el número de nivel 2.
Para que la transacción pueda añadir level2Score
y actualizar level
de 1 a 2, primero debe validar que el valor level
sea actualmente igual a 1. Al hacerlo, toma un bloqueo de rango en el prefijo SPO
de S=person1
, P=level
y O=1
en el índice SPOG
. Este bloqueo impide que las transacciones simultáneas eliminen el triple de la versión 1 y, como resultado, no se pueden producir actualizaciones simultáneas en conflicto.
Ejemplo 4: sustitución de una propiedad existente
Algunos eventos pueden actualizar la puntuación de crédito de una persona a un nuevo valor (aquí BBB
). Sin embargo, desea asegurarse de que los eventos simultáneos de ese tipo no puedan crear varias propiedades de puntuación de crédito para 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 .}
Este caso es similar al ejemplo 3, salvo que en lugar de bloquear el prefijo SPO
, Neptune bloquea el prefijo SP
solo con S=person1
y P=creditScore
. Esto impide que las transacciones simultáneas inserten o eliminen triples con la propiedad creditScore
para el asunto person1
.
Ejemplo 5: evitar propiedades o bordes pendientes
La actualización de una entidad no debe dejar un elemento pendiente, es decir, una propiedad o borde asociado a una entidad que no esté escrita. Esto solo es un problemaSPARQL, ya que Gremlin tiene restricciones integradas para evitar que los elementos cuelguen.
# SPARQL: tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person } tx2: DELETE { :person1 ?p ?o }
La consulta INSERT
debe leer y bloquear el prefijo SPO
con S=person1
, P=rdf:type
y O=Person
en el índice SPOG
. El bloqueo impide que la consulta DELETE
se realice correctamente en paralelo.
En la carrera entre la consulta DELETE
que intenta eliminar el registro :person1 rdf:type :Person
y la consulta INSERT
que lee el registro y crea un bloqueo de rango en su SPO
en el índice SPOG
, son posibles los siguientes resultados:
Si la consulta
INSERT
se confirma antes de que la consultaDELETE
lea y elimine todos los registros de:person1
,:person1
se elimina en su totalidad de la base de datos, incluido el registro recién insertado.Si la consulta
DELETE
se confirma antes de que la consultaINSERT
intente leer el registro:person1 rdf:type :Person
, la lectura observa el cambio confirmado. Es decir, no encuentra ningún registro:person1 rdf:type :Person
y, por lo tanto, se convierte en una instrucción no-op (sin operación).Si la
INSERT
consulta se lee antes que laDELETE
consulta, el:person1 rdf:type :Person
triple se bloquea y laDELETE
consulta se bloquea hasta que se confirmeINSERT, como en el primer caso anterior.Si
DELETE
se lee antes que la consultaINSERT
y la consultaINSERT
intenta leer y bloquear el prefijoSPO
del registro, se detecta un conflicto. Esto se debe a que el triple se ha marcado para su eliminación y, por lo tanto, se produce un fallo enINSERT
.
En todas estas diferentes secuencias posibles de eventos, no se crea ningún borde pendiente.