溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

圖數(shù)據(jù)庫查詢語言Gremlin vs Cypher vs nGQL的操作入門是怎樣的

發(fā)布時間:2021-12-20 14:21:57 來源:億速云 閱讀:164 作者:柒染 欄目:數(shù)據(jù)庫

圖數(shù)據(jù)庫查詢語言Gremlin vs Cypher vs nGQL的操作入門是怎樣的,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

文章的開頭我們先來看下什么是圖數(shù)據(jù)庫,根據(jù)維基百科的定義:圖數(shù)據(jù)庫是使用圖結(jié)構(gòu)進行語義查詢的數(shù)據(jù)庫,它使用節(jié)點、邊和屬性來表示和存儲數(shù)據(jù)。

雖然和關(guān)系型數(shù)據(jù)庫存儲的結(jié)構(gòu)不同(關(guān)系型數(shù)據(jù)庫為表結(jié)構(gòu),圖數(shù)據(jù)庫為圖結(jié)構(gòu)),但不計各自的性能問題,關(guān)系型數(shù)據(jù)庫可以通過遞歸查詢或者組合其他 SQL 語句(Join)完成圖查詢語言查詢節(jié)點關(guān)系操作。得益于 1987 年 SQL 成為國際標準化組織(ISO)標準,關(guān)系型數(shù)據(jù)庫行業(yè)得到了很好的發(fā)展。同 60、70 年代的關(guān)系型數(shù)據(jù)庫類似,圖數(shù)據(jù)庫這個領域的查詢語言目前也沒有統(tǒng)一標準,雖然 19 年 9 月經(jīng)過國際 SQL 標準委員會投票表決,決定將圖查詢語言(Graph Query Language)納為一種新的數(shù)據(jù)庫查詢語言,但 GQL 的制定仍需要一段時間。

介于市面上沒有統(tǒng)一的圖查詢語言標準,在本文中我們選取市面上主流的幾款圖查詢語言來分析一波用法,由于篇幅原因本文旨在簡單介紹圖查詢語言和常規(guī)用法,更詳細的內(nèi)容將在進階篇中講述。

圖查詢語言·介紹

圖查詢語言 Gremlin

Gremlin 是 Apache ThinkerPop 框架下的圖遍歷語言。Gremlin 可以是聲明性的也可以是命令性的。雖然 Gremlin 是基于 Groovy 的,但具有許多語言變體,允許開發(fā)人員以 Java、JavaScript、Python、Scala、Clojure 和 Groovy 等許多現(xiàn)代編程語言原生編寫 Gremlin 查詢。

支持圖數(shù)據(jù)庫:Janus Graph、InfiniteGraph、Cosmos DB、DataStax Enterprise(5.0+)    、Amazon Neptune

圖查詢語言 Cypher

Cypher 是一個描述性的圖形查詢語言,允許不必編寫圖形結(jié)構(gòu)的遍歷代碼對圖形存儲有表現(xiàn)力和效率的查詢,和 SQL 很相似,Cypher 語言的關(guān)鍵字不區(qū)分大小寫,但是屬性值,標簽,關(guān)系類型和變量是區(qū)分大小寫的。

支持圖數(shù)據(jù)庫: Neo4j、RedisGraph、AgensGraph

圖查詢語言 nGQL

nGQL 是一種類 SQL 的聲明型的文本查詢語言,nGQL 同樣是關(guān)鍵詞大小寫不敏感的查詢語言,目前支持模式匹配、聚合運算、圖計算,可無嵌入組合語句。

支持圖數(shù)據(jù)庫:Nebula Graph

圖查詢語言·術(shù)語篇

在比較這 3 個圖查詢語言之前,我們先來看看他們各自的術(shù)語,如果你翻閱他們的文檔會經(jīng)常見到下面這些“關(guān)鍵字”,在這里我們不講用法,只看這些圖數(shù)據(jù)庫常用概念在這 3 個圖數(shù)據(jù)庫文檔中的叫法。

術(shù)語GremlinCyphernGQL
VertexNodeVertex
EdgeRelationshipEdge
點類型LabelLabelTag
邊類型labelRelationshipTypeedge type
點 IDvidid(n)vid
邊 IDeidid(r)
插入addcreateinsert
刪除dropdeletedelete / drop
更新屬性setPropertysetupdate

我們可以看到大體上對點和邊的叫法類似,只不過 Cypher 中直接使用了 Relationship 關(guān)系一詞代表邊。其他的術(shù)語基本都非常直觀。

圖查詢語言·語法篇

了解過 Gremlin、Cypher、nGQL 中常見的術(shù)語之后,我們來看看使用這 3 個圖查詢語言過程中會需要了解的常規(guī)語法。

# Gremlin 創(chuàng)建圖
g = TinkerGraph.open().traversal()
# nGQL 創(chuàng)建圖空間
CREATE SPACE gods

圖結(jié)構(gòu)由點和邊組成,一條邊連接兩個點。在 Gremlin 和 nGQL 中稱之為 Vertex,Cypher 則稱之為 Node。如何在圖數(shù)據(jù)庫中新建一個點呢?可以參考下面的語法

# Gremlin 創(chuàng)建/插入點
g.addV(vertexLabel).property()
# Cypher 創(chuàng)建點
CREATE (:nodeLabel {property})
# nGQL 創(chuàng)建/插入點
INSERT VERTEX tagName (propNameList) VALUES vid:(tagKey propValue)
點類型

點允許有對應的類型,在 Gremlin 和 Cypher 叫 label ,在 nGQL 中為 tag 。點類型可對應有多種屬性(Property),例如 Person 可以有 nameage 等屬性。

圖數(shù)據(jù)庫查詢語言Gremlin vs Cypher vs nGQL的操作入門是怎樣的

創(chuàng)建點類型

點類型相關(guān)的語法示例如下:

# Gremlin 創(chuàng)建點類型
g.addV(vertexLabel).property()
# nGQL 創(chuàng)建點類型
CREATE tagName(PropNameList)

這里說明下,無論在 Gremlin 和 nGQL 中存在類似 IF NOT EXISTS  用法,即:如果不存在則創(chuàng)建,存在則直接返回。

查看點類型

創(chuàng)建好點之后如何查看點類型呢,可以參考以下方式。

# Gremlin 查看(獲?。c類型
g.V().label().dedup();
# Cypher 查看點類型方法 1
MATCH (n) 
RETURN DISTINCT labels(n)
# Cypher 查看點類型方法 2
CALL db.labels();
# nGQL 查看點類型
SHOW TAGS
點的 CRUD

上面簡單介紹了點、點類型,下面進入數(shù)據(jù)庫基本 DML——CRUD,在上文介紹點時順便介紹了點的創(chuàng)建和插入,這里說下如何插入特定類型的點,和點的獲取、刪除和更新。

插入特定類型點

和插入點的操作類似,只不過需要指定某種點類型。語法參考:

# Gremlin 插入特定類型點
g.addV(String vertexLabel).property()
# Cypher 插入特定類型點
CREATE (node:label) 
# nGQL 插入特定類型點
INSERT VERTEX <tag_name> (prop_name_list) VALUES <vid>:(prop_value_list)
查看點
# Gremlin 查看點
g.V(<vid>)
# Cypher 查看點
MATCH (n) 
WHERE condition
RETURN properties(n)
# nGQL 查看點
FETCH PROP ON <tag_name> <vid>
刪除點

術(shù)語篇中提過 nGQL 中刪除操作對應單詞有 DeleteDrop ,在 nGQL 中 Delete 一般用于點邊,Drop 用于 Schema 刪除,這點和 SQL 的設計思路是一樣的。

# Gremlin 刪除點
g.V(<vid>).drop()
# Cypher 刪除點
MATCH (node:label) 
DETACH DELETE node
# nGQL 刪除點
DELETE VERTEX <vid>
更新點

用數(shù)據(jù)庫的小伙伴都知道數(shù)據(jù)的常態(tài)是數(shù)據(jù)變更,來瞅瞅這 3 個圖查詢是使用什么語法來更新點數(shù)據(jù)的吧

# Gremlin 更新點
g.V(<vid>).property()
# Cypher 更新點
SET n.prop = V
# nGQL 更新點
UPDATE VERTEX <vid> SET <update_columns>

可以看到 Cypher 和 nGQL 都使用 SET 關(guān)鍵詞來設置點對應的類型值,只不過 nGQL 中多了 UPDATE 關(guān)鍵詞來標識操作,Gremlin 的操作和上文提到的查看點類似,只不過增加了變更 property 值操作。

在 Gremlin 和 nGQL 稱呼邊為 Edge,而 Cypher 稱之為 Relationship。下面進入到邊相關(guān)的語法內(nèi)容

邊類型

和點一樣,邊也可以有對應的類型

# Gremlin 創(chuàng)建邊類型
g.edgeLabel()
# nGQL 創(chuàng)建邊類型
CREATE EDGE edgeTypeName(propNameList)
邊的 CRUD

說完邊類型應該進入到邊的常規(guī)操作部分了

插入指定邊類型的邊

可以看到和點的使用語法類似,只不過在 Cypher 和 nGQL 中分別使用 -[]->-> 來表示關(guān)系,而 Gremlin 則用 to() 關(guān)鍵詞來標識指向關(guān)系,在使用這 3 種圖查詢語言的圖數(shù)據(jù)庫中的邊均為有向邊,下圖左邊為有向邊,右邊為無向邊。

圖數(shù)據(jù)庫查詢語言Gremlin vs Cypher vs nGQL的操作入門是怎樣的

# Gremlin 插入指定邊類型的邊
g.addE(String edgeLabel).from(v1).to(v2).property()
# Cypher 插入指定邊類型的邊
CREATE (<node1-name>:<label1-name>)-
  [(<relationship-name>:<relationship-label-name>)]
  ->(<node2-name>:<label2-name>)
# nGQL 插入指定邊類型的邊
INSERT EDGE <edge_name> (<prop_name_list>) VALUES <src_vid> -> <dst_vid>: \
(<prop_value_list>)
刪除邊
# Gremlin 刪除邊
g.E(<eid>).drop()
# Cypher 刪除邊
MATCH (<node1-name>:<label1-name>)-[r:relationship-label-name]->()
DELETE r
# nGQL 刪除邊
DELETE EDGE <edge_type> <src_vid> -> <dst_vid>
查看指定邊
# Gremlin 查看指定邊
g.E(<eid>)
# Cypher 查看指定邊
MATCH (n)-[r:label]->()
WHERE condition
RETURN properties(r)
# nGQL 查看指定邊
FETCH PROP ON <edge_name> <src_vid> -> <dst_vid>

其他操作

除了常規(guī)的點、邊 CRUD 外,我們可以簡單看看這 3 種圖查詢語言的組合查詢。

指定點查指定邊
# Gremlin 指定點查指定邊
g.V(<vid>).outE(<edge>)
# Cypher 指定點查指定邊
Match (n)->[r:label]->[]
WHERE id(n) = vid
RETURN r
# nGQL 指定點查指定邊
GO FROM <vid> OVER <edge>
沿指定點反向查詢指定邊

在反向查詢中,Gremlin 使用了 in 來表示反向關(guān)系,而 Cypher 則更直觀的將指向箭頭反向變成 <- 來表示反向關(guān)系,nGQL 則用關(guān)鍵詞 REVERSELY 來標識反向關(guān)系。

# Gremlin 沿指定點反向查詢指定邊
g.V(<vid>).inE(<edge>)
# Cypher 沿指定點反向查詢指定邊
MATCH (n)<-[r:label]-()
# nGQL 沿指定點反向查詢指定邊
GO FROM <vid> OVER <edge> REVERSELY
無向遍歷

如果在圖中,邊的方向不重要(正向、反向都可以),那 Gremlin 使用 both() ,Cypher 使用 -[]- ,nGQL使用關(guān)鍵詞 BIDIRECT 。

# Traverse edges with specified vertices Gremlin
g.V(<vid>).bothE(<edge>)
# Traverse edges with specified vertices Cypher
MATCH (n)-[r:label]-()
# Traverse edges with specified vertices nGQL
GO FROM <vid>  OVER <edge> BIDIRECT
沿指定點查詢指定邊 N 跳

Gremlin 和 nGQL 分別用 times 和 step 來表示 N 跳關(guān)系,而 Cypher 用 relationship*1..N 來表示 N 跳關(guān)系。

# Gremlin 沿指定點查詢指定邊 N 跳
g.V(<vid>).repeat(out(<edge>)).times(N)
# Cypher 沿指定點查詢指定邊 N 跳
MATCH (n)-[r:label*N]->()
WHERE condition
RETURN r
# nGQL 沿指定點查詢指定邊 N 跳
GO N STEPS FROM <vid> OVER <edge>
返回指定兩點路徑
# Gremlin 返回指定兩點路徑
g.V(<vid>).repeat(out()).until(<vid>).path()
# Cypher 返回指定兩點路徑
MATCH p =(a)-[.*]->(b)
WHERE condition
RETURN p
# nGQL 返回指定兩點路徑
FIND ALL PATH FROM <vid> TO <vid> OVER *

圖查詢語言·實操篇

說了一通語法之后,是時候展示真正的技術(shù)了——來個具體一點的例子。

示例圖:The Graphs of Gods

實操示例使用了 Janus Graph 的示例圖 The Graphs of Gods。該圖結(jié)構(gòu)如下圖所示,描述了羅馬萬神話中諸神關(guān)系。

圖數(shù)據(jù)庫查詢語言Gremlin vs Cypher vs nGQL的操作入門是怎樣的

插入數(shù)據(jù)

# 插入點
## nGQL
nebula> INSERT VERTEX character(name, age, type) VALUES hash("saturn"):("saturn", 10000, "titan"), hash("jupiter"):("jupiter", 5000, "god");
## Gremlin
gremlin> saturn = g.addV("character").property(T.id, 1).property('name', 'saturn').property('age', 10000).property('type', 'titan').next();
==>v[1]
gremlin> jupiter = g.addV("character").property(T.id, 2).property('name', 'jupiter').property('age', 5000).property('type', 'god').next();
==>v[2]
gremlin> prometheus = g.addV("character").property(T.id, 31).property('name',  'prometheus').property('age', 1000).property('type', 'god').next();
==>v[31]
gremlin> jesus = g.addV("character").property(T.id, 32).property('name',  'jesus').property('age', 5000).property('type', 'god').next();
==>v[32]
## Cypher
cypher> CREATE (src:character {name:"saturn", age: 10000, type:"titan"})
cypher> CREATE (dst:character {name:"jupiter", age: 5000, type:"god"})
# 插入邊
## nGQL
nebula> INSERT EDGE father() VALUES hash("jupiter")->hash("saturn"):();
## Gremlin
gremlin> g.addE("father").from(jupiter).to(saturn).property(T.id, 13);
==>e[13][2-father->1]
## Cypher
cypher> CREATE (src)-[rel:father]->(dst)

刪除數(shù)據(jù)

# nGQL
nebula> DELETE VERTEX hash("prometheus");
# Gremlin
gremlin> g.V(prometheus).drop();
# Cypher
cypher> MATCH (n:character {name:"prometheus"}) DETACH DELETE n

更新數(shù)據(jù)

# nGQL
nebula> UPDATE VERTEX hash("jesus") SET character.type = 'titan';
# Gremlin
gremlin> g.V(jesus).property('age', 6000);
==>v[32]
# Cypher
cypher> MATCH (n:character {name:"jesus"}) SET n.type = 'titan';

查看數(shù)據(jù)

# nGQL
nebula> FETCH PROP ON character hash("saturn");
===================================================
| character.name | character.age | character.type |
===================================================
| saturn         | 10000         | titan          |
---------------------------------------------------
# Gremlin
gremlin> g.V(saturn).valueMap();
==>[name:[saturn],type:[titan],age:[10000]]
# Cypher
cypher> MATCH (n:character {name:"saturn"}) RETURN properties(n)
  ╒════════════════════════════════════════════╕
  │"properties(n)"                             │
  ╞════════════════════════════════════════════╡
  │{"name":"saturn","type":"titan","age":10000}│
  └────────────────────────────────────────────┘

查詢 hercules 的父親

# nGQL
nebula>  LOOKUP ON character WHERE character.name == 'hercules' | \
      -> GO FROM $-.VertexID OVER father YIELD $$.character.name;
=====================
| $$.character.name |
=====================
| jupiter           |
---------------------
# Gremlin
gremlin> g.V().hasLabel('character').has('name','hercules').out('father').values('name');
==>jupiter
# Cypher
cypher> MATCH (src:character{name:"hercules"})-[:father]->(dst:character) RETURN dst.name
      ╒══════════╕
      │"dst.name"│
      ╞══════════╡
      │"jupiter" │
      └──────────┘

查詢 hercules 的祖父

# nGQL
nebula> LOOKUP ON character WHERE character.name == 'hercules' | \
     -> GO 2 STEPS FROM $-.VertexID OVER father YIELD $$.character.name;
=====================
| $$.character.name |
=====================
| saturn            |
---------------------
# Gremlin
gremlin> g.V().hasLabel('character').has('name','hercules').out('father').out('father').values('name');
==>saturn
# Cypher
cypher> MATCH (src:character{name:"hercules"})-[:father*2]->(dst:character) RETURN dst.name
      ╒══════════╕
      │"dst.name"│
      ╞══════════╡
      │"saturn"  │
      └──────────┘

查詢年齡大于 100 的人物

# nGQL
nebula> LOOKUP ON character WHERE character.age > 100 YIELD character.name, character.age;
=========================================================
| VertexID             | character.name | character.age |
=========================================================
| 6761447489613431910  | pluto          | 4000          |
---------------------------------------------------------
| -5860788569139907963 | neptune        | 4500          |
---------------------------------------------------------
| 4863977009196259577  | jupiter        | 5000          |
---------------------------------------------------------
| -4316810810681305233 | saturn         | 10000         |
---------------------------------------------------------
# Gremlin
gremlin> g.V().hasLabel('character').has('age',gt(100)).values('name');
==>saturn
==>jupiter
==>neptune
==>pluto
# Cypher
cypher> MATCH (src:character) WHERE src.age > 100 RETURN src.name
      ╒═══════════╕
      │"src.name" │
      ╞═══════════╡
      │  "saturn" │
      ├───────────┤
      │ "jupiter" │
      ├───────────┤
      │ "neptune" │
      │───────────│
      │  "pluto"  │
      └───────────┘

從一起居住的人物中排除 pluto 本人

# nGQL
nebula>  GO FROM hash("pluto") OVER lives YIELD lives._dst AS place | GO FROM $-.place OVER lives REVERSELY WHERE \
$$.character.name != "pluto" YIELD $$.character.name AS cohabitants;
===============
| cohabitants |
===============
| cerberus    |
---------------
# Gremlin
gremlin> g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name');
==>cerberus
# Cypher
cypher> MATCH (src:character{name:"pluto"})-[:lives]->()<-[:lives]-(dst:character) RETURN dst.name
      ╒══════════╕
      │"dst.name"│
      ╞══════════╡
      │"cerberus"│
      └──────────┘

Pluto 的兄弟們

# which brother lives in which place?
## nGQL
nebula> GO FROM hash("pluto") OVER brother YIELD brother._dst AS god | \
GO FROM $-.god OVER lives YIELD $^.character.name AS Brother, $$.location.name AS Habitations;
=========================
| Brother | Habitations |
=========================
| jupiter | sky         |
-------------------------
| neptune | sea         |
-------------------------
## Gremlin
gremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god','place').by('name');
==>[god:jupiter, place:sky]
==>[god:neptune, place:sea]
## Cypher
cypher> MATCH (src:Character{name:"pluto"})-[:brother]->(bro:Character)-[:lives]->(dst)
RETURN bro.name, dst.name
      ╒═════════════════════════╕
      │"bro.name"    │"dst.name"│
      ╞═════════════════════════╡
      │ "jupiter"    │  "sky"   │
      ├─────────────────────────┤
      │ "neptune"    │ "sea"    │
      └─────────────────────────┘

關(guān)于圖數(shù)據(jù)庫查詢語言Gremlin vs Cypher vs nGQL的操作入門是怎樣的問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI