1. Groovy 1.1. Java編程語言的一個超集 1.2. Gremlin Console的一個特性是能和Groovy配合使用 1.2.1. Gremlin Console會自動地迭代結果 1.3. 從技術上說,Gremlin Console就是Groovy互動式解釋器(read-eval- ...
1. Groovy
1.1. Java編程語言的一個超集
1.2. Gremlin Console的一個特性是能和Groovy配合使用
1.2.1. Gremlin Console會自動地迭代結果
1.3. 從技術上說,Gremlin Console就是Groovy互動式解釋器(read-eval-print loop,REPL)
1.3.1. 既可以作為一個獨立的程式運行,也可以很容易地在其他程式中作為整體程式的一部分使用
2. 變異(mutation)
2.1. 簡單地被理解為通過添加、修改或刪除頂點、邊和/或屬性來改變圖
2.2. 變異遍歷或變異過程是在某種程度上改變圖的內容或結構的操作
3. 添加頂點
3.1. INSERT INTO person (first_name) VALUES ('Dave');
3.2. 在圖中添加頂點相當於在關係資料庫中添加實體
3.3. 過程
3.3.1. 給定一個遍歷源g
3.3.2. 添加一個新的頂點,類型是person
3.3.3. 在該頂點上添加一個屬性,鍵是first_name,值是Dave
3.4. groovy
g.addV('person').property('first_name', 'Dave')
==>v[13]
3.4.1. 只需要為每一個addV()操作增加一個單一頂點
3.4.2. addV(label)
3.4.2.1. 在圖中增加一個類型為label的頂點並返回這個新增頂點的引用
3.4.3. property(key, value)
3.4.3.1. 在頂點或邊上增加一個屬性
3.4.3.2. 該屬性包含指定的key和value
3.4.3.3. 返回對進入該操作的頂點或邊的引用
3.4.4. v[13]
3.4.4.1. 頂點的唯一的識別碼
3.4.4.2. 這個ID值是根據資料庫的當前狀態內部生成的
3.4.4.2.1. 頂點的ID值應該被視為圖資料庫引擎的內部信息
3.4.4.2.2. 對資料庫引擎等工具的內部信息,你應該保持足夠的警惕
3.4.4.2.3. 為了應用程式的需要而在應用代碼中使用它們則是極其危險的
3.4.4.3. Gremlin Server,在頂點上使用簡單整數(32位),在邊上使用長整數(64位)
3.4.4.4. 其他圖資料庫引擎可能會使用UUID或GUID
3.4.4.5. 雖然可以在代碼中運用這些值,但最佳實踐是不去使用它們
3.5. g.V().addV('person')
3.5.1. V()操作不僅代表圖中的所有頂點,也會返回所有頂點
3.5.1.1. 下一個操作將在上一步操作輸出的每個元素上執行
3.5.2. 圖中的每一個現有頂點都會被添加一個person頂點
3.5.3. 在某些情況下,這可能是我們想要的結果
4. 添加邊
4.1. 在關係資料庫世界里,實體間的連接是通過外鍵隱式實現的
4.2. 在圖的世界里,這些連接需要通過邊來顯式添加
4.3. 在添加邊時,需要為它指定入頂點和出頂點
4.4. SELECT * FROM table1 WHERE id = (SELECT id1 FROM table2);
4.5. 過程
4.5.1. 給定一個遍歷源g
4.5.2. 添加一條標簽為friends的邊
4.5.3. 分配邊的出頂點是鍵為first_name、值為Ted的頂點
4.5.4. 分配邊的入頂點是鍵為first_name、值為Hank的頂點
4.6. groovy
g.addE('friends').
from(
V().has('person', 'first_name', 'Ted')
).
to(
V().has('person', 'first_name', 'Hank')
)
==>e[15][4-friends->6]
4.6.1. addE(label)
4.6.1.1. 添加一條標簽為label的邊
4.6.2. from(vertex)
4.6.2.1. 指定邊從哪個頂點開始的調節器
4.6.3. to(vertex)
4.6.3.1. 指定邊在哪個頂點結束的調節器
4.6.4. 操作調節器不能單獨使用
4.6.5. 調節器來源於TinkerPop,但提供開始頂點和結束頂點的細節則是通用需求
5. 刪除頂點
5.1. DELETE FROM person WHERE person_id = 13;
5.2. 過程
5.2.1. 給定一個遍歷源g
5.2.2. 找到一個ID為13的頂點
5.2.3. 刪除這個頂點
5.3. g.V(13).drop()
5.3.1. V(id)
5.3.1.1. 返回id指定的頂點
5.3.1.2. 這個id是由Gremlin Server(其選擇的資料庫)分配和維護的內部ID
5.3.2. drop()
5.3.2.1. 刪除任何經過它的頂點、邊或屬性
5.3.2.2. 沒有任何返回結果
5.3.2.2.1. 發揮作用之後,它不會向客戶端返回任何消息
6. 刪除邊
6.1. 方式1
6.1.1. 如果刪除開始頂點或結束頂點,那麼任何與該頂點關聯的邊也會被刪除,這是圖資料庫版本的引用完整性體現
6.2. 方式2
6.2.1. 顯式地刪除它們,留下開始頂點和結束頂點
6.3. 過程
6.3.1. 給定一個遍歷源g
6.3.2. 找到一條ID為15的邊
6.3.3. 刪除這條邊
6.4. g.E(15).drop()
6.4.1. 在TinkerPop中,g.E()的預設實現需要一個類型為Long而不是int的參數,在Java中要留意這一點
6.4.2. 幾乎和刪除頂點的語句一模一樣
6.4.2.1. 這種相似的語法也昭示了頂點和邊在圖資料庫中同等重要
7. 修改圖
7.1. UPDATE person SET first_name = 'Dave' WHERE first_name = 'Dav';
7.2. 過程
7.2.1. 給定一個遍歷源g
7.2.2. 找到一個鍵為first_name、值為Dav的頂點
7.2.3. 修改該頂點的屬性,將其值改為Dave
7.3. groovy
g.V().has('person', 'first_name', 'Dav').
property('first_name', 'Dave')
==>v[18]
8. 腳本變異
8.1. groovy
g.V().drop().iterate()
dave = g.addV('person').property('first_name', 'Dave').next()
josh = g.addV('person').property('first_name', 'Josh').next()
ted = g.addV('person').property('first_name', 'Ted').next()
hank = g.addV('person').property('first_name', 'Hank').next()
g.addE('friends').from(dave).to(ted).next()
g.addE('friends').from(dave).to(josh).next()
g.addE('friends').from(dave).to(hank).next()
g.addE('friends').from(josh).to(hank).next()
g.addE('friends').from(ted).to(josh).next()
8.2. Gremlin代碼的第一行是g.V().drop().iterate(),用來清除圖中的所有數據
8.3. iterate()操作和next()操作類似,都會觸發遍歷
8.4. iterate()操作不會返回結果,而next()操作會返回遍歷的結果
8.5. 由於drop()操作不返回值,因此這裡使用iterate()操作比next()操作更合適
8.6. dave = g.addV('person').property('first_name', 'Dave').next()
8.6.1. 要在添加邊之前把相應的頂點創建好
8.6.2. 過程
8.6.2.1. 給定一個遍歷源g
8.6.2.2. 添加一個含有標簽person的新頂點
8.6.2.3. 為這個頂點添加一個鍵為first_name、值為Dave的屬性
8.6.2.4. 執行這些操作,返回迭代中的第一個(下一個)項作為結果
8.6.3. 聲明保存遍歷結果的變數dave
8.6.3.1. 變數是圖世界中另一種差別的源頭
8.6.3.1.1. Cypher,不支持這種跨請求的查詢
8.6.3.1.2. 甚至在支持TinkerPop的圖資料庫間的支持程度都不一樣
8.6.3.1.3. 不管是Azure的CosmosDB還是Amazon Nepture,都沒有這個功能
8.6.3.1.4. JanusGraph和DataStax Enterprise Graph則完全支持
8.6.3.1.5. 如果查詢語言和資料庫支持變數的話,我們推薦使用它們
8.6.3.1.6. 變數可以極大地簡化某些操作
8.6.3.1.6.1. 把添加頂點和邊的操作串聯在一起
8.6.3.2. 當要把結果賦值給一個變數時,則不得不包含終端操作
8.6.3.3. 否則,整個迭代集會被分配到變數中,而不只是迭代集里的那些結果
8.6.3.4. 這不是一個冪等的操作
8.6.4. next()
8.6.4.1. 一個終端操作,它從上一個操作獲得迭代遍歷源,迭代一次,然後返回迭代中的第一個或下一個項
8.6.4.2. 類似於iterate()的終端操作
8.6.4.3. 可以把它想成一個強制遍歷迴圈的操作
8.7. g.addE('friends').from(dave).to(ted)
8.7.1. 給定一個遍歷源g
8.7.2. 增加一條標簽為friends的邊
8.7.3. 出頂點指向dave變數
8.7.4. 入頂點指向ted變數
9. 鏈式變異
9.1. 在圖資料庫中,變異可以鏈接在一起,以同時執行多個變更
9.2. groovy
g.addE('friends').from(dave).to(josh).
addE('friends').from(dave).to(hank).
addE('friends').from(josh).to(hank).
addE('friends').from(ted).to(josh).iterate()
9.3. 要在一個語句中包含複雜的操作,鏈接操作是Gremlin中的基本策略
9.3.1. 每一個操作從上一個操作的輸出獲取數據,併在處理後將該數據交給下一個操作
9.3.2. 對於熟悉函數式編程的朋友來說,這一切都似曾相識
9.4. 圖遍歷中的變異操作允許把多個變異操作鏈接成一個操作,而SQL做不到這一點
10. 路徑(path)
10.1. 在遍歷中從開始頂點訪問到結束頂點之間的所有頂點和邊的列表
10.2. 不僅告訴我們兩個頂點是連接的,而且展示了它們之間的所有中間元素
10.3. 路徑描述了從開始頂點到結束頂點的一系列遍歷操作
10.4. 路徑代表一系列連接兩個元素的頂點和邊
10.5. 意味著我們不僅能發現兩個頂點是相互連接的,而且能確定如何從起點到達終點
10.6. groovy
g.V().has('person', 'first_name', 'Ted').
until(has('person', 'first_name', 'Denise')).
repeat(
both('friends')
).path()
10.6.1. path()
10.6.1.1. 當遍歷執行時,返回指定遍歷器訪問頂點(某些時候還有邊)的歷史
10.6.1.2. 在Gremlin中使用path()操作會增加伺服器的資源消耗,因為每個遍歷器都需要維護自己訪問的所有歷史記錄
10.6.1.3. 只在需要所有路徑數據時使用path()
10.7. groovy
Script evaluation exceeded the configured 'scriptEvaluationTimeout' threshold
of 30000 ms or evaluation was otherwise cancelled directly for request
[g.V().has('person', 'first_name', 'Ted').
until(has('person', 'first_name', 'Denise')).
repeat(
both('friends')
).path()]
Type ':help' or ':h' for help.
10.7.1. 遍歷超時了
10.7.2. 圖中生成了一個環
10.7.2.1. 環是圖論中的一個概念,指的是圖中頂點和邊的路徑包含一個或多個能到達自己的頂點
10.7.2.2. 環指的是含有重覆頂點的路徑,通常會在圖遍歷過程中引起長時間運行的迴圈與尋路查詢
10.7.3. :clear命令清除緩存並重新啟動遍歷
11. 簡單路徑
11.1. 不會在任何一個頂點上重覆的路徑
11.2. 在簡單路徑中只會得到非環的結果
11.2.1. 簡單路徑就是圖中不含重覆頂點的路徑
11.3. 每個遍歷器會維護它訪問的所有項的歷史
11.3.1. 當碰到一個曾經訪問過的項時,它就知道這個元素在環中,並把它剔除
11.3.2. 只有那些不含環的遍歷器會繼續完成遍歷工作
11.4. groovy
g.V().has('person', 'first_name', 'Ted').
until(has('person', 'first_name', 'Denise')).
repeat(
both('friends').simplePath()
).path()
==>path[v[4], v[0], v[15], v[19]]
==>path[v[4], v[0], v[13], v[19]]
==>path[v[4], v[2], v[0], v[15], v[19]]
==>path[v[4], v[2], v[0], v[13], v[19]]
==>path[v[4], v[0], v[15], v[17], v[19]]
==>path[v[4], v[0], v[15], v[13], v[19]]
==>path[v[4], v[0], v[13], v[15], v[19]]
==>path[v[4], v[2], v[6], v[0], v[15], v[19]]
==>path[v[4], v[2], v[6], v[0], v[13], v[19]]
==>path[v[4], v[2], v[0], v[15], v[17], v[19]]
==>path[v[4], v[2], v[0], v[15], v[13], v[19]]
==>path[v[4], v[2], v[0], v[13], v[15], v[19]]
==>path[v[4], v[0], v[13], v[15], v[17], v[19]]
==>path[v[4], v[2], v[6], v[0], v[15], v[17], v[19]]
==>path[v[4], v[2], v[6], v[0], v[15], v[13], v[19]]
==>path[v[4], v[2], v[6], v[0], v[13], v[15], v[19]]
==>path[v[4], v[2], v[0], v[13], v[15], v[17], v[19]]
==>path[v[4], v[2], v[6], v[0], v[13], v[15], v[17], v[19]]
11.4.1. simplePath()
11.4.1.1. 篩選掉遍歷中被重覆訪問的頂點
11.4.1.2. 如果把simplePath()放在遍歷末尾,它就在迴圈邏輯之外了,遍歷器會被困在環里,無法離開
11.4.1.3. 就像在Java里創建一個for迴圈,但把計數器變數放在for迴圈之外
12. 遍歷和篩選邊
12.1. 從頂點走到邊,再從邊走到頂點。必須顯式遍歷到邊,並顯式從邊離開
12.2. 邊可以直接被遍歷和篩選,不需要遍歷到相鄰的頂點
12.3. InE(label)
12.3.1. 從當前頂點遍歷到相鄰的入邊
12.4. outE(label)
12.4.1. 從當前頂點遍歷到相鄰的出邊
12.5. bothE(label)
12.5.1. 從當前頂點遍歷到相鄰邊,不考慮方向
12.6. 如果指定了標簽,只遍歷到符合篩選條件的邊
12.7. 每個E操作都從一個頂點開始,遍歷到一條邊,然後停留在這條邊上
12.7.1. 這些操作都結束於邊,而不是相鄰的頂點
12.8. inV()
12.8.1. 從當前邊遍歷到入頂點
12.8.2. 通常和outE()操作搭配使用
12.8.2.1. 組合來完成到相鄰頂點的遍歷
12.9. outV()
12.9.1. 從當前邊遍歷到出頂點
12.9.2. 通常和inE()操作搭配使用
12.9.2.1. 組合來完成到相鄰頂點的遍歷
12.10. otherV()
12.10.1. 遍歷到不是出頂點的那個頂點(如另一個頂點)
12.10.2. 通常和bothE()操作搭配使用
12.10.2.1. 輕鬆地帶到“另一個頂點”上,不是遍歷出發的那個頂點
12.11. bothV()
12.11.1. 從當前邊遍歷到兩個相鄰的頂點
12.11.2. 極少用到
12.12. groovy
g.V().has('person','first_name','Dave').
bothE('works_with').otherV().values('first_name')
==>Ted
==>Josh
==>Hank
==>Kelly
==>Denise
12.13. groovy
g.V().has('person', 'first_name','Dave').
both('works_with').values('first_name')
==>Ted
==>Josh
==>Hank
==>Kelly
==>Denise
12.14. groovy
g.V().has('person', 'first_name', 'Ted').
until(has('person', 'first_name', 'Denise')).
repeat(
bothE('works_with').otherV().simplePath()
).path()
==>path[v[4], e[29][0-works_with->4], v[0], e[33][0-works_with->19], v[19]]
==>path[v[4], e[29][0-works_with->4], v[0], e[32][0-works_with->13], v[13],
e[34][19-works_with->13], v[19]]
==>path[v[4], e[30][2-works_with->4], v[2], e[28][0-works_with->2], v[0],
e[33][0-works_with->19], v[19]]
==>path[v[4], e[30][2-works_with->4], v[2], e[28][0-works_with->2], v[0],
e[[32][0-works_with->13], v[13], e[34][19-works_with->13], v[19]]
12.14.1. bothE().otherV()遍歷模式來顯式地遍歷到邊上
12.14.2. 在路徑結果中包括邊
12.14.3. 航空交通路線
12.14.3.1. 頂點代表機場,邊代表機場間的航班
13. 通過屬性篩選邊
13.1. 基於時間的篩選
13.2. 基於權重的篩選
13.3. groovy
g.V().has('person','first_name','Dave').
bothE('works_with').has('end_year',lte(2018)).
otherV().
values('first_name')
==>Josh
==>Ted
==>Hank