圖數據庫查詢語言Cypher
1. Cypher簡介
Cypher 是 Neo4j 提出的圖查詢語言,是一種聲明式的圖數據庫查詢語言,它擁有精簡的語法和強大的表現(xiàn)力,能夠精準且高效地對圖數據進行查詢和更新。它是一種受 SQL 啟發(fā)的語言,用于使用 ASCII-Art 語法描述圖中的可視模式。它允許聲明想要從圖數據庫中選擇、插入、更新或刪除什么,而不需要精確地描述如何做到這一點。通過 Cypher,用戶可以構建表達性強且高效的查詢,處理所需的創(chuàng)建、讀取、更新和刪除功能。
1.1 Cypher 設計理念
Cypher 的設計理念是:無論是開發(fā)工程師,數據庫管理員,還是運維工程師,甚至非技術人員都可以輕松讀懂 Cypher。這使得圖數據庫的使用者可以專注于自身業(yè)務需求,而不必花費很多時間去理解圖數據庫的底層實現(xiàn)原理。
(1)人性化設計
Cypher 在語法設計上十分人性化,它提供了一個直觀方式來匹配圖中的節(jié)點和關系。例如想要查詢一個一跳路徑,()代表節(jié)點,[] 代表關系,看起來就像兩個點一條關系組成的一跳路徑。
(2)博采眾長
Cypher 集思廣益,借鑒和吸收了已有數據庫查詢語言的習慣寫法。例如 WHERE、ORDER BY、SKIP 和 LIMIT 就來源于關系數據庫查詢語言 SQL,例如可視化模式匹配的語法設計來源于 RDF 查詢語言 SPARQL 等。
(3)語句組合Cypher
類似于 SQL 語言,一條完整的查詢可由多個語句(Clause)組合而成,每條語句的執(zhí)行結果將保存為中間結果,并往下一條語句傳遞,值得一提的是,Cypher 執(zhí)行采用火山模型(Vocalno),所以除了聚合(Eager)操作,當前語句完全執(zhí)行完之前就會把部分已完成的結果往下一條語句傳遞。
1.2 Cypher 事務操作
在Galaxybase 中,用戶可以自行選擇是否開啟事務,對于一個事務內的 Cypher 更新操作來說,要不全部執(zhí)行失敗,要不全部執(zhí)行成功。
若業(yè)務需求不需開啟事務,執(zhí)行 Cypher 會獲得更佳的性能 。
若業(yè)務需求需開啟事務,開啟事務后,Cypher 執(zhí)行就運行在該事務中,直到事務成功提交事務,執(zhí)行 造成的數據改動才會持久化到磁盤中去。
此外可以在一個事務中執(zhí)行多個 Cypher 查詢:通過 Bolt Driver 提供的 API 創(chuàng)建并開啟一個事務;執(zhí)行多個 Cypher 查詢;提交并關閉這個事務。
1.3 Cypher 唯一性
當進行多跳路徑查找時,Galaxybase 將自動對每個路徑擴展起始點和它的二跳鄰居點進行去重。 例如:查找一個用戶同學的同學,將不會在返回結果返回該用戶。
1.4 Cypher兼容性
Cypher 是目前圖數據庫領域屬性圖的主流查詢語言。為了迎合用戶的使用習慣,避免重復的學習成本,Galaxybase選擇兼容了 Cypher 查詢語言。而 Galaxybase 與 Neo4j 在底層結構上有一定差異,所以 Galaxybase 實現(xiàn)的 Cypher 與 Neo4j 的 Cypher 標準也有一定的差異性,本書將在語法講解過程中標注出 Galaxybase 與 Neo4j 的使用差異。
2. Cypher使用場景
本節(jié)將從一個用戶的視角,使用Cypher完成一個場景下各種查詢任務的語句編寫,使讀者上手一步一步學習和體驗如何使用圖查詢語言來解決實際問題。本節(jié)將以MovieDemo圖做樣例,在Galaxybase上執(zhí)行Cypher語句。
MovieDemo是一個簡單的電影關系。其中包含了3種點類型(人物、電影、電視?。┖?種關系類型(出演電影、出演電視劇、導演電影、導演電視?。?。
MovieDemo下載鏈接:https://www.galaxybase.com/public/download/MovieDemo%E5%9B%BE%E6%95%B0%E6%8D%AE.zip
MovieDemo 圖模型:
點類型
a.?人物:外部唯一標識姓名,擁有出生年份(STRING),籍貫(STRING)屬性
b.?電影:外部唯一標識電影名,擁有上映年份(STRING),語言(STRING),類型(STRING),評分(INT),票房(INT)屬性
c.?電視劇:外部唯一標識電視劇名,擁有首播日期(STRING),語言(STRING),類型(STRING),評分(INT),集數(INT)屬性
關系類型
a.?出演電影:起始點類型人物,終止點類型電影,擁有角色名稱(STRING)屬性,是否主演(STRING)屬性,片酬(INT)屬性
b.?出演電視劇:起始點類型人物,終止點類型電視劇,擁有角色名稱(STRING)屬性,是否主演(STRING)屬性,片酬(INT)屬性
c.?導演電影:起始點類型人物,終止點類型電影,擁有工資(INT)屬性
d.?導演電視劇:起始點類型人物,終止點類型電視劇,擁有工資(INT)屬性
若想了解 Cypher更多使用細節(jié),可以訪問 Galaxybase Cypher官方使用文檔。
Galaxybase Cypher官方使用文檔:https://galaxybase.com/document?file=dev&docid=13
2.1 Match
(1)簡介
MATCH 用于檢索圖數據庫中的節(jié)點和關系。
(2)基本節(jié)點查找
a)獲取圖中所有節(jié)點
如果指定模式為不帶類型的節(jié)點,返回結果則為圖中的所有節(jié)點。示例如下:
b)獲取所有電影類型的節(jié)點
如果單節(jié)點模式(pattern)中節(jié)點帶類型,返回結果為所有此類型的節(jié)點。示例如下:
(3)基本關系查找
a)查找與人物“綾野剛”所有存在一跳關系的實體
當需要說明節(jié)點間關系的方向時,可以用 -→ 或 ←- 表示。示例如下:
b)查找人物“綾野剛”所有一跳關系的類型
如果需要為關系添加屬性過濾,或者需將關系返回時,需為關系命名。示例如下:
c)查找所有出演“老炮兒”電影的人
可以通過冒號和關系類型對其加以指定。示例如下:
2.2 OPTIONAL MATCH
(1)簡介
OPTIONAL MATCH 和 MATCH 一樣用于對圖數據進行檢索。兩者的區(qū)別在于,對于找不到的匹配項 OPTIONAL MATCH 會用 null 代替。注意,與不加 OPTIOANAL 關鍵字時的查詢做比較會更容易理解 OPTIONAL 關鍵字的作用。
(2)可選模式
查找人物“安圣基”和與其有關系的話劇,若話劇不存在就用 null 替代。示例如下:
(3)可選元素的屬性
查找人物“安圣基”和與其有關系的話劇,并返回“安圣基”和話劇的名字,若話劇名不存在,則用 null替代。示例如下:
(4)可選關系類型和命名
查找人物“安圣基”和與其存在“出演話劇”關系的實體,并返回“安圣基”和該關系 ,若“出演話劇”關系不存在,則使用 null 替代。示例如下:
2.3 RETURN
(1)簡介
RETURN用于指定查詢結果返回的部分。
(2)返回節(jié)點
查找并返回“安圣基”。示例如下:
(3)返回關系
查找并返回“安圣基”的一跳“出演電影”關系。示例如下:
(4)返回屬性
查找并返回“安圣基”的姓名屬性。示例如下:
(5)返回所有元素
查找“安圣基”存在關系一跳路徑,并返回所有實體。示例如下:
2.4 WITH
(1)簡介
WITH 用于向后面的語句傳遞指定結果,并可以改變結果集中實體的形式和數量。注意,WITH 會影響查詢結果集里的變量,WITH 語句外的變量不會傳遞到后續(xù)查詢中。
(2)處理查詢結果并往后傳遞
a)查詢五部評分最高的電影,并查找與這五部電影有關系的人物
示例如下:
b)查找所有電影的平均評分,并查詢評分為該平均分的電影
示例如下:
2.5 UNWIND
(1)簡介
UNWIND用于將任何列表變回單獨的行。這些列表可以是傳入的參數,先前編輯的 collect 結果或其他列表表達式。注意UNWIND 需要指定一個新的名稱。
(2)展開列表
將文字列表轉換為以x命名的行并返回。示例如下:
2.6 WHERE
(1)簡介
WHERE 用于為 MATCH,OPTIONAL MATCH 和 WITH 語句添加過濾條件。
(2)基本用法
a)查找電影“頭文字D”,并返回它
示例如下:
b)可選查找人物類型的點,并返回它
示例如下:
c)查找評分大于8的電影,并返回它們的名字和評分
示例如下:
2.7 ORDER BY
(1)簡介
ORDER BY用于對結果進行排序。
(2)根據屬性排序
查找所有人物節(jié)點,并按人物姓名屬性字典序順序返回人物姓名,出生年份。示例如下:
2.8 SKIP
(1)簡介
SKIP用于跳過指定行數RETURN、WITH的結果。
(2)跳過前三行
查找所有人物節(jié)點,跳過前三個人,從第四個人開始返回其姓名。示例如下:
2.9 LIMIT
(1)簡介
LIMIT用于保留指定行數RETURN、WITH的結果。
(2)返回部分結果
查找所有人物節(jié)點,并返回年齡最大的前三個人。示例如下:
2.10 CREATE
(1)簡介
CREATE 用于創(chuàng)建節(jié)點,關系或者路徑。
(2)創(chuàng)建節(jié)點
a)創(chuàng)建一個人物類型節(jié)點
示例如下:
b)創(chuàng)建一個姓名為“香取慎吾”的人物節(jié)點
示例如下:
c)創(chuàng)建一個姓名為“香取慎吾”的人物節(jié)點,并返回它
示例如下:
(3)創(chuàng)建關系
a)在人物“安圣基”和電影“甲方乙方”間創(chuàng)建一個關系“出演電影”,并返回該關系
示例如下:
(4)創(chuàng)建完整路徑
a)創(chuàng)建人物“長妻樹里”出演電影“十二生肖”,人物“香取慎吾”導演電影“十二生肖”的路徑
單獨使用 CREATE 創(chuàng)建整個模式時,模式中所有的節(jié)點和關系都會被創(chuàng)建。示例如下:
(5)創(chuàng)建新類型
a)創(chuàng)建新的點類型
示例如下:
b)創(chuàng)建新的關系類型
示例如下:
2.11 DELETE
(1)簡介
DELETE用于刪除節(jié)點和關系。注意,刪除節(jié)點前需先刪除與該節(jié)點有關聯(lián)的所有邊。
(2)刪除單個節(jié)點
查找到姓名為’香取慎吾’的人物節(jié)點并刪除。示例如下:
(3)刪除節(jié)點及其所有關系?刪除人物“香取慎吾”及其所有相關聯(lián)的關系。
示例如下:
(4)僅刪除關系?刪除所有以香取慎吾為起始節(jié)點的“出演電影”關系。
示例如下:
2.12 SET
(1)簡介
SET 用于設置節(jié)點和關系的屬性。注意,在Galaxybase中,主鍵屬性(外部唯一標識)在創(chuàng)建以后不能修改和刪除。
(2)設置屬性
查找人物“矢本悠馬”,將其籍貫屬性改成日本,并返回他的籍貫。示例如下:
(3)刪除屬性
查找人物“品冠”,移除他的籍貫屬性。示例如下:
2.13 REMOVE
(1)簡介
REMOVE用于移除節(jié)點和關系的屬性。
(2)刪除屬性
查找人物“溫崢嶸”,刪除他的籍貫屬性。示例如下:
2.14 FOREACH
(1)簡介
FOREACH用于遍歷并操作集合元素。
(2)標記路徑上的所有節(jié)點
查找5個人物節(jié)點,將其放入集合,然后將集合內所有人物點出生年份設置為“1979”。示例如下:
2.15 MERGE
(1)簡介
MERGE用于保證元素一定存在,作用為查詢節(jié)點和邊,若查不到就創(chuàng)建該節(jié)點和邊。
(2)合并(MERGE)使用
a)查找人物“安圣基”,若未找到就創(chuàng)建人物“安圣基”,并返回他的姓名
示例如下:
b)查找人物“安圣基”和電影“無間道”,再查找他們之間“出演電影”的關系,若找不到該關系,則創(chuàng)建該關系,并返回它們
示例如下:
c)查找電影“無間道”,若未找到就創(chuàng)建電影“無間道”,并設置它的評分屬性為7,然后返回該電影
示例如下:
d)查找電影“無間道”,若找到該電影就設置它的評分屬性為7,若未找到就創(chuàng)建電影“無間道”,然后返回該電影
示例如下:
e)查找電影“無間道”,若找到該電影就設置它的評分屬性為7,若未找到就創(chuàng)建電影“無間道”,并設置它的評分屬性為8,然后返回該電影
示例如下:
2.16 CALL[...YIELD]
(1)簡介
CALL 語句用于調用數據庫中的內置過程(Procedure),內置過程類似于關系型數據庫中的存儲過程,是一組完成特定功能的方法。
(2)使用 CALL 調用內置過程
a)調用數據庫內置過程查詢數據庫中所有的點類型
示例如下:
也可以使用命名空間和名字調用過程,示例如下:
b)使用字面值作為參數調用內置過程查詢兩點間最短路徑
示例如下:
c)使用查詢參數作為參數調用內置過程查詢兩點間最短路徑
示例如下:
d)調用內置過程并將結果綁定變量
示例如下:
e)調用內置過程并過濾結果
示例如下:
2.17 UNION
(1)簡介
UNION 用于將兩個或多個查詢的結果合并為一個結果集,該結果集中包含所有進行合并操作的行。
(2)合并兩個查詢并保留重復項
查找人物“安圣基”和人物“楚源”,并將結果合并后返回他們的姓名。示例如下:
(3)合并兩個查詢并刪除重復項
查找人物“安圣基”和人物“楚源”,并將結果合并后返回他們的姓名。示例如下:
2.18 LOAD CSV
(1)簡介
LOAD CSV用于將CSV文件加載至Cypher語句中。 company.csv 文件如下:
(2)LOAD CSV支持四種URL:http, https, ftp, file
注意:在 Galaxybase 數據庫中 LOAD CSV 文件并使用 CREATE 語句創(chuàng)建的節(jié)點和關系類型必須已經在 schema 預設過(Galaxybase 不允許使用 CREATE 語句直接創(chuàng)建新的節(jié)點和關系實體) 通過以下四種方式加載 CSV 文件:
3. Cypher 高級特性
本節(jié)會對Cypher高級特性索引,查詢調優(yōu),執(zhí)行計劃做一個基本闡述,若想深入了解Cypher高級特性,可以訪問 Galaxybase Cypher官方使用文檔。
Galaxybase Cypher官方使用文檔:https://galaxybase.com/document?file=dev&docid=13
3.1 索引
數據庫索引是數據庫中某些數據的冗余副本,以增加存儲空間和較慢的寫入為代價的,使相關數據的搜索更加高效。因此決定要建立索引的內容和不建立索引的內容是一項重要且通常不容易的任務。
想要快速查找評分為某一值或為某范圍值內的電影,可以對電影類型的評分屬性建立索引,建立完成后可以使用評分屬性快速查找電影類型點,圖數據庫會自動應用創(chuàng)建的索引。
(1)創(chuàng)建電影類型評分屬性的索引
請注意,該索引不是立即可用的,而是將在后臺創(chuàng)建。示例如下:
(2)查看索引
使用 Call 方法查看所有索引,索引的狀態(tài)為 online 表示索引創(chuàng)建成功,可以使用。
(3)使用索引進行查找
使用索引需使用建立索引的類型和屬性進行查找,示例如下:
3.2 查詢調優(yōu)
(1)查詢分析模式?
當希望通過查看查詢的執(zhí)行計劃來分析查詢時,有兩種模式可供選擇:
EXPLAIN?如果想查看執(zhí)行計劃但不運行該語句,請在 Cypher 語句前加上 EXPLAIN。 該語句將始終返回空結果,并且不對數據庫進行任何更改。
PROFILE?如果要運行該語句并查看那些執(zhí)行計劃執(zhí)行的細節(jié),請在 Cypher 語句前加上 PROFILE。 這將運行語句,并跟蹤每個執(zhí)行計劃輸入輸出的行數,以及每個執(zhí)行計劃與存儲層進行了多少次交互以獲取必要的數據。 請注意,使用 PROFILE 對查詢進行性能分析會占用更多資源。因此,除非正在做查詢性能分析,否則最好不要使用。
注意:在查詢中明確地指出節(jié)點和關系的類型,將會使 Galaxybase 使用更準確的統(tǒng)計信息,從而制定性能更好的執(zhí)行計劃。也就是說,當知道節(jié)點或者關系只能是某種類型時,應該將其添加到查詢中。在關系的開始節(jié)點和結束節(jié)點上聲明類型可以幫助 Galaxybase 找到執(zhí)行語句的最佳方式。
(2)調優(yōu)示例
假設我們想要查找籍貫為“中國香港”的人物節(jié)點,性能不理想的 Cypher 是這樣寫:
該查詢將找到所有籍貫為“中國香港”的節(jié)點,但是隨著數據庫中節(jié)點數量地增加,它會變得越來越慢。通過分析查詢,可以找到性能不佳原因。
使用PROFILE模式查看此次執(zhí)行細節(jié),自底向上開始閱讀。

從最后一行開始,我們注意到的第一件事是, “Rows” 列中的值似乎很高。 如果查看 “Operator” 列,我們將看到已使用?AllNodesScan,這意味著查詢計劃程序已掃描數據庫中的所有節(jié)點。
因此,我們查找到了許多非人物類型的節(jié)點,這些都不是我們想要的點的類型,因此上訴方法似乎不是一個高效的查找方法。解決此問題的方法是,每當我們尋找節(jié)點時,都應指定類型以幫助查詢計劃器縮小搜索空間。 對于此查詢,我們需要添加一個人物類型。

可以看到,此次查詢的執(zhí)行細節(jié)中,最后一行的 “Rows” 值減小了,是因為此次查詢我們不再掃描那些非人物類型的節(jié)點。NodeByLabelScan?運算符表明,我們首先通過對數據庫中的所有人物類型節(jié)點進行線性掃描來實現(xiàn)此目的。完成之后,我們再次使用?Filter?運算符過濾這些人物類型節(jié)點,比較每個節(jié)點的籍貫屬性。
在某些情況下,這可能是可以接受的,但是如果我們要經常按籍貫查找人,那么,如果在人物類型的籍貫屬性上創(chuàng)建索引,就會看到更好的效果:
待索引創(chuàng)建完成后,再次運行查詢

可以看到執(zhí)行計劃?NodeIndexSeek?運算符的 “Rows” 值變成了366,通過執(zhí)行索引快速的找到了籍貫為“中國香港”的人物節(jié)點。
3.3 執(zhí)行計劃
(1)概述
執(zhí)行計劃定義
執(zhí)行查詢的任務被分解為多個操作,每個操作都執(zhí)行特定的工作。 操作組合成一個樹狀結構,稱為執(zhí)行計劃。 執(zhí)行計劃中的每個操作都表示為樹中的一個節(jié)點。 每個操作將零個或多個行作為輸入,并產生零個或多個行作為輸出。 這意味著一個操作的輸出將成為下一個操作的輸入。執(zhí)行計劃中兩個分支的操作將來自兩個傳入流的輸入合并,產生單個輸出。
執(zhí)行模型
執(zhí)行計劃的評估從樹的葉節(jié)點開始。葉節(jié)點沒有輸入行,通常由諸如掃描和查找之類的操作符組成。這些操作符直接從存儲引擎獲取數據,從而導致數據庫命中。葉子節(jié)點生成的任何行都將被管道輸送到它的父節(jié)點,然后父節(jié)點又將自身輸出行輸送到它們的父節(jié)點,以此類推,一直到根節(jié)點。根節(jié)點生成查詢的最終結果。
操作類型
執(zhí)行計劃操作分為兩種類型,一種是流式操作,另一種是全量操作。查詢操作通常是流式的:大多數操作開始產生部分行結果后,都會立刻將其通過管道傳遞給其父操作。這意味著子操作在父操作開始使用由子操作產生的輸入行時可能還未全完執(zhí)行完畢。
但是,某些操作(例如用于聚合和排序的操作)需要先匯總所有行,然后才能向父操作傳遞。在將任何行發(fā)送給其父級作為輸入之前,此類操作需要完整地完成執(zhí)行。這些操作稱為“全量操作”,全量可能導致較高的內存使用率,從而導致查詢性能問題。
統(tǒng)計信息
每個操作都帶有統(tǒng)計信息。
?Rows
操作生成的行數。只有使用 PROFILE 模式執(zhí)行 Cypher 時才有意義。
?EstimatedRows
這是操作符預期生成的估計行數。這個估計值是基于現(xiàn)有統(tǒng)計信息的近似數字。編譯器使用此估計來選擇合適的執(zhí)行計劃。
?DbHits
每個操作符都會要求 Galaxybase 存儲引擎執(zhí)行檢索或更新數據之類的工作。數據庫命中是存儲引擎工作的一個抽象單元。觸發(fā)數據庫命中的操作在數據庫命中 (DbHits) 中列出。
(2)數據庫命中
每個操作將向存儲引擎發(fā)送一個請求,以執(zhí)行檢索或更新數據等工作。數據庫命中是存儲引擎工作的一個抽象單元。以下列出能觸發(fā)一個或多個數據庫命中的所有操作:
?創(chuàng)建操作
創(chuàng)建一個節(jié)點;創(chuàng)建一個關系;創(chuàng)建一個新的點類型;創(chuàng)建一個新的關系類型;創(chuàng)建一個新的屬性。
?刪除操作
刪除一個節(jié)點;刪除一個關系。
?節(jié)點特定操作
使用 elementId 獲取一個節(jié)點;獲取節(jié)點的度;獲取節(jié)點的類型;獲取節(jié)點的屬性。
?關系特定操作
使用 elementId 獲取一個關系;獲取關系的屬性;獲取關系的類型。
?通用操作
通過ID獲取屬性名稱,或者通過鍵名獲取屬性鍵的ID;通過索引查找或索引掃描找到節(jié)點或關系;使用可變路徑方式查詢路徑;找到最短路徑;查詢節(jié)點和關系的統(tǒng)計數量。
?Schema 操作
添加索引;丟棄索引;獲取索引的引用。
?調用 procedure 方法
(3)執(zhí)行計劃操作
本節(jié)列舉了部分執(zhí)行計劃操作,若想了解執(zhí)行計劃的更多使用細節(jié),可以訪問 Galaxybase Cypher官方使用文檔。
Galaxybase Cypher官方使用文檔:https://galaxybase.com/document?file=dev&docid=13
a)All Nodes Scan
All Nodes Scan 操作符從存儲層讀取所有節(jié)點。 查詢:

b)Directed Relationship By Id Seek
Directed Relationship By Id Seek 操作符通過 elementId 從存儲層讀取一個或多個關系。 查詢:

c)Node By Id Seek
Node By Id Seek 操作符通過 elementId 從存儲層讀取一個或多個節(jié)點。 查詢:

d)Node By Label Scan
Node By Label Scan 操作從存儲層讀取具有特定類型的所有節(jié)點。 查詢:

e)Node Index Seek
Node Index Seek 操作使用索引查找節(jié)點。 查詢:

-END
想了解更多圖數據庫相關知識請在微信搜索【創(chuàng)鄰科技Galaxybase】關注該公眾號!