Neo4j Cypher語法(一)


目錄

Cypher手冊詳解

1 背景

2 唯一性

3 語法

3.1 命名規則

3.2 表達式

3.3 變量與保留關鍵字

3.4 參數

3.5 操作符

3.6 模式

3.7 列表


Cypher手冊詳解

最近在研究知識圖譜,避免不了的涉及到了圖數據庫和圖算法,我們用的圖數據庫是neo4j,對其CQL語法做一個記錄。整篇文章是對官網Cypher手冊的翻譯(正常訪問超級慢,也許要翻牆),同時做了一些刪減,例如地理函數和時間函數,和我的項目關系不大,就沒有學習,對於官網的一些示例加上了結果的截圖和自己的理解,本博文基於Neo4j3.5.3,其余版本可能會報錯。如有錯誤,還麻煩各位大佬指正,非常感謝。

1 背景

什么是neo4j?

Neo4j是一個高性能的,NOSQL圖形數據庫,它將結構化數據存儲在網絡上而不是表中。它是一個嵌入式的、基於磁盤的、具備完全的事務特性的Java持久化引擎,但是它將結構化數據存儲在網絡(從數學角度叫做圖)上而不是表中。Neo4j也可以被看作是一個高性能的圖引擎,該引擎具有成熟數據庫的所有特性。程序員工作在一個面向對象的、靈活的網絡結構下而不是嚴格、靜態的表中--但是他們可以享受到具備完全的事務特性、企業級的數據庫的所有好處。

neo4j的呈現形式:Neo4j中不存在表的概念,只有兩類:節點(Node)和關系(Relation),可以簡單理解為圖里面的點和邊。

在數據查詢中,節點一般用小括號(),關系用中括號[]。

當然也隱含路徑的概念,是用節點和關聯表示的,如:(a)-[r]->(b),表示一條從節點a經關聯r到節點b的路徑。

關系:neo4j中是單向關系,嚴格的來說不具備雙向或者無向的關系。但是merge (a)-[r]-(b)這樣的語句創建的關系可以理解為是雙向的,但是neo4j中比較尷尬的一點是這樣可以理解為無向關系的關系,在web呈現時是帶着單向箭頭的。

屬性:節點和關系都可以具備屬性。

標簽:代表節點的類型,一個節點可以有0個、1個或者多個標簽。

類型:代表關系的類型,一條關系可以有0個或者1個,一條邊不能具有多個type。

2 唯一性

在模式匹配時,neo4j確保不會在單個模式中多次找到相同圖形關系的匹配。舉例,在尋找朋友的朋友時,不會返回所述用戶自身。

CREATE (adam:User { name: 'Adam' }),(pernilla:User { name: 'Pernilla' }),(david:User { name: 'David'}),(adam)-[:FRIEND]->(pernilla),(pernilla)-[:FRIEND]->(david) 

尋找Adam朋友的朋友

MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-()-[r2:FRIEND]-(friend_of_a_friend)

RETURN friend_of_a_friend.name AS fofName

返回David

因為r1和r2在同一個模式中,又是不同的變量名,所以不會返回同一條關系,即圖形中的有向邊。檢驗:在兩個子句中用不同的變量名就不管用

MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend)

MATCH (friend)-[r2:FRIEND]-(friend_of_a_friend)

RETURN friend_of_a_friend.name AS fofName

但是只要在一個模式中,即使拆分了多個子模式也不會匹配到同一關系,如下所示。

MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend),(friend)-[r2:FRIEND]-(friend_of_a_friend)

RETURN friend_of_a_friend.name AS fofName

3 語法

3.1 命名規則

必須以字母開頭,不能以數字開頭。

節點標簽:駝峰式命名,關系類型:全大寫命名。

3.2 表達式

十進制、十六進制:0x13ff,0xFCA39

八進制整數文字:01372、02127

字符串、bool類型

屬性:n.prop、x.prop、rel.thisProperty

動態屬性: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)

聚合函數,路徑模式

正則表達式:a.name =~ 'Tim.*'

字符串匹配:

surname STARTS WITH 'Sven',

surname ENDS WITH 'son' or a.surname CONTAINS 'son'

CASE表達式

3.2.1 字符串常用的轉義序列

\t Tab鍵 \b 后退鍵 \n 新起一行 \r 回車符 \f 制表符 \’ 單引號 \’’雙引號

\\ 反斜杠的轉義

3.2.2 CASE表達式

計算表達式,並按順序與WHEN子句進行比較,直到找到匹配項。 如果未找到匹配項,則返回ELSE子句中的表達式。 但是,如果沒有ELSE情況且未找到匹配項,則返回null。

CASE test

 WHEN value THEN result

  [WHEN ...]

  [ELSE default]

END

 

建表語句:

create (A:Person {name:'Alice', eyes:"brown",age:38}),

(B:Person {name:"Bob", eyes:"blue", age:25}),

(C:Person {name:"Charlie", eyes:'green',age:53}),

(D:Person {name:"Daniel", eyes:'brown'}),

(E:Person {name:'Eskil',eyes:"blue",age:41,array:['one','two','three']}),

(A)-[:KNOWS]->(B),

(A)-[:KNOWS]->(C),

(B)-[:KNOWS]->(D),

(C)-[:KNOWS]->(D),

(B)-[:MARRIED]->(E)

測試語句1:

MATCH (n:Person)
RETURN n.name,
CASE n.eyes
WHEN 'blue'
THEN 1
WHEN 'brown'
THEN 2
ELSE 3 END AS result

測試語句2:

MATCH (n:Person)
RETURN n.name,
CASE
WHEN n.eyes = 'blue'
THEN 1
WHEN n.age < 40
THEN 2
ELSE 3 END AS result

測試語句3:

我們看到建表語句中,存在一些節點時沒有age屬性的,我們希望返回一個age_10_years_ago的值,假設不存在age屬性,將該值返回-1。我們按照如下的方式來試寫查詢語句,期望對於Daniel返回-1,因為他不具備age屬性。但是並不如意:

MATCH (n:Person)
RETURN n.name,
CASE n.age
WHEN n.age IS NULL THEN -1
ELSE n.age - 10 END AS age_10_years_ago

原因:n.age是一個整型,而n.age IS NULL是一個bool值,所以不會走到WHEN n.age IS NULL THEN -1這個對應的分支,需要換成如下的寫法:

MATCH (n:Person)
RETURN n.name,
CASE
WHEN n.age IS NULL THEN -1
ELSE n.age - 10 END AS age_10_years_ago

換一種方式理解,就是常用的switch(n.age), 不會等於 n.age is null這個case ,想要返回-1直接寫成如下方式即可。

MATCH (n:Person)
RETURN n.name,
CASE n.age
WHEN NULL THEN -1
ELSE n.age - 10 END AS age_10_years_ago

3.3 變量與保留關鍵字

變量僅在同一查詢部分中可見

變量不會轉移到后續查詢中。 如果使用WITH將多個查詢部分鏈接在一起,則必須在WITH子句中列出變量以將其轉移到下一部分。

保留關鍵字不能用於變量名、函數名、參數。

3.4 參數

Cypher支持使用參數查詢。這意味着開發人員不必使用字符串構建來創建查詢。此外,參數使得Cypher的執行計划緩存更加容易,從而縮短了查詢執行時間。

參數可用於:文字和表達式

節點和關系id

僅用於顯式索引:索引值和查詢

參數不能用於以下構造,因為它們構成了編譯到查詢計划中的查詢結構的一部分:

屬性鍵;所以,MATCH(n)WHERE n.$ param ='something'無效

關系類型

標簽

參數可以包含字母和數字,以及這些參數的任意組合,但不能以數字或貨幣符號開頭。

3.4.1 參數定義

參數僅僅對當前會話有效,網頁刷新變量消失。變量為一個kv的鍵值對。

:param a:1, b:2或者:param {a: 1, b: 2}以這樣的形式來定義參數,注意前面是有冒號的。

MATCH (n:Person)

WHERE n.name = $name

RETURN n

MATCH (n:Person { name: $name })

RETURN n

查看當前的所有參數:

:params

3.4.2 可以使用參數的各種場景

正則表達式:

:param {"regex":".*VM.*"}

match (n:VM) where n.name=~ $regex return n.name

大小寫敏感的字符串匹配

:params { "name" : "Michael"}

MATCH (n:Person)

WHERE n.name STARTS WITH $name

RETURN n.name

創建多個帶屬性帶標簽的節點

:param {"props" : [ {

    "awesome" : true,

    "name" : "Andy",

    "position" : "Developer"

  }, {

    "children" : 3,

    "name" : "Michael",

    "position" : "Developer"

  } ]}

 

UNWIND $props AS properties

CREATE (n:Person)

SET n = properties

RETURN n

判斷某個變量在或者不在變量列表中

:param "ids" : [ 0, 1, 2 ]

//判斷變量在列表中,如何判斷變量不在對應的列表中?not in會報錯,<>達不到想要的結果

MATCH (n)

WHERE id(n) IN $ids

RETURN n.name

//判斷變量不存在於列表中

match(n:VM) where size([l in [id(n)] where l in $ids ])=0 return n

調用函數

:param "value" : "Michaela"

START n=node:people(name = $value)

RETURN n

3.5 操作符

3.5.1 使用[]

來訪問動態計算的屬性鍵 對多個屬性鍵來進行共同篩選

CREATE (a:Restaurant { name: 'Hungry Jo', rating_hygiene: 10, rating_food: 7 }),(b:Restaurant { name: 'Buttercup Tea Rooms', rating_hygiene: 5, rating_food: 6 }),(c1:Category { name: 'hygiene' }),(c2:Category { name: 'food' })

WITH a, b, c1, c2

MATCH (restaurant:Restaurant),(category:Category)

WHERE restaurant["rating_" + category.name]> 6

RETURN DISTINCT restaurant.name

3.5.2 ^完成指數運算

3.5.3字符串判斷

STARTS WITH       ENDS WITH  CONTAINS

3.5.4 使用in進行更加復雜的列表成員操作

RETURN [2, 1] IN [1,[2, 1], 3] AS inList 會return true。

RETURN [1, 2] IN [1, 2] AS inList  會return false 這里的in不是判斷認為兩個是整體,而是將左邊作為一個整體元素,判斷左邊是否為右邊的子元素

如下查詢可以用於判斷llhs是否至少包含一個也存在於lrhs中的元素

MATCH (n)//判斷當前庫中的所有節點,有哪些的標簽是Person或者Employee

WHERE size([l IN labels(n) WHERE l IN ['Person', 'Employee'] | 1]) > 0

RETURN count(n)

3.5.5 用[]獲取列表元素

WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names
RETURN names[1..3] AS result

這里的方括號是左閉右開的,

所以會返回[‘John’,‘Bill’]

和C語言一樣//表示對應的注釋

3.6 模式

模式和模式匹配時Cypher的核心,有效使用Cypher需要對模式有一個正確的理解。

最為簡單的模式就是一個雙括號括上一個變量名,例如(a) a就是一個變量名

(a)-->(b)

(a)-->(b)<--(c)這樣的一系列的節點和關系稱之為路徑

可以在模式中描述的最簡單的屬性稱之為標簽(a:User)-->(b)   同時可以描述具備多個標簽的節點(a:User:Admin)-->(b)

3.6.1 指定屬性

對於MERGE子句,屬性將用作任何現有數據必須具有的形狀的附加約束(指定的屬性必須與圖中的任何現有數據完全匹配)。 如果未找到匹配的數據,則MERGE的行為類似於CREATE,並且將在新創建的節點和關系中設置屬性。

3.6.2 關系的模式

類似於節點的標簽,對於關系來說叫做類型,但是和節點標簽不同的是,關系的類型僅僅只有一種。如果我們想要描述一些數據,使得這種關系可以有一組類型中的任何一種,那么它們都可以在模式中列出,用管道符號將它們分開。像這樣(但是僅僅適用於match,不適用於Create和merge):

(a)-[r:TYPE1|TYPE2]->(b)

關系名稱通常也可以省略

3.6.3 變量長度的模式匹配

在模式的關系描述中指定長度來進行對應的描述

(a)-[*2]->(b)  等價於  (a)-->()-->(b)

(a)-[*3..5]->(b)這一關系是左閉右閉,即包含3個關系、4個關系、5個關系

(a)-[*3..]->(b)    (a)-[*..5]->(b)

需要特別注意的一點是,即使關系是單向的,在如下的語句中,--表示不考慮關系的方向,仍然會反向查找找出走一個關系或者兩個關系的節點。

MATCH (me)-[:KNOWS*1..2]-(remote_friend)

WHERE me.name = 'Filipa'

RETURN remote_friend.name

3.7 列表

RETURN range(0, 10) as list ,range(0, 10)[3] as result//將列表中下標索引為3的元素也就是第4個元素返回

與Python不同的是 這里的range是左閉右閉的,即一個列表中有11個元素

range(0, 10)[-3]//倒數第三個元素

RETURN range(0, 10)[0..3]//左閉右開

RETURN range(0, 10)[-5..]或者[..4]//只有在list中的a..b是左閉右開的,路徑長度的匹配與range范圍中的a..b都左閉右閉的。

//也可以理解為返回倒數5個元素的列表和正數4個元素的列表

RETURN size(range(0, 10)[0..3])//size函數的返回結果是3

3.7.1 列表推導

RETURN [x IN range(0,10) WHERE x % 2 = 0 | x^3] AS result//這里的豎線不是或,而是管道

MATCH (a:Person { name: 'Charlie Sheen' })

RETURN [(a)-->(b) WHERE b:Movie | b.year] AS years

3.8 映射

Cypher堅定地支持映射,對map的處理不太理解。

3.9 使用null

Cypher中的null表示缺失或未定義的值,null並不等於null,不知道的兩個值並不意味着它們相等 ,所以null=null會拋出null而不是true

null IN [1, 2, 3]  

null IN [1, null, 3] 

null in [] 

如果使用null來做列表切片的首尾索引值,那么返回值也是null。

原文地址:https://blog.csdn.net/weixin_42348333/article/details/89758617


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM