Neptune 트랜잭션 시맨틱의 예제 - Amazon Neptune

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Neptune 트랜잭션 시맨틱의 예제

다음 예제는 Amazon Neptune에서 트랜잭션 시맨틱의 다양한 사용 사례를 보여줍니다.

예제 1 - 존재하지 않는 경우에만 속성을 추가

속성을 단 한 번만 설정하고 싶다고 가정합니다. 예를 들어 여러 개의 쿼리가 어떤 사람에게 하나의 크레딧 점수를 동시에 할당하려고 시도한다고 가정해 보겠습니다. 속성이 이미 설정되어 있기 때문에 속성의 한 인스턴스만 삽입하고 다른 쿼리들은 실패하도록 하고 싶을 수 있습니다.

# 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 .} }

Gremlin property() 단계는 주어진 키와 값으로 속성을 삽입합니다. coalesce() 단계는 첫 번째 단계의 인수를 실행하는데, 이 작업이 실패하면 두 번째 단계가 실행됩니다.

주어진 person1 버텍스에 대한 creditScore 속성의 값을 삽입하기 전에 트랜잭션이 person1에서 존재하지 않을 가능성이 있는 creditScore 값에 대한 읽기를 시도해야 합니다. 이렇게 읽기를 시도하면 creditScore 값이 존재하거나 기록되는 SPOG 인덱스에서 S=person1P=creditScore에 대한 SP 범위가 잠깁니다.

이렇게 범위를 잠그면 어떤 동시 트랜잭션도 creditScore 값을 동시에 삽입하지 못하도록 할 수 있습니다. 여러 병렬 트랜잭션이 있을 때 한 번에 최대 1개의 트랜잭션만 이 값을 업데이트할 수 있습니다. 이렇게 하면 하나 이상의 creditScore 속성이 생성되는 이상 현상을 막을 수 있습니다.

예제 2 - 속성값이 전역적으로 고유하다고 어설션

사회 보장 번호를 기본 키로 해서 어떤 사람을 추가하고 싶다고 가정합니다. 변형 쿼리를 통해 전역적 수준에서 데이터베이스의 다른 어떤 것도 동일한 사회 보장 번호를 가지지 못하도록 보장하고 싶을 수 있습니다.

# 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 } }

이 예제는 이전 예제와 유사합니다. 가장 큰 차이라면 SPOG 인덱스가 아닌 POGS 인덱스에서 범위 잠금이 이루어진다는 것입니다.

쿼리를 실행 중인 트랜잭션은 PO 위치가 바인딩되는 패턴 ?person :ssn 123456789을 읽어야 합니다. P=ssnO=123456789에 대한 POGS 인덱스에서 범위 잠금이 이루어집니다.

  • 패턴이 존재하면 아무 조치도 이루어지지 않습니다.

  • 패턴이 존재하지 않는 경우에는 이러한 잠금을 통해 동시 트랜잭션이 사회 보장 번호를 삽입하는 것을 막을 수 있습니다.

예제 3 - 다른 속성에 지정된 값이 있을 경우 속성 변경

게임의 다양한 이벤트가 어떤 사람을 레벨 1에서 레벨 2로 높이고 이들에게 0으로 설정된 level2Score 속성을 새로 할당한다고 가정합니다. 이 경우에는 이 트랜잭션에 대한 여러 개의 동시 인스턴스에서 레벨 2 점수 속성에 대해 여러 개의 인스턴스를 생성하지 못하도록 해야 합니다. Gremlin 및 의 쿼리는 다음과 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 .}

Gremlin에서 Cardinality.single이 지정되면 property() 단계가 새 속성을 추가하거나 기존 속성 값을 지정된 새 값으로 바꿉니다.

현재 레코드를 삭제하고 새로운 속성 값을 가진 새 레코드를 삽입하면 level을 1에서 2로 올리는 등 속성 값 업데이트가 실행됩니다. 이 경우에는 레벨 1인 레코드가 삭제되고 레벨 2인 레코드가 삽입됩니다.

트랜잭션이 level2Score을 추가하고 level를 1에서 2로 업데이트할 수 있도록 하려면 현재 level 값이 1과 같은지 먼저 확인해야 합니다. 이렇게 하면 SPOG 인덱스의 S=person1, P=levelO=1에서 SPO 접두사에 대한 범위 잠금이 이루어집니다. 이러한 잠금은 동시 트랜잭션이 버전 1 트리플이 삭제되는 일이 없도록 해주기 때문에 결과적으로 동시 업데이트의 충돌이 발생하지 않습니다.

예제 4 - 기존 속성 대체

특정 이벤트가 어떤 사람의 크레딧 점수를 새 값으로 업데이트할 수 있습니다(여기 나온 BBB 참조). 그러나 사용자는 해당 유형의 동시 이벤트가 어떤 사람에 대해 여러 개의 크레딧 점수 속성을 생성하지 못하도록 하고 싶습니다.

# 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 .}

이 경우는 SPO 접두사를 잠그는 대신 Neptune이 S=person1P=creditScore에서만 SP 접두사를 잠근다는 점을 제외하고 예제 3과 비슷합니다. 이렇게 하면 동시 트랜잭션이 person1 제목에서 creditScore 속성을 가진 어떤 트리플도 삽입 또는 삭제할 수 없습니다.

예제 5 - 속성 또는 엣지 누락 방지

엔터티를 업데이트해도 요소 누락, 즉 엔터티와 관련된 속성 또는 엣지가 입력되지 않는 상황이 발생하지 않아야 합니다. Gremlin에는 매달린 요소를 방지하는 제약 조건이 내장되어 SPARQL있기 때문에 이는 의 문제일 뿐입니다.

# SPARQL: tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person } tx2: DELETE { :person1 ?p ?o }

INSERT 쿼리는 SPOG 인덱스에서 S=person1, P=rdf:typeO=Person를 통해 SPO 접두사를 읽고 잠가야 합니다. 이러한 잠금은 DELETE 쿼리가 병렬로 성공하는 일이 없도록 막아줍니다.

:person1 rdf:type :Person 레코드의 삭제를 시도하는 DELETE 쿼리와 레코드를 읽어서 SPOG 인덱스에서 SPO에 대한 범위 잠금을 생성하는 INSERT 쿼리가 서로 경쟁하면 다음과 같은 결과가 발생할 수 있습니다.

  • DELETE 쿼리가 :person1에서 모든 레코드를 읽고 삭제하기 전에 INSERT 쿼리가 커밋되면 새로 삽입된 레코드를 포함해 :person1가 데이터베이스에서 완전히 삭제됩니다.

  • INSERT 쿼리가 :person1 rdf:type :Person 레코드의 읽기를 시도하기 전에 DELETE 쿼리가 커밋되면 해당 읽기 작업에서 커밋된 변경이 관찰됩니다. 즉, :person1 rdf:type :Person 레코드는 전혀 찾지 않기 때문에 no-op 상태가 됩니다.

  • INSERT 쿼리가 읽기 전에 DELETE 쿼리가 읽히면 이전에 첫 번째 경우와 같이 :person1 rdf:type :Person 트리플이 잠기고 DELETE 쿼리가 커밋될 때까지 INSERT 쿼리가 차단됩니다.

  • INSERT 쿼리에 앞서 DELETE이 읽기를 수행하고 INSERT 쿼리가 해당 레코드의 SPO 접두사에 대해 읽기 및 잠금을 시도하면 충돌이 감지됩니다. 왜냐하면 트리플이 제거되었다고 표시되면 INSERT가 실패하기 때문입니다.

가능한 모든 이벤트 시퀀스에서 누락 엣지가 생성되지 않습니다.