- Neo4j權威指南 (圖數據庫技術叢書)
- 張幟
- 5188字
- 2020-11-28 15:15:52
3.2 基本語法
本節主要描述Cypher查詢語言的基本語法。
3.2.1 類型
Cypher處理的所有值都有一個特定的類型,它支持如下類型:
● 數值型
● 字符串
● 布爾型
● 節點
● 關系
● 路徑
● 映射(Map)
● 列表(List)
在Cypher語句中,大多數類型的值都可以使用字面值表達式(參見“3.2.2表達式”小節)。在使用null的時候要特別注意,因為null是任何類型的值(參見“3.2.9空值”小節)。節點、關系和路徑可以作為模式匹配的返回結果。
提示
標簽(label)不是值,它只是模式匹配的一種語法形式。
3.2.2 表達式
3.2.2.1 概述
Cypher中的表達式如下:
● 十進制(整型和雙精度型)的字面值:13、-4000、3.14、6.022E23。
● 十六進制整型字面值(以0x開頭):0x13zf、0xFC3A9、-0x66eff。
● 八進制整型字面值(以0開頭):01372、02127、 -05671。
● 字符串字面值:'Hello'、"World"。
● 布爾字面值:true、false、TRUE、FALSE。
● 變量:n、x、rel、myFancyVariable、`A name with weird stuff in it[]! `。
● 屬性:n.prop、x.prop、rel.thisProperty 、myFancyVariable. `(weird property name)`。
● 動態屬性:n["prop"]、rel[n.city + n.zip]、map[coll[0]]。
● 參數:$param、$0
● 表達式列表:['a', 'b']、[1, 2, 3]、['a', 2, n.property, $param] 、[ ]。
● 函數調用:length(p)、nodes(p)。
● 聚合函數:avg(x.prop)、count(*)。
● 路徑-模式:(a)-->()<--(b)。
● 計算式:1 + 2 and 3 < 4。
● 返回true或者false的斷言表達式:a.prop = 'Hello'、length(p) >10、exists(a.name)。
● 正則表達式:a.name =~ 'Tob.*'。
● 大小寫敏感的字符串匹配表達式:a.surname STARTS WITH 'Sven'、a.surname ENDS WITH 'son' or a.surname CONTAINS 'son'。
● CASE表達式。
3.2.2.2 轉義字符
Cypher中的字符串可以包含的轉義字符如表3-1所示。
表3-1 Cypher中的字符串可以包含的轉義字符

3.2.2.3 Case表達式
Cypher支持Case條件表達式,它類似于其他語言中的if/else語句。
1.簡單的Case表達式
計算表達式的值,然后依次與WHEN語句中的表達式進行比較,直到匹配上為止。如果未匹配上,則ELSE中的表達式將作為結果。如果ELSE語句不存在,那么將返回null。
語法
CASE test WHEN value THEN result [WHEN ...] [ELSE default] END
參數
● test:一個有效的表達式。
● value:一個表達式,它的結果將與test表達式的結果進行比較。
● result:如果value表達式能夠與test表達式匹配,它將作為結果表達式。
● default:沒有匹配的情況下的默認返回表達式。
查詢
MATCH (n) RETURN CASE n.eyes WHEN 'blue' THEN 1 WHEN 'brown' THEN 2 ELSE 3 END AS result
結果

2.一般的Case表達式
按順序判斷斷言,直到找到一個為true,然后對應的結果被返回。如果沒有找到,就返回ELSE的值。如果沒有ELSE語句,則返回null。
語法
CASE WHEN predicate THEN result [WHEN ...] [ELSE default] END
參數
● predicate:判斷的斷言,以找到一個有效的可選項。
● result:如果predicate匹配到,result就作為結果表達式。
● default:沒有匹配到情況下,默認返回表達式。
查詢
MATCH (n) RETURN CASE WHEN n.eyes = 'blue' THEN 1 WHEN n.age < 40 THEN 2 ELSE 3 END AS result
結果

3.2.3 變量
當需要引用模式(Pattern)或者查詢某一部分的時候,可以對其進行命名。針對不同部分的這些命名被稱為變量。
例如:
MATCH (n)-->(b) RETURN b
這里的n和b就是變量。
變量名是區分大小寫的。它可以包含下劃線、字母(a~z、A~Z)和數字(0~9),但必須以字母開頭。如果變量名中需要用到其他字符,可以用反向單引號(`)將變量名括起來。比如,如果變量名中包含特殊字符μ,則可以按如下方式使用:
match(`μg`:food) return `μg`
變量的命名規則同樣也適用于屬性的命名。
提示
變量僅在同一個查詢內可見。它不能被用于后續的查詢。如果有WITH連接起來的多個查詢部分,變量必須列在WITH語句中才能應用到后續部分。詳細參見“3.3.18 WITH”小節。
3.2.4 參數
Cypher支持帶參數的查詢,這意味著開發人員不是必須用字符串來構建查詢。此外,這也讓執行計劃的緩存更容易。
參數能夠用于WHERE語句中的字面值和表達式,START語句中的索引值、索引查詢以及節點和關系的id。參數不能用于屬性名、關系類型和標簽,因為這些模式(Pattern)將作為查詢結構的一部分被編譯進查詢計劃。
合法的參數名是字母、數字以及兩者的組合。下面是一個使用參數的完整例子。參數以JSON格式提供,具體如何提交它們取決于所使用的驅動程序。
3.2.4.1 字符串
參數
{ "name" : "Johan" }
可以有兩種查詢方式來使用參數,如下:
查詢方式1
MATCH (n) WHERE n.name = $name RETURN n
查詢方式2
MATCH (n { name: $name }) RETURN n
3.2.4.2 正則表達式
參數
{ "regex" : ".*h.*" }
查詢
MATCH (n) WHERE n.name =~ $regex RETURN n.name
3.2.4.3 大小寫敏感的字符串模式匹配
參數
{ "name" : "Michael" }
查詢
MATCH (n) WHERE n.name STARTS WITH $name RETURN n.name
3.2.4.4 創建帶有屬性的節點
參數
{ "props" : { "name" : "Andres", "position" : "Developer" } }
查詢
CREATE ($props)
3.2.4.5 創建帶有多個屬性的多個節點
參數
{
"props" : [ {
"awesome" : true,
"name" : "Andres",
"position" : "Developer"
}, {
"children" : 3,
"name" : "Michael",
"position" : "Developer"
} ]
}
查詢
UNWIND $props AS properties CREATE (n:Person) SET n = properties RETURN n
3.2.4.6 設置節點的所有屬性
注意:這將替換當前的所有屬性。
參數
{ "props" : { "name" : "Andres", "position" : "Developer" } }
查詢
MATCH (n) WHERE n.name='Michaela' SET n = $props
3.2.4.7 SKIP和LIMIT
參數
{ "s" : 1, "l" : 1 }
查詢
MATCH (n) RETURN n.name SKIP $s LIMIT $l
3.2.4.8 節點id
參數
{ "id" : 0 }
查詢
MATCH (n) WHERE id(n)= $id RETURN n.name
3.2.4.9 多個節點id
參數
{ "ids" : [ 0, 1, 2 ] }
查詢
MATCH (n) WHERE id(n) IN $ids RETURN n.name
3.2.5 運算符
3.2.5.1 數學運算符
數學運算符包括+、-、*、/、%和^。
3.2.5.2 比較運算符
比較運算符包括=、<>、<、>、<=、>=、IS NULL和IS NOT NULL。
3.2.5.3 布爾運算符
布爾運算符包括AND、OR、XOR和NOT。
3.2.5.4 字符串運算符
連接字符串的運算符為+,正則表達式的匹配運算符為=~。
3.2.5.5 列表運算符
列表的連接也可以通過+運算符,可以用IN來檢查列表中是否存在某個元素。
3.2.5.6 屬性運算符
提示
Cypher 2.0版本以后,之前存在的屬性運算符“? ”和“! ”已經被移除了。這個語法不再支持。對于不存在的屬性將返回null。如果真的還需要?運算符的功能,可以使用(NOT(has(<ident>.prop)) OR <ident>.prop=<value>)。使用“? ”表達可選關系也被移除了,取而代之的是OPTINAL MATCH。
3.2.5.7 值的相等與比較
Cypher支持使用=和<>來比較兩個值的相等/不相等關系,同類型的值只有它們是同一個值的時候才相等,如3 = 3和"x" <> "xy"。
只有兩個Map的鍵相同且指向的值也相等的時候它們才相等。對于列表來說,只有它們包含相等值的相同序列的時候才相等,如[3, 4] = [1+2, 8/2]。
不同類型的值在比較相等的時候遵循以下規則:
● 路徑可看作是一些節點和關系的列表,它等于所有包含相同序列節點和關系的所有列表。
● 對任何值測試是否 = 和 <> null都將返回null,這包括null = null和null <> null。唯一可靠地測試一個值是否為null的方法是使用IS NULL或者IS NOT NULL。
不同類型之間不能相互比較。特別地,節點、關系和映射之間不能相互比較。
3.2.5.8 值的排序與比較
比較運算符<=、<(升序)和>=、>(降序)可以用于值排序的比較,如下所示。
● 數字型值的排序比較采用數字順序。
● java.lang.Double.NaN大于所有值。
● 字符串排序的比較采用字典順序。如"x" < "xy"。
● 布爾值的排序遵循false < true。
● 當有個參數為null的時候,比較結果為null,如null < 3的結果為null。
● 將其他類型的值相互比較進行排序將報錯。
3.2.5.9 鏈式比較運算
比較運算可以被任意地聯結在一起,如x < y <= z等價于x < y AND y <= z。
正式地,如果a, b, c, …, y, z是表達式,op1, op2, …, opN是比較運算符,這時,a op1 b op2 c … y opN z等價于a op1 b and b op2 c and … y opN z。
例如:
MATCH (n) WHERE 21 < n.age <= 30 RETURN n
等價于:
MATCH (n) WHERE 21 < n.age AND n.age <= 30 RETURN n
該查詢將匹配年齡介于21和30之間的所有節點。
3.2.6 注釋
Cypher語言的注釋類似其他語言,用雙斜線//來注釋行,例如:
MATCH (n) RETURN n //這是行末尾注釋 MATCH (n) //這是整行注釋 RETURN n MATCH (n) WHERE n.property = '//這不是注釋’ RETURN n
3.2.7 模式(Patterns)
模式和模式匹配是Cypher非常核心的部分。要高效地使用Cypher必須深入理解模式。
使用模式可以描述你期望看到的數據的形狀。例如,在MATCH語句中,當用模式描述一個形狀的時候,Cypher將按照模式來獲取相應的數據。
模式描述數據的形式很類似在白板上畫出圖的形狀。通常用圓圈來表達節點,使用箭頭來表達關系。
模式在MATCH、CREATE和MERGE等語句中都會出現,后續章節會詳細描述。
3.2.7.1 節點模式
模式能表達的最簡單的形狀就是節點。節點使用一對圓括號表示,然后中間含一個名字。例如:
(a)
這個模式描述了一個節點,其名稱使用變量a表示。
3.2.7.2 關聯節點的模式
模式可以描述多個節點及其之間的關系。Cypher使用箭頭來表達兩個節點之間的關系。例如:
(a)-->(b)
這個模式描述了一個非常簡單的數據形狀,即兩個節點和從其中一個節點到另外一個節點的關系。兩個節點分別命名為a和b,關系是有方向的,從a指向b。
這種描述節點和關系的方式可以擴展到任意數量的節點和它們之間的關系,例如:
(a)-->(b)<--(c)
這一系列相互關聯的節點和關系被稱為路徑(Path)。
注意:節點的命名僅僅當后續的模式或者Cypher查詢中需要引用時才需要。如果不需要引用,則命名可以省略。例如:
(a)-->()<--(c)
3.2.7.3 標簽
模式除了可以描述節點之外,還可以用來描述標簽。比如:
(a:User)-->(b)
也可以描述一個節點的多個標簽,如:
(a:User:Admin)-->(b)
3.2.7.4 指定屬性
節點和關系是圖的基礎結構。Neo4j的節點和關系都可以有屬性,這樣可以建立更豐富的模型。屬性在模式中使用鍵值對的映射結構來表達,然后用大括號包起來。例如,一個有兩個屬性的節點如下所示。
(a {name: 'Andres', sport: 'Brazilian Ju-Jitsu'})
關系中的屬性如下所示。
(a)-[{blocked: false}]->(b)
當模式中有屬性時,它實際上為數據增加了額外的約束。在CREATE語句中,屬性會被增加到新創建的節點和關系中。在MERGE語句中,屬性將作為一個約束去匹配數據庫中的數據是否存在該屬性。如果沒有匹配到,這時MERGE的行為將與CREATE一樣,即屬性將被設置到新創建的節點和關系中。
提示
模式在CREATE語句中支持使用單個參數來指定屬性。例如:CREATE (node$paramName)。但這在其他語句中是不行的,因為Cypher在編譯查詢的時候需要知道屬性的名稱,以便能夠高效地匹配。
3.2.7.5 描述關系
如前面的例子所示,可以用箭頭簡單地描述兩個節點之間的關系。它描述了關系的存在性和方向性。但如果不關心關系的方向,則箭頭的頭部可以省略。例如:
(a)--(b)
與節點類似,如果后續需要引用到該關系,則可以給關系賦一個變量名。變量名需要用方括號括起來,放在箭頭的短橫線中間,如下所示。
(a)-[r]->(b)
就像節點有標簽一樣,關系可以有類型(Type)。給關系指定類型,如下所示。
(a)-[r:REL_TYPE]->(b)
不像節點可以有多個標簽,關系只能有一個類型。但如果所描述的關系可以是一個類型集中的任意一種類型,可以將這些類型都列入模式中,它們之間以豎線“|”分割,例如:
(a)-[r:TYPE1|TYPE2]->(b)
注意:這種模式僅適用于描述已經存在的數據(如在MATCH語句中),而在CREATE或者MERGE語句中是不允許的,因為一個關系不能創建多個類型。
與節點類似,關系的命名也是可以省略的,例如:
(a)-[:REL_TYPE]->(b)
與使用一串節點和關系來描述一個長路徑的模式不同,很多關系(以及中間的節點)可以采用指定關系的長度的模式來描述,例如:
(a)-[*2]->(b)
它描述了一張三個節點和兩個關系的圖。這些節點和關系都在同一條路徑中(路徑的長度為2)。它等同于:
(a)-->()-->(b)
關系的長度也可以指定一個范圍,這被稱為可變長度的關系,例如:
(a)-[*3..5]->(b)
關系的長度最小值為3,最大值為5。它描述了一個或者有4個節點和3個關系,或者5個節點4個關系,或者6個節點和5個關系連在一起的圖組成的一條路徑。
長度的邊界也是可以省略的,如描述一個路徑長度大于等于3的路徑:
(a)-[*3..]->(b)
路徑長度小于等于5的路徑,例如:
(a)-[*..5]->(b)
兩個邊界都可以省略,這允許任意長度的路徑,例如:
(a)-[*]->(b)
來看一個簡單的查詢例子:
查詢
MATCH (me)-[:KNOWS*1..2]-(remote_friend) WHERE me.name = 'Filipa' RETURN remote_friend.name
結果

這個查詢用于找到符合這個模式的數據:即指定一個節點(name屬性值為‘Filipa')和與它關系為KNOWS的一步和兩步的節點。這是一個查詢一度和二度人脈的典型例子。
提示
變長關系不能用于CREATE和MERGE語句。
3.2.7.6 賦值給路徑變量
如上所述,連接在一起的一系列節點和關系被稱為路徑。Cypher允許使用標識符給路徑命名,例如:
p= (a)-[*3..5]->(b)
在MATCH中,CREAT和MERGE語句中可以這樣做,但當模式作為表達式的時候不能這樣。
3.2.8 列表
Cypher對列表(List)有很好的支持。
3.2.8.1 概述
可以使用方括號和一組以逗號分割的元素來創建一個列表。
查詢
RETURN [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] AS list
結果

在下面的例子中使用了range函數。它指定了列表包含元素的開始數字和結束數字。范圍的兩端也是被包含在內的,例如:
查詢
RETURN range(0, 10)
結果

可以使用方括號[]訪問列表中的元素。
查詢
RETURN range(0, 10)[3]
結果

索引也可以為負數,這時訪問的方向將從列表的末尾作為開始點。
查詢
RETURN range(0, 10)[-3]
結果

也可以在[]中指定列表返回指定范圍的元素。它將提取開始索引到結束索引的值,但不包含結束索引所對應的值。如下面例子中,開始索引為0,結束索引為3,結果0,1,2索引對應的值被返回,但結束索引3對應的值未返回。
查詢
RETURN range(0, 10)[0..3]
結果

查詢
RETURN range(0, 10)[0..-5]
結果

查詢
RETURN range(0, 10)[-5..]
結果

查詢
RETURN range(0, 10)[..4]
結果

提示
如果返回一個范圍的索引值越界了,那么返回直接從越界的地方進行截斷。如果是單個元素的索引值越界,則返回null。
查詢
RETURN range(0, 10)[5..15]
結果

查詢
RETURN range(0, 10)[15]
結果

可以用size函數獲取列表的長度,例如:
查詢
RETURN size(range(0, 10)[0..3])
結果

3.2.8.2 List推導式
List推導式(Comprehension)是Cypher中基于已經存在的列表創建一個列表的語法構造。它遵循數學上的集合,代替使用映射和過濾函數。
查詢
RETURN [x IN range(0,10) WHERE x % 2 = 0 | x^3] AS result
結果

如果希望分別地過濾或者映射,WHERE部分或者表達式部分都是可以省略的。
查詢
RETURN [x IN range(0,10) WHERE x % 2 = 0] AS result
結果

查詢
RETURN [x IN range(0,10)| x^3] AS result
結果

3.2.8.3 模式推導式
模式推導式是Cypher基于模式匹配的結果創建列表的一種語法構造。模式推導式將像一般的MATCH語句那樣去匹配模式,斷言部分與一般的WHERE語句一樣,但它將產生一個指定的定制投射。
查詢
MATCH (a:Person { name: 'Charlie Sheen' }) RETURN [(a)-->(b) WHERE b:Movie | b.year] AS years
結果

整個斷言,包括WHERE關鍵字都是可選的,可以被省略。
3.2.8.4 字面值映射
Cypher也可以構造映射。通過REST接口可以獲取JSON對象。在Java中對應的是java.util.Map<String, Object>。
查詢
RETURN { key: 'Value', listKey: [{ inner: 'Map1' }, { inner: 'Map2' }]}
結果

3.2.8.5 Map投射
Cypher支持一個名為“map projections”的概念。它使得基于已有的節點、關系和其他map值來構建map變得容易。
Map投射以指向圖實體的且用逗號分隔的變量簇開頭,并包含以{}包括起來的映射元素,語法如下:
map_variable {map_element, [, …n]}
一個map元素投射一個或多個鍵值對到map投射。這里有4種類型的map投射元素:
● 屬性選擇器——投射屬性名作為鍵,map_variable中對應鍵的值作為鍵值。
● 字面值項——來自任意表達式的鍵值對,如key: <expression>。
● 變量選擇器——投射一個變量,變量名作為鍵,變量的值作為投射的值。它的語法只有變量。
● 全屬性選擇器——投射來自map_variable中的所有鍵值對。
提示
如果map_variable的值指向一個null,那么整個map投射將返回null。
投射舉例
找到Charlie Sheen和返回關于他和他參演過的電影。這個例子展示了字面值項類型的map投射,反過來它還在聚合函數collect()中使用了map投射。
查詢
MATCH (actor:Person { name: 'Charlie Sheen' })-[:ACTED_IN]->(movie:Movie) RETURN actor { .name, .realName, movies: collect(movie { .title, .year })}
結果

找到演過電影的所有演員,并顯示他們所參演電影的數量。這個例子用一個變量來代表數量,使用變量選擇器來投射值,如下所示。
查詢
MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie) WITH actor, count(movie) AS nrOfMovies RETURN actor { .name, nrOfMovies }
結果

還是以“Charlie Sheen”為例,此時返回該節點的所有屬性。這里使用了全屬性選擇器來投射所有的節點屬性和一個額外的顯式投射的age屬性。因為此屬性在該節點不存在,所以投射的值為null。
查詢
MATCH (actor:Person { name: 'Charlie Sheen' }) RETURN actor { .*, .age }
結果

3.2.9 空值
3.2.9.1 空值介紹
空值null在Cypher中表示未找到或者未定義。從概念上講,null意味著“一個未找到的未知值”。對待null會與其他值有些不同,例如從節點中獲取一個并不存在的屬性將返回null。大多數以null作為輸入的表達式將返回null。這包括WHERE語句中用于斷言的布爾表達式。
null不等于null,兩個未知的值并不意味著它們是同一個值。因此,null = null返回null而不是true。
3.2.9.2 空值的邏輯運算
邏輯運算符包括AND、OR、XOR、IN、NOT,把null當作未知的三值邏輯值,AND、OR和XOR的邏輯值表如表3-2所示。
表3-2 空值與AND、OR和XOR的邏輯值表

3.2.9.3 空值與IN
IN運算符遵循類似的邏輯。如果列表中存在某個值,結果就返回true;如果列表包含null值并且沒有匹配到值,結果返回null;否則結果為false。表3-3給出一些例子。
表3-3 空值與IN運算符的例子

All、any、none和single與IN類似,如果可以確切地計算結果,將返回true或者false;否則將返回null。
3.2.9.4 返回空值的表達式
● 從列表中獲取不存在的元素:[][0], head([])。
● 試圖訪問節點或者關系的不存在的屬性:n.missingProperty。
● 與null做比較:1 < null。
● 包含null的算術運算:1 + null。
● 包含任何null參數的函數調用:sin(null)。