Neo4j Cypher語法(三)


目錄

5 函數

5.1 謂詞函數

5.2 標量函數

5.3 聚合函數

5.4 列表函數

5.5 數學函數

5.6 字符串函數

5.7 Udf與用戶自定義函數

6 模式

6.1 索引

6.2 限制

7 查詢調優

7.1 Cypher查詢選項

7.2 基礎查詢調優示例

7.3 索引值與順序

8 執行計划

8.1 執行計划的操作符

8.2 最短路徑規划


5 函數

如果輸入參數作為null,則Cypher中的函數返回null

將字符串作為輸入的函數都在Unicode字符上操作,而不是在標准char[]上操作。例如,size(s),其中s是中文字符,也會返回1。

5.1 謂詞函數

這些函數官網原文叫predicate function,翻譯過來就是謂詞函數,對於為什么要這么叫我也覺得不是很能理解,在上世紀5 60年代,知識圖譜前身的RDF,進行的推理中,就包含了本體推理和規則推理。規則推理中,最基礎的就是所謂的一階謂詞邏輯,個人認為所謂的謂詞大概就是簡單的邏輯關系的判斷吧。

all()、any()、exists()、none()、single()

這些預測函數都是bool類型,對於給定的非空輸入返回true or false。它們最常用於過濾掉查詢的where部分中的子圖。

 

all():對所有元素都滿足條件返回true,否則返回false。

建表語句見Neo4j Cypher語法(一)3.2.2case表達式。

MATCH p =(a)-[*1..3]->(b)

WHERE a.name = 'Alice' AND b.name = 'Daniel' AND ALL (x IN nodes(p) WHERE x.age > 30)

RETURN p

該語句的意思是找到一條從Alice可以走到Daniel的路徑,要求路徑上的每一個節點的age都大於30,包括起始和終止的Alice和Daniel節點,但是回顧建表語句可知,Daniel節點時不具備age屬性的,所以這條查詢語句不會返回結果。

any():在給定列表中有一個元素滿足對應子句即可。

none():如果在給定的元素列表中沒有元素滿足對應條件,返回真值。

MATCH p =(n)-[*1..3]->(b)

WHERE n.name = 'Alice' AND NONE (x IN nodes(p) WHERE x.age = 25)

RETURN p

該查詢語句的作用是找到一條或多條路徑,這條路徑的起始節點和終止節點經過1條、2條或者3條邊的距離,這條路徑上的所有節點,對於x.age=25(這里的=符號和其余編程語言中的邏輯等==是一樣的,不是我們理解的賦值)這個條件都會返回false。根據下方的列表和連通圖來看,從Alice出發,要求年齡不等於25,那么和Bob相連的所有邊都會被切斷。這里還有一點要稍微注意的是,由於Daniel節點沒有設置age屬性,即Daniel.age會返回null值,這里的null值既不是true也不是false,所以Daniel節點也不會在返回結果中

返回結果:

為驗證我們剛才的判斷,手動給Daniel設置一個不等於25的age屬性。

match (n:Person{name:'Daniel'}) set n.age=37

再執行剛才的match語句,結果發生了變化,現在Daniel節點肯定是包含於路徑的,如后續想刪除屬性可使用remove語句:

single() :如果在給定列表中,僅僅一個元素滿足預測條件/篩選條件,則返回真。

5.2 標量函數

length():對路徑使用length()

id():返回某個節點或者關系的id,即下圖中使用尖括號括起來的內置屬性,在創建節點或者關系時會自動創建。

match(n:Person{name:'Eskil'}) return id(n)

size():對字符串、列表和模式表達式使用size()

coalesce():返回表達式列表的第一個非空值

:param {a:[null,1]}

return coalesce($a[0],$a[1]) as res

EndNode():返回關系中的結束節點 startNode()

Head():返回列表中的第一個元素。

Last():返回列表中的最后一個元素。

properties():以映射形式返回對應的屬性

match(n:Person{name:'Eskil'}) return properties(n)

Type():返回關系的類型

timestamp():返回毫秒級時間戳

toBoolean():將字符串類型轉換為Bool類型

RETURN toBoolean('TRUE'), toBoolean('not a boolean')

toFloat():將整型或者字符串轉換為浮點類型。除非有特定的需求,個人不建議在存屬性時使用這兩個函數。因為一旦使用這兩個函數入庫,后續如果要進行屬性判斷,也要寫成這種形式:match (n) where n.age =toInteger(25),這樣一是復雜。而是屬性多了之后記不住自己最初轉換了什么類型

toInteger():將字符串或者浮點類型轉換為整型

5.3 聚合函數

聚合函數采用一組值並計算它們的聚合值。示例是avg(),用於計算多個數值的平均值,或min(),用於查找一組值中的最小數值或字符串值。當我們在下面說聚合函數對一組值進行操作時,我們的意思是這些是將內部表達式(例如n.age)應用於同一聚合組中的所有記錄的結果。

可以在所有匹配的子圖上計算聚合,或者可以通過引入分組鍵來進一步划分聚合。這些是非聚合表達式,用於對進入聚合函數的值進行分組。

舉例:

Return n,count(*)

我們有兩個返回表達式:n和count(*)。第一個,n,不是聚合函數,因此它將是分組鍵。后者count(*)是一個聚合表達式。匹配的子圖將根據分組鍵分為不同的桶。然后,聚合函數將在這些桶上運行,計算每個桶的聚合值。

要使用聚合對結果集進行排序,聚合必須包含在要在ORDER BY中使用的RETURN中。

DISTINCT運算符與聚合一起使用。它用於在通過聚合函數運行它們之前使所有值唯一。

avg() - Numeric values

MATCH (n:Person)

RETURN avg(n.age)

collect() 返回列表

MATCH (n:Person)
RETURN collect(n.age)

count() count(*)返回計數 

max()

MATCH (n:Person)

RETURN max(n.age)

min() UNWIND [1, 'a', NULL , 0.2, 'b', '1', '99'] AS val //返回的是1的字符類型,判斷的是ascii碼值?

RETURN min(val)

UNWIND ['d',[1, 2],['a', 'c', 23]] AS val

RETURN min(val)//返回的是['a','c',23]

percentileCont()  //這兩個方法沒太看懂,還是先記錄一下吧

MATCH (n:Person)
RETURN percentileCont(n.age, 0.4)

//返回屬性年齡值的第40個百分位數,使用加權平均值計算。 在這種情況下,0.4是中位數,或40%。

percentileDisc()  

MATCH (n:Person)
RETURN percentileDisc(n.age, 0.5)

stDev() MATCH (n)

WHERE n.name IN ['A', 'B', 'C']

RETURN stDev(n.age)//返回標准差,除的是n-1

stDevP() 返回除n的標准差

5.4 列表函數

keys() //keys返回一個列表,其中包含節點,關系或映射的所有屬性名稱的字符串表示形式。這對於json數據也可以直接使用

MATCH (a)

WHERE a.name = 'Alice'

RETURN keys(a)

labels()

MATCH (a)

WHERE a.name = 'Alice'

RETURN labels(a)

nodes()

MATCH p =(a)-->(b)-->(c)

WHERE a.name = 'Alice' AND c.name = 'Eskil'

RETURN nodes(p)//返回在路徑上的所有節點

range()

與Python的range不同,是左閉右閉的

reduce() MATCH p =(a)-->(b)-->(c)

WHERE a.name = 'Alice' AND b.name = 'Bob' AND c.name = 'Daniel'

RETURN reduce(totalAge = 0, n IN nodes(p)| totalAge + n.age) AS reduction//對列表中的所有元素代入表達式 |管道符右側為表達式

relationships() //返回路徑中包含的所有關系的列表 [:KNOWS[0]{},:MARRIED[4]{}] 這里的0和4代表了什么,暫時還不清楚

MATCH p =(a)-->(b)-->(c)

WHERE a.name = 'Alice' AND c.name = 'Eskil'

RETURN relationships(p)

reverse() 返回逆序列表

tail() //返回去除掉第一個元素的列表

5.5 數學函數

abs() ceil() floor() 絕對值、向上取整、向下取整

rand() 返回[0,1)的隨機數

round() 四舍五入

sign() 將正數、負數和0映射為1、-1、0

e() 返回2.71828

exp() log() e的n次方 自然對數:以e為底的對數

log10() sqrt() 其余三角函數自行查詢手冊

5.6 字符串函數

left() RETURN left('hello', 3)//自左邊起的3個字符

lTrim() 去除掉字符串左邊的空格

replace() RETURN replace("hello", "l", "w")//返回hewwo

reverse() 字符串逆序

right() 與left相對

rTrim() 去除掉字符串右邊的空格

split() RETURN split('one,two', ',')

substring() RETURN substring('hello', 1, 3), substring('hello', 2)//ell llo

toLower()、toString()、toUpper()  

trim() 刪除字符串首尾的空格

5.7 Udf與用戶自定義函數

用戶定義的函數用Java編寫,需要查看apoc的具體用法,部署jar包到數據庫中,並以與任何其他Cypher函數相同的方式調用。

此示例顯示如何從Cypher調用名為join的用戶定義函數。

MATCH (n:Member)

RETURN org.neo4j.function.example.join(collect(n.name)) AS members

用戶定義的聚合函數使用Java編寫,部署到數據庫中,並以與任何其他Cypher函數相同的方式調用。

此示例顯示如何從Cypher調用名為longestString的用戶定義聚合函數。

MATCH (n:Member)

RETURN org.neo4j.function.example.longestString(n.name) AS member

6 模式

6.1 索引

6.1.1 創建單一索引

CREATE INDEX ON :Label(property)

CREATE INDEX ON :Person(firstname)

6.1.2 創建復合索引

CREATE INDEX ON :Person(age, country)

6.1.3 刪除索引

CALL db.indexes //查看對應索引

DROP INDEX ON :Person(firstname)

DROP INDEX ON :Person(age, country) //刪除復合索引

MATCH (p:Person)

WHERE exists(p.firstname)

RETURN p

6.1.4 全文模式索引

索引和全文模式索引的區別在哪里,如何區分?

例如,solr的分詞,就是全文索引的一種?倒排?

之前的常規模式索引只能對字符串進行精確匹配或者前后綴索引(startswith,endswith,contains),全文索引將標記化索引字符串值,因此它可以匹配字符串中任何位置的術語。索引字符串如何被標記化並分解為術語,取決於配置全文模式索引的分析器。

索引是通過屬性來創建,便於快速查找節點或者關系。

創建和配置全文模式索引

使用db.index.fulltext.createNodeIndex和db.index.fulltext.createRelationshipIndex創建全文模式索引。在創建索引時,每個索引必須為每個索引指定一個唯一的名稱,用於在查詢或刪除索引時引用相關的特定索引。然后,全文模式索引分別應用於標簽列表或關系類型列表,分別用於節點和關系索引,然后應用於屬性名稱列表。

應用於多個標簽或多個關系類型的索引稱為多標記索引/多令牌索引。

db.index.fulltext.createNodeIndex and db.index.fulltext.createRelationshipIndex用於創建全文模式索引。

6.1.5 創建、配置與查詢全文模式索引

CREATE (m:Movie { title: "The Matrix" })

RETURN m.title

CALL db.index.fulltext.createNodeIndex("titlesAndDescriptions",["Movie", "Book"],["title", "description"])

//創建了一個復合類型的全文索引之后,對其進行查詢

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", "matrix") YIELD node, score

RETURN node.title, node.description, score

//對關系創建對應的索引

CALL db.index.fulltext.createRelationshipIndex("taggedByRelationshipIndex",["TAGGED_AS"],["taggedByUser"], { analyzer: "url_or_email", eventually_consistent: "true" })

//對全文模式索引進行查詢

除了完全匹配的結果之外,全文索引還會返回給定查詢的近似匹配,lucence的查詢,類似於搜索引擎的查詢方式

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", "Full Metal Jacket") YIELD node, score

RETURN node.title, score

//返回值並不完全是精確匹配,將按照相關度降序排列。

 

完全精確匹配采用如下方式:

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", "\"Full Metal Jacket\"") YIELD node, score

RETURN node.title, score

使用與或的邏輯操作符

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", 'full AND metal') YIELD node, score

RETURN node.title, score

和對應的屬性值進行匹配

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", 'description:"surreal adventure"') YIELD node, score

RETURN node.title, node.description, score

 

6.2 限制

6.2.1 唯一性約束/主鍵約束

Create unique表示在創建時避免重復創建

Unique約束類似於數據庫的第一范式,即主鍵約束的記錄唯一性。

應該使用一些數據庫約束來創建節點或關系的一個或多個屬性的規則。

創建唯一性約束的語法:

CREATE CONSTRAINT ON (<label_name>)

ASSERT <property_name> IS UNIQUE

具體實例:

CREATE CONSTRAINT ON (cc:CreditCard)

ASSERT cc.number IS UNIQUE

6.2.2 刪除唯一性約束

DROP CONSTRAINT ON (cc:CreditCard)

ASSERT cc.number IS UNIQUE

查看庫中的限制:

CALL db.constraints

7 查詢調優

7.1 Cypher查詢選項

Cypher查詢計划程序將每個查詢轉換為執行計划。 執行計划告訴Neo4j在執行查詢時要執行哪些操作。

Neo4j使用基於成本的執行計划策略(稱為“成本”計划程序):Neo4j中的統計服務用於為替代計划分配成本並選擇最成本最低的計划。

Explain:僅查看執行計划但是並不運行該語句

PROFILE:概要。如果要運行語句並查看哪些運算符正在執行大部分工作,請使用PROFILE。這將運行您的語句並跟蹤每個運算符傳遞的行數,以及每個運算符需要與存儲層交互以檢索必要數據的程度

7.2 基礎查詢調優示例

//導入電影的csv並且在導入時創建屬性,且避免創建重復節點,實現冪等效果

LOAD CSV WITH HEADERS FROM 'file:///movies.csv' AS line

MERGE (m:Movie { title: line.title })

ON CREATE SET m.released = toInteger(line.released), m.tagline = line.tagline

LOAD CSV WITH HEADERS FROM 'file:///actors.csv' AS line

MATCH (m:Movie { title: line.title })

MERGE (p:Person { name: line.name })

ON CREATE SET p.born = toInteger(line.born)

MERGE (p)-[:ACTED_IN { roles:split(line.roles, ';')}]->(m)

LOAD CSV WITH HEADERS FROM 'file:///directors.csv' AS line

MATCH (m:Movie { title: line.title })

MERGE (p:Person { name: line.name })

ON CREATE SET p.born = toInteger(line.born)

MERGE (p)-[:DIRECTED]->(m)

此時需要尋找叫做Tom hanks的演員,

7.2.1 最初始的做法

MATCH (p { name: 'Tom Hanks' })

RETURN p

在之前加上profile來進行查詢,可以查看查詢計划

 

可見全表掃描,很低效的方法

7.2.2 加標簽

PROFILE MATCH (p:Person { name: 'Tom Hanks' }) RETURN p

效率提高不少,整體的數據庫命中數也減少了一半

 

NodeByLabelScan運算符指示我們通過首先對數據庫中的所有Person節點進行線性掃描來實現此目的。

完成后我們再次使用Filter運算符掃描所有節點,比較每個節點的name屬性。

在某些情況下這可能是可以接受的,但如果我們要經常按名稱查找人員,那么如果我們在Person標簽的name屬性上創建索引,我們會看到更好的性能:

7.2.3 加索引

 

7.3 索引值與順序

7.3.1 高級查詢調優示例

CALL db.awaitIndexes

CALL db.indexes

//尋找Tom開頭的演員出演的電影

//擁有索引支持的屬性查找

PROFILE

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)

WHERE p.name STARTS WITH 'Tom'

RETURN p.name, count(m)

在neo4j3.5中,我們可以利用索引存儲屬性值的事實。在這種情況下,意味着可以直接從索引中查找名稱,允許Cypher避免第二次掃庫來查找屬性。

根據上圖可知neo4j緩存了對應的索引值。

改變查詢語句,不再使用where的過濾語句。

PROFILE

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)

RETURN p.name, count(m)

此時不再使用索引緩存而是掃庫機制

可以用於優化的過濾語句如下:

Existance (WHERE exists(n.name))

Equality (e.g. WHERE n.name = 'Tom Hanks')

Range (eg. WHERE n.uid > 1000 AND n.uid < 2000)

Prefix (eg. WHERE n.name STARTS WITH 'Tom')

Suffix (eg. WHERE n.name ENDS WITH 'Hanks')

Substring (eg. WHERE n.name CONTAINS 'a')

//索引支持的order by(優化語句)

//可見下左,在一開始的節點索引階段就具備了

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)

WHERE p.name STARTS WITH 'Tom'

RETURN p.name, count(m)

ORDER BY p.name

//改變查詢,換一種方式來使用索引

//可見下右,直到sort階段才有order by的操作。

PROFILE

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)

USING INDEX p:Person(name)

WHERE exists(p.name)

RETURN p.name, count(m)

ORDER BY p.name

 

總結:對於排序order by而言,不能夠使用exists來做優化

排序可使用的過濾語句如下:

Equality (e.g. WHERE n.name = 'Tom Hanks')

Range (eg. WHERE n.uid > 1000 AND n.uid < 2000)

Prefix (eg. WHERE n.name STARTS WITH 'Tom')

Suffix (eg. WHERE n.name ENDS WITH 'Hanks')

Substring (eg. WHERE n.name CONTAINS 'a')

7.4 計划程序提示與USING關鍵字

在為查詢構建執行計划時,計划程序提示用於影響計划程序的決策,使用using關鍵字在查詢中指定計划程序提示。

強制規划器行為是一項高級功能,會導致性能下降,應該謹慎使用。

8 執行計划

8.1 執行計划的操作符

8.2 最短路徑規划

規划Cypher的最短路徑可能會導致不同的查詢計划,具體取決於需要評估的過濾條件。Neo4j默認使用快速雙向廣度優先搜索算法。

如果廣搜未獲得結果,neo4j可能不得不求助於較慢的窮舉深度優先搜索算法來查找路徑,

8.2.1 最短路徑的快速算法

MATCH (ms:Person { name: 'Martin Sheen' }),(cs:Person { name: 'Charlie Sheen' }), p = shortestPath((ms)-[:ACTED_IN*]-(cs))

WHERE ALL (r IN relationships(p) WHERE exists(r.role))

RETURN p

8.2.2 較慢的深搜作為后續算法

MATCH (cs:Person { name: 'Charlie Sheen' }),(ms:Person { name: 'Martin Sheen' }), p = shortestPath((cs)-[*]-(ms))

WHERE length(p)> 1

RETURN p

更詳盡的詳盡查詢計划的工作方式是使用Apply / Optional來確保當快速算法找不到任何結果時,生成空結果而不是簡單地停止結果流。 除此之外,規划器將發出一個AntiConditionalApply,如果路徑變量指向null而不是路徑,它將運行窮舉搜索。

在(i)cypher.forbid_exhaustive_shortestpath設置為true,以及(ii)快速算法無法找到最短路徑的情況下,ErrorPlan運算符將出現在執行計划中。

8.2.3 阻止慢深搜作為后備

MATCH (cs:Person { name: 'Charlie Sheen' }),(ms:Person { name: 'Martin Sheen' }), p = shortestPath((cs)-[*]-(ms))

WITH p//with子句即意味着不包含深搜算法

WHERE length(p)> 1

RETURN p

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


免責聲明!

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



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