本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
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
值。此嘗試讀取會鎖定 SPOG
索引中 S=person1
和 P=creditScore
的 SP
範圍,其中 creditScore
值存在或將被寫入。
採取此範圍鎖定可防止任何並行交易同時插入 creditScore
值。有多個平行交易時,一次最多一個平行交易可以更新該值。這會排除建立多個 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 } }
此範例與上述範例類似。主要差別在於範圍鎖定是針對 POGS
索引而非 SPOG
索引採取的。
執行查詢的交易必須讀取模式 (?person :ssn 123456789
),其中繫結 P
和 O
位置。範圍鎖定是針對 P=ssn
和 O=123456789
的 POGS
索引採取的。
如果模式的確存在,則不會採取任何動作。
如果不存在,鎖定會防止任何並行交易也插入該社會安全號碼
範例 3 - 如果另一個屬性具有指定值,則變更屬性
假設遊戲中的各種事件將人物從第一層移到第二層,並將設為零的新 level2Score
屬性指派給他們。您需要確保這類交易的多個並行執行個體無法建立層級二分數屬性的多個執行個體。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 的記錄。
若要讓交易能夠新增 level
,並將 level2Score
從 1 更新到 2,必須先驗證 level
值目前是否等於 1。執行此動作時,它會對 SPOG
索引中 S=person1
、P=level
和 O=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 .}
此案例與範例 3 類似,差別在於不是鎖定 SPO
字首,而是 Neptune 只會鎖定具有 S=person1
和 P=creditScore
的 SP
字首。這可防止並行交易插入或刪除任何具有 person1
主旨之 creditScore
屬性的三元組。
範例 5 - 避免懸置屬性或邊緣
實體上的更新不應留下懸置元素,也就是與未輸入之實體相關聯的屬性或邊緣。這只是 中的問題SPARQL,因為 Gremlin 具有內建限制條件,以防止元素懸置。
# SPARQL: tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person } tx2: DELETE { :person1 ?p ?o }
INSERT
查詢必須讀取和鎖定 SPOG
索引 O=Person
中具有 S=person1
和 P=rdf:type
,的 SPO
字首。鎖定可防止 DELETE
查詢平行成功。
在這兩個查詢 (嘗試刪除 :person1 rdf:type :Person
記錄的 DELETE
查詢,以及讀取記錄並在 SPOG
索引中的 SPO
上建立範圍的 INSERT
查詢) 之間的競爭中,可能會產生以下結果:
如果
INSERT
查詢在DELETE
查詢讀取並刪除:person1
的所有記錄之前遞交,則:person1
會完全從資料庫中移除,包括新插入的記錄。如果
DELETE
查詢在INSERT
查詢嘗試讀取:person1 rdf:type :Person
記錄之前遞交,則讀取會觀察遞交的變更。也就是說,它找不到任何:person1 rdf:type :Person
記錄,因此變成無操作。如果
INSERT
查詢在DELETE
查詢執行之前讀取,則會鎖定:person1 rdf:type :Person
三元,並封鎖DELETE
查詢,直到INSERT查詢遞交為止,如同先前第一個案例一樣。如果
DELETE
在INSERT
查詢之前讀取,而且INSERT
查詢嘗試讀取,並對記錄的SPO
字首採取鎖定,則會偵測到衝突。這是因為三元組已標記為移除,然後INSERT
失敗。
在所有這些不同的可能事件序列中,不會建立懸置邊緣。