Ejemplos de semántica de transacciones de Neptune - Amazon Neptune

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.

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 consulta DELETE 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 consulta INSERT 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 la DELETE consulta, el :person1 rdf:type :Person triple se bloquea y la DELETE consulta se bloquea hasta que se confirmeINSERT, como en el primer caso anterior.

  • Si DELETE se lee antes que la consulta INSERT y la consulta INSERT intenta leer y bloquear el prefijo SPO 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 en INSERT.

En todas estas diferentes secuencias posibles de eventos, no se crea ningún borde pendiente.