neo4j中文文檔-入門指南
Neo4j v4.4
許可:知識共享 4.0
neo4j
Neo4j 是世界領先的圖形數據庫。該架構旨在優化管理、存儲和遍歷節點和關系。圖數據庫采用屬性圖方法,這對遍歷性能和操作運行時都有好處。
**Cypher **
Cypher 是 Neo4j 的圖形查詢語言,允許用戶從圖形數據庫中存儲和檢索數據。它是一種聲明式的、受 SQL 啟發的語言,用於使用 ASCII 藝術語法描述圖形中的視覺模式。語法提供了一種視覺和邏輯方式來匹配圖中節點和關系的模式。Cypher 旨在讓每個人都易於學習、理解和使用,而且還融合了其他標准數據訪問語言的強大功能。
本指南的內容
Neo4j 入門指南涵蓋以下領域:
- 開始使用 Neo4j — 如何開始使用 Neo4j。
- 圖數據庫概念 -圖數據庫概念介紹。
- Cypher 簡介 — 圖查詢語言 Cypher 簡介。
誰應該讀這個?
本指南是為正在探索 Neo4j 和 Cypher 的任何人編寫的。
開始使用 Neo4j
關於如何安裝 Neo4j 以及如何開始運行 Cypher 查詢,有許多選項。
1. 安裝 Neo4j
設置使用 Neo4j 和 Cypher 開發應用程序的環境的最簡單方法是使用 Neo4j Desktop。從https://neo4j.com/download/下載 Neo4j Desktop,然后按照您操作系統的安裝說明進行操作。
有關如何開始使用 Neo4j 和 Cypher 的更多選項,請參閱https://neo4j.com/try-neo4j/。
2. 文檔
所有官方文檔都可以在https://neo4j.com/docs/ 獲得。
在這里您可以找到完整的手冊,例如:
The Cypher Refcard 是學習和編寫 Cypher 時的寶貴兒准確的資料
此外,您可以找到更專業的文檔以及 API 文檔和舊 Neo4j 版本的文檔。
圖數據庫概念
Neo4j 使用屬性圖數據庫模型。
圖數據結構由可以通過關系連接的節點(離散對象)組成。
示例 1. 圖結構的概念。
具有三個節點(圓圈)和三個關系(箭頭)的圖。
Neo4j 屬性圖數據庫模型包括:
- 節點描述域的實體(離散對象)。
- 節點可以有零個或多個標簽來定義(分類)它們是什么類型的節點。
- 關系描述了源節點和目標節點之間的連接。
- 關系總是有一個方向(一個方向)。
- 關系必須有一個類型(一種類型)來定義(分類)它們是什么類型的關系。
- 節點和關系可以具有進一步描述它們的屬性(鍵值對)。
在數學中,圖論是對圖的研究。在圖論中:節點也稱為頂點或點。關系也稱為邊、鏈接或線。
1. 示例圖
下面的示例圖,介紹了屬性圖的基本概念:
示例 2. 示例圖。
示例 3. 密碼。
要創建示例圖,請使用 Cypher 子句CREATE
。
CREATE (:Person:Actor {name: 'Tom Hanks', born: 1956})-[:ACTED_IN {roles: ['Forrest']}]->(:Movie {title: 'Forrest Gump'})<-[:DIRECTED]-(:Person {name: 'Robert Zemeckis', born: 1951})
2.節點
節點用於表示域的實體(離散對象)。
最簡單的圖是沒有關系的單個節點。考慮下圖,由單個節點組成。
示例 4. 節點。
節點標簽是:
Person
Actor
屬性是:
name: Tom Hanks
born: 1956
可以使用 Cypher 使用查詢創建節點:
CREATE (:Person:Actor {name: 'Tom Hanks', born: 1956})
3. 節點標簽
標簽通過將節點分組(分類)到集合中來塑造域,其中具有特定標簽的所有節點都屬於同一集合。
例如,所有代表用戶的節點都可以用標簽來標記User
。有了它,您就可以讓 Neo4j 僅在您的用戶節點上執行操作,例如查找具有給定名稱的所有用戶。
由於可以在運行時添加和刪除標簽,因此它們還可用於標記節點的臨時狀態。一個Suspended
標簽可以用來表示已暫停的銀行賬戶,並且Seasonal
標簽可以表示蔬菜目前在季節。
一個節點可以有零到多個標簽。
在該示例圖中,節點的標簽,Person
,Actor
,和Movie
,用於描述(分類)的節點。可以添加更多標簽來表示數據的不同維度。
下圖顯示了多個標簽的使用。
示例 5. 多個標簽。
4. 關系
關系描述了源節點和目標節點之間的連接如何相關。節點可能與自身有關系。
關系:
- 連接源節點和目標節點。
- 有一個方向(一個方向)。
- 必須有一個類型(一種類型)來定義(分類)它是什么類型的關系。
- 可以有屬性(鍵值對),進一步描述關系。
關系將節點組織成結構,允許圖類似於列表、樹、地圖或復合實體——其中任何一個都可以組合成更復雜、相互關聯豐富的結構。
示例 6. 關系。
節點類型: ACTED_IN
屬性是:
roles: ['Forrest']
performance: 5
該roles
屬性有一個數組值,其中包含單個項目 ( 'Forrest'
)。
可以使用 Cypher 使用查詢創建關系:
CREATE ()-[:ACTED_IN {roles: ['Forrest'], performance: 5}]->()
您必須創建或引用源節點和目標節點才能創建關系。
關系總是有方向的。但是,如果方向沒有用處,則可以忽略該方向。這意味着除非需要正確描述數據模型,否則無需添加相反方向的重復關系。
一個節點可以與它自己有關系。要表達Tom Hanks
KNOWS
他自己將被表達為:
示例 7. 與單個節點的關系。
5. 關系類型
一個關系必須只有一種關系類型。
下面是一個ACTED_IN
關系,隨着Tom Hanks
節點作為源節點和Forrest Gump
作為目標節點。
示例 8. 關系類型。
觀察Tom Hanks
節點有傳出關系,而Forrest Gump
節點有傳入關系。
6. 屬性
屬性是用於存儲節點和關系數據的鍵值對。
屬性的值部分:
- 可以容納不同的數據類型,例如
number
,string
或boolean
。 - 可以保存包含例如字符串、數字或布爾值的同類列表(數組)。
示例 9. 數字
CREATE (:Example {a: 1, b: 3.14})
- 該屬性
a
具有integer
值為的類型1
。 - 該屬性
b
具有float
值為的類型3.14
。
示例 10. 字符串和布爾值
CREATE (:Example {c: 'This is an example string', d: true, e: false})
- 該屬性
c
具有string
值為的類型'This is an example string'
。 - 該屬性
d
具有boolean
值為的類型true
。 - 該屬性
e
具有boolean
值為的類型false
。
示例 11. 列表
CREATE (:Example {f: [1, 2, 3], g: [2.71, 3.14], h: ['abc', 'example'], i: [true, true, false]})
- 該屬性
f
包含一個值為 的數組[1, 2, 3]
。 - 該屬性
g
包含一個值為 的數組[2.71, 3.14]
。 - 該屬性
h
包含一個值為 的數組['abc', 'example']
。 - 該屬性
i
包含一個值為 的數組[true, true, false]
。
有關可用數據類型的詳細說明,請參閱Cypher 手冊 → 值和類型。
7. 遍歷和路徑
遍歷是您查詢圖形以找到問題答案的方式,例如:“我的朋友喜歡哪些音樂但我尚未擁有?”或“如果此電源中斷,哪些 Web 服務會受到影響? ”。
遍歷圖是指按照一定的規則遵循關系來訪問節點。在大多數情況下,只會訪問圖的一個子集。
示例 12. 路徑匹配。
為了根據微型示例數據庫找出湯姆漢克斯出演的電影,遍歷將從Tom Hanks
節點開始,遵循ACTED_IN
連接到節點的任何關系,最后Forrest Gump
得到結果(見虛線):
遍歷結果可以作為長度為 的路徑返回1
:
最短路徑的長度為零。它包含一個節點,沒有關系。
示例 13. 長度為零的路徑。
僅包含單個節點的路徑的長度為0
。
示例 14. 長度為 1 的路徑。
包含一個關系的路徑的長度為1
。
8. 架構
Neo4j 中的模式指的是索引和約束。
Neo4j 通常被描述為schema optional,這意味着沒有必要創建索引和約束。您可以創建數據——節點、關系和屬性——而無需預先定義架構。可以在需要時引入索引和約束,以獲得性能或建模優勢。
9. 索引
索引用於提高性能。要查看如何使用索引的示例,請參閱使用索引。有關如何在 Cypher 中使用索引的詳細說明,請參閱Cypher 手冊 → 索引。
10. 約束
約束用於確保數據符合域的規則。要查看如何使用約束的示例,請參閱使用約束。有關如何在 Cypher 中使用約束的詳細說明,請參閱Cypher 手冊 → 約束。
11.命名約定
節點標簽、關系類型和屬性(關鍵部分)區分大小寫,例如,這意味着屬性與屬性name
不同Name
。
建議使用以下命名約定:
圖實體 | 推薦款式 | 例子 |
---|---|---|
節點標簽 | 駝峰式大小寫,以大寫字符開頭 | :VehicleOwnerrather than :vehice_owner |
關系類型 | 大寫,使用下划線分隔單詞 | :OWNS_VEHICLErather than :ownsVehicle |
財產 | 駝峰小寫,以小寫字符開頭 | firstNamerather than first_name |
具體的命名規則請參考Cypher 手冊→命名規則和建議。
Cypher 簡介
本節將向您介紹圖查詢語言 Cypher。它將幫助您開始思考圖形和模式,將這些知識應用於簡單的問題,並學習如何編寫 Cypher 語句。
有關 Cypher 的完整參考,請參閱Cypher 手冊。
(一)、圖案(Patterns)
Neo4j 的屬性圖由節點和關系組成,其中任何一個都可能具有屬性。節點代表實體,例如概念、事件、地點和事物。關系連接成對的節點。
但是,節點和關系可以被視為低級構建塊。屬性圖的真正優勢在於它能夠對連接節點和關系的模式進行編碼。單個節點或關系通常編碼的信息很少,但節點和關系的模式可以編碼任意復雜的想法。
Neo4j 的查詢語言 Cypher 強烈基於模式。具體來說,模式用於匹配所需的圖形結構。一旦找到或創建了匹配結構,Neo4j 就可以使用它進行進一步處理。
一個簡單的模式,只有一個關系,連接一對節點(或者,偶爾,一個節點到它自己)。例如,一個人 LIVES_IN
是一個城市或一個城市是 PART_OF
一個國家。
復雜模式,使用多重關系,可以表達任意復雜的概念並支持各種有趣的用例。例如,我們可能想要匹配Person LIVES_IN
和 Country 的實例。以下 Cypher 代碼將兩個簡單的模式組合成一個稍微復雜的模式來執行此匹配:
(:Person) -[:LIVES_IN]-> (:City) -[:PART_OF]-> (:Country)
由圖標和箭頭組成的圖表通常用於可視化圖形。文本注釋提供標簽、定義屬性等。
1、節點語法
Cypher 使用一對括號來表示一個節點:()
. 這讓人想起帶有圓形端蓋的圓形或矩形。下面是一些節點示例,提供了不同類型和變量的細節:
()
(matrix)
(:Movie)
(matrix:Movie)
(matrix:Movie {title: 'The Matrix'})
(matrix:Movie {title: 'The Matrix', released: 1997})
最簡單的形式,()
代表一個匿名的、無特征的節點。如果我們想在別處引用該節點,我們可以添加一個變量,例如:(matrix)
。變量僅限於單個語句。它在另一個陳述中可能具有不同的含義或沒有含義。
該:Movie
模式聲明了節點的標簽。這允許我們限制模式,使其不匹配(例如)具有Actor
該位置的節點的結構。
例如title
,節點的屬性表示為鍵值對列表,括在一對大括號內,例如:{name: 'Keanu Reeves'}
。屬性可用於存儲信息和/或限制模式。
2. 關系語法
Cypher 使用一對破折號 ( --
) 表示無向關系。定向關系的一端有一個箭頭 ( <--
, -->
)。括號表達式 ( [...]
) 可用於添加詳細信息。這可能包括變量、屬性和類型信息:
-->
-[role]->
-[:ACTED_IN]->
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ['Neo']}]->
關系的括號對中的語法和語義與節點括號之間使用的語法和語義非常相似。role
可以定義一個變量(例如,role),以便在語句的其他地方使用。關系的類型(例如,:ACTED_IN
)類似於節點的標簽。屬性(例如,roles
)完全等同於節點屬性。
3. 模式語法
結合節點和關系的語法,我們可以表達模式。以下可能是該領域中的一個簡單模式(或事實):
(keanu:Person:Actor {name: 'Keanu Reeves'})-[role:ACTED_IN {roles: ['Neo']}]->(matrix:Movie {title: 'The Matrix'})
相當於節點標簽,:ACTED_IN
模式聲明了關系的關系類型。變量(例如,role
)可以在語句的其他地方使用來指代關系。
如同節點屬性,關系屬性被表示為一對大括號括起來,例如鍵/值對的列表:{roles: ['Neo']}
。在這種情況下,我們為 使用了一個數組屬性roles
,允許指定多個角色。屬性可用於存儲信息和/或限制模式。
4. 模式變量
為了增加模塊化並減少重復,Cypher 允許將模式分配給變量。這允許檢查匹配路徑,用於其他表達式等。
acted_in = (:Person)-[:ACTED_IN]->(:Movie)
該acted_in
變量將包含兩個節點以及找到或創建的每條路徑的連接關系。有多項功能的路徑,例如訪問細節:nodes(path)
,relationships(path)
,和length(path)
。
5. 規則
Cypher 語句通常有多個子句,每個子句執行一個特定的任務,例如:
- 在圖中創建和匹配模式
- 過濾、投影、排序或分頁結果
- 撰寫部分陳述
通過組合 Cypher 子句,我們可以組合更復雜的語句來表達我們想要知道或創建的內容。
模式實踐
1. 創建數據
我們將首先研究允許我們創建數據的子句。
要添加數據,我們只使用我們已經知道的模式。通過提供模式,我們可以指定我們希望將哪些圖形結構、標簽和屬性作為圖形的一部分。
顯然,最簡單的子句稱為CREATE
。它會繼續直接創建您指定的模式。
對於我們目前看到的模式,它可能如下所示:
Cypher
CREATE (:Movie {title: 'The Matrix', released: 1997})
如果我們執行此語句,Cypher 會返回更改的數量,在本例中添加 1 個節點、1 個標簽和 2 個屬性。
Created Nodes: 1
Added Labels: 1
Set Properties: 2
Rows: 0
當我們從一個空數據庫開始時,我們現在有一個包含單個節點的數據庫:
如果我們還想返回創建的數據,我們可以添加一個RETURN
子句,它引用我們分配給模式元素的變量。
Cypher
CREATE (p:Person {name: 'Keanu Reeves', born: 1964})
RETURN p
這是返回的內容:
Created Nodes: 1
Added Labels: 1
Set Properties: 2
Rows: 1
+----------------------------------------------+
| p |
+----------------------------------------------+
| (:Person {name: 'Keanu Reeves', born: 1964}) |
+----------------------------------------------+
如果我們想創建多個元素,我們可以用逗號( , )分隔元素或使用多個CREATE
語句。
我們當然也可以創建更復雜的結構,例如ACTED_IN
與角色信息或DIRECTED
導演信息的關系。
Cypher
CREATE (a:Person {name: 'Tom Hanks', born: 1956})-[r:ACTED_IN {roles: ['Forrest']}]->(m:Movie {title: 'Forrest Gump', released: 1994})
CREATE (d:Person {name: 'Robert Zemeckis', born: 1951})-[:DIRECTED]->(m)
RETURN a, d, r, m
這是我們剛剛更新的圖表部分:
在大多數情況下,我們希望將新數據連接到現有結構。這要求我們知道如何在我們的圖形數據中找到現有的模式,我們將在接下來進行研究。
2. 匹配模式
匹配模式是MATCH
語句的任務。我們傳遞到目前為止使用的相同類型的模式MATCH
來描述我們正在尋找的內容。它類似於query by example,只是我們的例子也包括結構。
一條MATCH
語句將搜索我們指定的模式,並為每個成功的模式匹配返回一行。
為了找到到目前為止我們創建的數據,我們可以開始尋找所有標有Movie
標簽的節點。
Cypher
MATCH (m:Movie)
RETURN m
結果如下:
這應該同時顯示The Matrix和Forrest Gump。
我們也可以找一個特定的人,比如基努里維斯。
Cypher
MATCH (p:Person {name: 'Keanu Reeves'})
RETURN p
此查詢返回匹配的節點:
在這里需要注意的是,我們僅提供足夠的信息來查找節點,並非所有屬性都是必需的。在大多數情況下,您需要查找關鍵屬性,例如 SSN、ISBN、電子郵件、登錄名、地理位置或產品代碼。
我們還可以找到更多有趣的聯系,例如湯姆漢克斯扮演的電影名稱和他扮演的角色。
Cypher
MATCH (p:Person {name: 'Tom Hanks'})-[r:ACTED_IN]->(m:Movie)
RETURN m.title, r.roles
Rows: 1
+------------------------------+
| m.title | r.roles |
+------------------------------+
| 'Forrest Gump' | ['Forrest'] |
+------------------------------+
在這種情況下,我們只返回我們感興趣的節點和關系的屬性。您可以通過點符號在任何地方訪問它們identifer.property
。
當然,這只是列出了他在《阿甘正傳》中作為Forrest 的角色,因為這是我們添加的所有數據。
現在我們知道足以將新節點連接到現有節點,並且可以組合MATCH
並CREATE
附加結構到圖中。
3. 附着結構
為了用新信息擴展圖,我們首先匹配現有的連接點,然后通過關系將新創建的節點附加到它們。將Cloud Atlas添加為Tom Hanks的新電影可以這樣實現:
Cypher
MATCH (p:Person {name: 'Tom Hanks'})
CREATE (m:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (p)-[r:ACTED_IN {roles: ['Zachry']}]->(m)
RETURN p, r, m
以下是數據庫中的結構:
重要的是要記住,我們可以為節點和關系分配變量並在以后使用它們,無論它們是創建的還是匹配的。
可以在單個CREATE
子句中附加節點和關系。為了可讀性,將它們分開是有幫助的。
MATCH
和組合的一個棘手方面CREATE
是我們每個匹配的模式都得到一行。這會導致CREATE
對每一行執行一次后續語句。在許多情況下,這正是您想要的。如果這不是故意的,請將CREATE
語句移到之前MATCH
,或者使用稍后討論的方法更改查詢的基數,或者使用下一個子句的get 或 create語義:MERGE
。
4. 完成模式
每當我們從外部系統獲取數據或不確定圖中是否已經存在某些信息時,我們都希望能夠表達可重復(冪等)的更新操作。在 Cypher 中MERGE
有這個功能。它的作用類似於MATCH
or 的組合CREATE
,它在創建數據之前首先檢查數據是否存在。與MERGE
您一起定義要查找或創建的模式。通常,與MATCH
您一樣,您只想包含要在核心模式中查找的關鍵屬性。 MERGE
允許您提供要設置的其他屬性ON CREATE
。
如果我們不知道我們的圖形是否已經包含Cloud Atlas,我們可以再次將其合並。
Cypher
MERGE (m:Movie {title: 'Cloud Atlas'})
ON CREATE SET m.released = 2012
RETURN m
Created Nodes: 1
Added Labels: 1
Set Properties: 2
Rows: 1
+-------------------------------------------------+
| m |
+-------------------------------------------------+
| (:Movie {title: 'Cloud Atlas', released: 2012}) |
+-------------------------------------------------+
我們在任何兩種情況下都會得到結果:要么是圖中已經存在的數據(可能不止一行),要么是一個新創建的Movie
節點。
其中MERGE
沒有任何先前分配的變量的子句匹配完整模式或創建完整模式。它永遠不會在模式中產生匹配和創建的部分混合。要實現部分匹配/創建,請確保對不應受到影響的部分使用已定義的變量。
因此,最重要的MERGE
是確保您不能創建重復的信息或結構,但這需要首先檢查現有匹配項的成本。特別是在大型圖上,掃描大量標記節點以獲得特定屬性的成本可能很高。您可以通過創建支持索引或約束來緩解其中的一些問題,我們將在稍后討論。但它仍然不是免費的,所以每當你一定不會創建重復數據使用CREATE
了MERGE
。
MERGE
也可以斷言關系只創建一次。為此,您必須從先前的模式匹配中傳入兩個節點。
Cypher
MATCH (m:Movie {title: 'Cloud Atlas'})
MATCH (p:Person {name: 'Tom Hanks'})
MERGE (p)-[r:ACTED_IN]->(m)
ON CREATE SET r.roles =['Zachry']
RETURN p, r, m
如果關系的方向是任意的,您可以不使用箭頭。 MERGE
然后將檢查任一方向的關系,如果未找到匹配關系,則創建新的定向關系。
如果您選擇只傳入前一個子句中的一個節點,MERGE
則會提供一個有趣的功能。然后它只會在給定模式的提供節點的直接鄰域內匹配,如果沒有找到,則創建它。這對於創建例如樹結構非常方便。
Cypher
CREATE (y:Year {year: 2014})
MERGE (y)<-[:IN_YEAR]-(m10:Month {month: 10})
MERGE (y)<-[:IN_YEAR]-(m11:Month {month: 11})
RETURN y, m10, m11
這是創建的圖形結構:
這里沒有對這兩個Month
節點進行全局搜索;僅在2014 Year
節點的上下文中搜索它們。
返回正確的結果
1. 示例圖
首先,我們創建一些數據用於我們的示例:
Cypher
CREATE (matrix:Movie {title: 'The Matrix', released: 1997})
CREATE (cloudAtlas:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (keanu:Person {name: 'Keanu Reeves', born: 1964})
CREATE (robert:Person {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (tom)-[:ACTED_IN {roles: ['Zachry']}]->(cloudAtlas)
CREATE (robert)-[:DIRECTED]->(forrestGump)
這是結果圖:
2. 過濾結果
到目前為止,我們已經在圖中匹配了模式,並且總是返回我們找到的所有結果。現在我們將研究過濾結果的選項,只返回我們感興趣的數據子集。這些過濾條件使用WHERE
子句表示。這個子句允許使用任意數量的布爾表達式,的謂詞,結合AND
,OR
,XOR
和NOT
。最簡單的謂詞是比較;尤其是等於(=)。
Cypher
MATCH (m:Movie)
WHERE m.title = 'The Matrix'
RETURN m
Rows: 1
+------------------------------------------------+
| m |
+------------------------------------------------+
| (:Movie {title: 'The Matrix', released: 1997}) |
+------------------------------------------------+
上面的查詢,使用WHERE
子句,相當於這個查詢,它在模式匹配中包含條件:
Cypher
MATCH (m:Movie {title: 'The Matrix'}) RETURN m
其他選項包括數字比較、匹配正則表達式以及檢查列表中值的存在。
WHERE
以下示例中的子句包括正則表達式匹配、大於比較和用於查看列表中是否存在某個值的測試:
Cypher
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name =~ 'K.+' OR m.released > 2000 OR 'Neo' IN r.roles
RETURN p, r, m
Rows: 1
+-------------------------------------------------------------------------------------------------------------------------------+
| p | r | m |
+-------------------------------------------------------------------------------------------------------------------------------+
| (:Person {name: 'Tom Hanks', born: 1956}) | [:ACTED_IN {roles: ['Zachry']}] | (:Movie {title: 'Cloud Atlas', released: 2012}) |
+-------------------------------------------------------------------------------------------------------------------------------+
一個高級方面是模式可以用作謂詞。在MATCH
擴展匹配模式的數量和形狀的地方,模式謂詞限制當前結果集。它只允許滿足指定模式的路徑通過。正如我們可以預期,采用NOT
只允許路徑傳遞那些不符合指定的模式。
Cypher
MATCH (p:Person)-[:ACTED_IN]->(m)
WHERE NOT (p)-[:DIRECTED]->()
RETURN p, m
Rows: 2
+----------------------------------------------------------------------------------------------+
| p | m |
+----------------------------------------------------------------------------------------------+
| (:Person {name: 'Tom Hanks', born: 1956}) | (:Movie {title: 'Cloud Atlas', released: 2012}) |
| (:Person {name: 'Tom Hanks', born: 1956}) | (:Movie {title: 'Forrest Gump', released: 1994}) |
+----------------------------------------------------------------------------------------------+
返回圖如下:
在這里,我們找到演員,因為他們建立了ACTED_IN
關系,但隨后跳過了DIRECTED
任何電影中的那些演員。
還有更高級的過濾方法,例如列表謂詞,我們將在本節后面討論。
3. 返回結果
到目前為止,我們已經直接通過它們的變量返回了節點、關系和路徑。但是,該RETURN
子句可以返回任意數量的表達式。但是 Cypher 中的表達式是什么?
最簡單的表達式是文字值。文字值的示例包括:數字、字符串、數組(例如:)[1,2,3]
和映射(例如:){name: 'Tom Hanks', born:1964, movies: ['Forrest Gump', ...], count: 13}
。的任何節點,關系或地圖各個屬性可以使用訪問點語法,例如:n.name
。可以使用下標檢索單個元素或數組切片,例如:names[0]
和movies[1..-1]
。每個功能的評價,例如:length(array)
,toInteger('12')
,substring('2014-07-01', 0, 4)
和coalesce(p.nickname, 'n/a')
,也是一個表達式。
WHERE
子句中使用的謂詞算作布爾表達式。
可以組合和連接簡單的表達式以形成更復雜的表達式。
默認情況下,表達式本身將用作列的標簽,在許多情況下,您希望使用expression AS alias
. 隨后可以使用別名來引用該列。
Cypher
MATCH (p:Person)
RETURN
p,
p.name AS name,
toUpper(p.name),
coalesce(p.nickname, 'n/a') AS nickname,
{name: p.name, label: head(labels(p))} AS person
Rows: 3
+-------------------------------------------------------------------------------------------------------------------------------------------------+
| p | name | toUpper(p.name) | nickname | person |
+-------------------------------------------------------------------------------------------------------------------------------------------------+
| (:Person {name: 'Keanu Reeves', born: 1964}) | 'Keanu Reeves' | 'KEANU REEVES' | 'n/a' | {name: 'Keanu Reeves', label: 'Person'} |
| (:Person {name: 'Robert Zemeckis', born: 1951}) | 'Robert Zemeckis' | 'ROBERT ZEMECKIS' | 'n/a' | {name: 'Robert Zemeckis', label: 'Person'} |
| (:Person {name: 'Tom Hanks', born: 1956}) | 'Tom Hanks' | 'TOM HANKS' | 'n/a' | {name: 'Tom Hanks', label: 'Person'} |
+-------------------------------------------------------------------------------------------------------------------------------------------------+
如果我們希望只顯示唯一的結果,我們可以使用DISTINCT
after 關鍵字RETURN
:
Cypher
MATCH (n)
RETURN DISTINCT labels(n) AS Labels
Rows: 2
+------------+
| Labels |
+------------+
| ['Movie'] |
| ['Person'] |
+------------+
4. 匯總信息
在許多情況下,我們希望在遍歷圖中的模式時對遇到的數據進行聚合或分組。在 Cypher 中,聚合發生在RETURN
計算最終結果的子句中。許多常見的聚集功能的支持,例如count
,sum
,avg
,min
,和max
,但也有幾個。
可以通過以下方式計算數據庫中的人數:
Cypher
MATCH (:Person)
RETURN count(*) AS people
Rows: 1
+--------+
| people |
+--------+
| 3 |
+--------+
請注意,NULL
聚合期間會跳過值。要僅聚合唯一值,請使用DISTINCT
,例如:count(DISTINCT role)
。
聚合在 Cypher 中隱式工作。我們指定要聚合的結果列。Cypher 將使用所有非聚合列作為分組鍵。
聚合會影響哪些數據在排序或稍后的查詢部分中仍然可見。
下面的陳述找出了演員和導演一起工作的頻率:
Cypher
MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(director:Person)
RETURN actor, director, count(*) AS collaborations
Rows: 1
+--------------------------------------------------------------------------------------------------------------+
| actor | director | collaborations |
+--------------------------------------------------------------------------------------------------------------+
| (:Person {name: 'Tom Hanks', born: 1956}) | (:Person {name: 'Robert Zemeckis', born: 1951}) | 1 |
+--------------------------------------------------------------------------------------------------------------+
5. 排序和分頁
使用 聚合后進行排序和分頁是很常見的count(x)
。
使用ORDER BY expression [ASC|DESC]
子句進行排序。表達式可以是任何表達式,只要它可以從返回的信息中計算出來。
例如,如果我們返回person.name
我們仍然可以,ORDER BY person.age
因為兩者都可以從person
引用中訪問。我們不能按未退回的東西訂購。這對於聚合和DISTINCT
返回值尤其重要,因為兩者都會消除聚合數據的可見性。
分頁是使用SKIP {offset}
andLIMIT {count}
子句完成的。
一個常見的模式是聚合一個計數(score或frequency),按它排序,然后只返回 top-n 條目。
例如,為了找到我們可以做的最多產的演員:
Cypher
MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
RETURN a, count(*) AS appearances
ORDER BY appearances DESC LIMIT 10
Rows: 1
+---------------------------------------------------------+
| a | appearances |
+---------------------------------------------------------+
| (:Person {name: 'Tom Hanks', born: 1956}) | 2 |
+---------------------------------------------------------+
6. 采集聚合
一個非常有用的聚合函數是collect()
,它將所有聚合值收集到一個列表中。這在許多情況下非常有用,因為在聚合時不會丟失任何細節信息。
collect()
非常適合檢索典型的父子結構,其中每行返回一個核心實體(parent、root或head)及其所有相關信息,這些信息位於用collect()
. 這意味着無需為每個子行重復父信息,也無需運行n+1
語句來分別檢索父行及其子行。
以下語句可用於檢索我們數據庫中每部電影的演員表:
Cypher
MATCH (m:Movie)<-[:ACTED_IN]-(a:Person)
RETURN m.title AS movie, collect(a.name) AS cast, count(*) AS actors
Rows: 2
+-----------------------------------------+
| movie | cast | actors |
+-----------------------------------------+
| 'Forrest Gump' | ['Tom Hanks'] | 1 |
| 'Cloud Atlas' | ['Tom Hanks'] | 1 |
+-----------------------------------------+
創建的列表collect()
可以從使用 Cypher 結果的客戶端使用,也可以直接在具有任何列表函數或謂詞的語句中使用。
編寫復雜語句
1. 示例圖( Example graph)
我們繼續使用與之前相同的示例數據:
Cypher
CREATE (matrix:Movie {title: 'The Matrix', released: 1997})
CREATE (cloudAtlas:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (keanu:Person {name: 'Keanu Reeves', born: 1964})
CREATE (robert:Person {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (tom)-[:ACTED_IN {roles: ['Zachry']}]->(cloudAtlas)
CREATE (robert)-[:DIRECTED]->(forrestGump)
這是結果圖:
2. UNION
如果要合並具有相同結果結構的兩個語句的結果,可以使用 。UNION [ALL]
例如,以下語句同時列出了演員和導演:
Cypher
MATCH (actor:Person)-[r:ACTED_IN]->(movie:Movie)
RETURN actor.name AS name, type(r) AS type, movie.title AS title
UNION
MATCH (director:Person)-[r:DIRECTED]->(movie:Movie)
RETURN director.name AS name, type(r) AS type, movie.title AS title
Rows: 3
+-------------------------------------------------+
| name | type | title |
+-------------------------------------------------+
| 'Tom Hanks' | 'ACTED_IN' | 'Cloud Atlas' |
| 'Tom Hanks' | 'ACTED_IN' | 'Forrest Gump' |
| 'Robert Zemeckis' | 'DIRECTED' | 'Forrest Gump' |
+-------------------------------------------------+
請注意,在所有子句中,返回的列必須以相同的方式命名。
上面的查詢等效於這個更緊湊的查詢:
Cypher
MATCH (actor:Person)-[r:ACTED_IN|DIRECTED]->(movie:Movie) RETURN actor.name AS name, type(r) AS type, movie.title AS title
3. WITH
在Cypher中,可以將語句片段鏈接在一起,類似於在數據流管道中完成的方式。每個片段都處理前一個片段的輸出,其結果可以饋送到下一個片段。只有子句中聲明的列在后續查詢部分中可用。WITH
該子句用於組合各個部分,並聲明哪些數據從一個部分流向另一個部分。 類似於子句。不同之處在於,子句不會完成查詢,而是為下一部分准備輸入。表達式、聚合、排序和分頁的使用方式與子句中的使用方式相同。唯一的區別是所有列都必須有別名。WITH``WITH``RETURN``WITH``RETURN
在下面的示例中,我們收集了某人出演的電影,然后過濾掉那些只出現在一部電影中的電影:
Cypher
MATCH (person:Person)-[:ACTED_IN]->(m:Movie)
WITH person, count(*) AS appearances, collect(m.title) AS movies
WHERE appearances > 1
RETURN person.name, appearances, movies
Rows: 1
+-------------------------------------------------------------+
| person.name | appearances | movies |
+-------------------------------------------------------------+
| 'Tom Hanks' | 2 | ['Cloud Atlas', 'Forrest Gump'] |
+-------------------------------------------------------------+
定義模式
1. 示例圖
首先創建一些數據用於我們的示例:
Cypher
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (robert:Person:Director {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person:Actor {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (robert)-[:DIRECTED]->(forrestGump)
這是結果圖:
2. 使用索引
在圖數據庫中使用索引的主要原因是為了找到圖遍歷的起點。一旦找到該起點,遍歷就依賴於圖內結構來實現高性能。
可以隨時添加索引。
如果數據庫中已有數據,則索引上線需要一些時間。
以下查詢創建一個索引以加快在數據庫中按名稱查找演員的速度:
Cypher
CREATE INDEX example_index_1 FOR (a:Actor) ON (a.name)
在大多數情況下,查詢數據時不需要指定索引,因為將自動使用適當的索引。
可以使用索引提示指定在特定查詢中使用哪個索引。這是查詢調優的幾個選項之一,在Cypher 手冊 → 查詢調優中有詳細描述。
例如,以下查詢將自動使用example_index_1
:
Cypher
MATCH (actor:Actor {name: 'Tom Hanks'})
RETURN actor
A 綜合指數是對具有特定標簽的所有節點的多個屬性的索引。例如,以下語句將在所有標有Actor
和 且同時具有 aname
和 aborn
屬性的節點上創建一個復合索引。請注意,由於Actor
標簽name
為“基努·里維斯”的節點不具有該born
屬性。因此該節點不會被添加到索引中。
Cypher
CREATE INDEX example_index_2 FOR (a:Actor) ON (a.name, a.born)
您可以查詢數據庫SHOW INDEXES
以找出定義了哪些索引。
Cypher
SHOW INDEXES YIELD name, labelsOrTypes, properties, type
Rows: 2
+----------------------------------------------------------------+
| name | labelsOrTypes | properties | type |
+----------------------------------------------------------------+
| 'example_index_1' | ['Actor'] | ['name'] | 'BTREE' |
| 'example_index_2' | ['Actor'] | ['name', 'born'] | 'BTREE' |
+----------------------------------------------------------------+
在Cypher Manual → Indexes 中了解有關索引的更多信息。
3. 使用約束
約束用於確保數據符合域的規則。例如:
“如果一個節點的標簽為
Actor
,屬性為name
,則 的值name
在所有具有Actor
標簽的節點中必須是唯一的”。
示例 1. 唯一性約束
此示例顯示如何為具有標簽Movie
和屬性的節點創建約束title
。約束指定title
屬性必須是唯一的。
添加唯一約束將隱式添加該屬性的索引。如果刪除了約束,但仍然需要索引,則必須顯式創建索引。
Cypher
CREATE CONSTRAINT constraint_example_1 FOR (movie:Movie) REQUIRE movie.title IS UNIQUE
Neo4j 4.4 中的語法發生了變化,舊的語法是:CREATE CONSTRAINT constraint_example_1 ON (movie:Movie) ASSERT movie.title IS UNIQUE Deprecated
可以將約束添加到已經有數據的數據庫中。這要求現有數據符合正在添加的約束。
您可以查詢數據庫以找出使用SHOW CONSTRAINTS
Cypher 語法定義的約束。
示例 2. 約束查詢
此示例顯示了一個 Cypher 查詢,該查詢返回已為數據庫定義的約束。
Cypher
SHOW CONSTRAINTS YIELD id, name, type, entityType, labelsOrTypes, properties, ownedIndexId
Rows: 1
+-----------------------------------------------------------------------------------------------------+
| id | name | type | entityType | labelsOrTypes | properties | ownedIndexId |
+-----------------------------------------------------------------------------------------------------+
| 4 | 'constraint_example_1' | 'UNIQUENESS' | 'NODE' | ['Movie'] | ['title'] | 3 |
+-----------------------------------------------------------------------------------------------------+
上述約束適用於 Neo4j 的所有版本。Neo4j 企業版有額外的限制。
在Cypher 手冊 → 約束中了解有關約束的更多信息。
導入數據
本教程演示了如何使用 .csv 文件從 CSV 文件導入數據
LOAD CSV
。
結合 Cypher 子句LOAD CSV
, MERGE
, 和CREATE
您可以方便地將數據導入 Neo4j。 LOAD CSV
允許您訪問數據值並對其執行操作。
有關 的完整說明LOAD CSV
,請參閱Cypher 手冊 →LOAD CSV
。有關 Cypher 子句的完整列表,請參閱Cypher 手冊 → 子句。
1. 數據文件
在本教程中,您將從以下 CSV 文件導入數據:
- persons.csv
- movies.csv
- roles.csv
people.csv文件的內容:
persons.csv
Cypher
id,name
1,Charlie Sheen
2,Michael Douglas
3,Martin Sheen
4,Morgan Freeman
該persons.csv文件包含兩列id
和name
。每一行代表一個人,他有一個唯一的id
和一個name
。
movies.csv文件的內容:
movies.csv
Cypher
id,title,country,year
1,Wall Street,USA,1987
2,The American President,USA,1995
3,The Shawshank Redemption,USA,1994
該movies.csv文件包含列id
,title
,country
,和year
。每一行代表一部電影,它有一個 unique id
、 a title
、 a country
of origin 和 a release year
。
roles.csv文件的內容:
角色.csv
Cypher
personId,movieId,role
1,1,Bud Fox
4,1,Carl Fox
3,1,Gordon Gekko
4,2,A.J. MacInerney
3,2,President Andrew Shepherd
5,3,Ellis Boyd 'Red' Redding
該roles.csv文件包含列personId
,movieId
和role
。每一行代表與有關的人的關系數據的一個角色id
(從persons.csv文件)和電影id
(從movies.csv文件)。
2. 圖模型
以下簡單數據模型顯示了此數據集的圖形模型可能是什么樣子:
這是基於 CSV 文件數據的結果圖:
3. 先決條件
本教程使用 Linux 或 macOS tarball 安裝。
它假設您當前的工作目錄是tarball 安裝的
有關其他安裝的默認目錄,請參閱操作手冊 → 文件位置。導入位置可通過操作手冊 →dbms.directories.import
進行配置。
4.准備數據庫
在導入數據之前,您應該通過創建索引和約束來准備要使用的數據庫。
您應該通過對Person
和Movie
節點id
創建約束來確保它們具有唯一的屬性。
創建唯一約束也會隱式創建索引。通過索引id
屬性,節點查找(例如 by MATCH
)會快得多。
此外,最好為國家/地區name
建立索引以進行快速查找。
1、啟動neo4j。
Shell
bin/neo4j start
默認用戶名是neo4j
和密碼neo4j
。
2. 創建一個約束,使每個Person
節點都有一個唯一的id
屬性。
您id
對Person
節點的屬性創建約束以確保帶有Person
標簽的節點將具有唯一的id
屬性。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
CREATE CONSTRAINT personIdConstraint FOR (person:Person) REQUIRE person.id IS UNIQUE
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j "CREATE CONSTRAINT personIdConstraint FOR (person:Person) REQUIRE person.id IS UNIQUE"
3. 創建一個約束,使每個Movie
節點都有一個唯一的id
屬性。
您id
對Movie
節點的屬性創建約束以確保帶有Movie
標簽的節點將具有唯一的id
屬性。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
CREATE CONSTRAINT movieIdConstraint FOR (movie:Movie) REQUIRE movie.id IS UNIQUE
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j "CREATE CONSTRAINT movieIdConstraint FOR (movie:Movie) REQUIRE movie.id IS UNIQUE"
4.Country
為name
屬性創建節點索引。
在節點的name
屬性上創建索引Country
以確保快速查找。
使用MERGE
或MATCH
with 時LOAD CSV
,請確保對要合並的屬性具有索引或唯一約束。這將確保查詢以高性能方式執行。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
CREATE INDEX FOR (c:Country) ON (c.name)
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j "CREATE INDEX FOR (c:Country) ON (c.name)"
5.導入數據使用 LOAD CSV
1. 從*persons.csv*文件加載數據。
您創建具有Person
標簽和屬性的節點id
以及name
。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
LOAD CSV WITH HEADERS FROM "file:///persons.csv" AS csvLine
CREATE (p:Person {id: toInteger(csvLine.id), name: csvLine.name})
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j 'LOAD CSV WITH HEADERS FROM "file:///persons.csv" AS csvLine CREATE (p:Person {id:toInteger(csvLine.id), name:csvLine.name})'
Return
Added 4 nodes, Set 8 properties, Added 4 labels
LOAD CSV
還支持通過HTTPS
、HTTP
和訪問 CSV 文件FTP
,請參閱密碼手冊 →LOAD CSV
。
2. 從*movies.csv*文件加載數據。
您可以使用Movie
標簽和屬性id
、title
、 和 來創建節點year
。
您還可以使用Country
標簽創建節點。在多部電影具有相同原產國的情況下,使用MERGE
可避免創建重復Country
節點。
與類型的關系ORIGIN
將連接Country
節點和Movie
節點。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
LOAD CSV WITH HEADERS FROM "file:///movies.csv" AS csvLine
MERGE (country:Country {name: csvLine.country})
CREATE (movie:Movie {id: toInteger(csvLine.id), title: csvLine.title, year:toInteger(csvLine.year)})
CREATE (movie)-[:ORIGIN]->(country)
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j 'LOAD CSV WITH HEADERS FROM "file:///movies.csv" AS csvLine MERGE (country:Country {name:csvLine.country}) CREATE (movie:Movie {id:toInteger(csvLine.id), title:csvLine.title, year:toInteger(csvLine.year)}) CREATE (movie)-[:ORIGIN]->(country)'
Return
Added 4 nodes, Created 3 relationships, Set 10 properties, Added 4 labels
3.從*roles.csv*文件中加載數據
從roles.csv文件導入數據就是找到Person
節點和Movie
節點,然后在它們之間創建關系。
對於較大的數據文件,它是使用提示有用USING PERIODIC COMMIT
的條款LOAD CSV
。這個提示告訴 Neo4j 查詢可能會建立過多的事務狀態,因此需要定期提交。有關更多信息,請參閱4.4@cypher-manual:ROOT:query-tuning/using/index.adoc#query-using-periodic-commit-hint。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM "file:///roles.csv" AS csvLine
MATCH (person:Person {id: toInteger(csvLine.personId)}), (movie:Movie {id: toInteger(csvLine.movieId)})
CREATE (person)-[:ACTED_IN {role: csvLine.role}]->(movie)
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j 'USING PERIODIC COMMIT 500 LOAD CSV WITH HEADERS FROM "file:///roles.csv" AS csvLine MATCH (person:Person {id:toInteger(csvLine.personId)}), (movie:Movie {id:toInteger(csvLine.movieId)}) CREATE (person)-[:ACTED_IND {role:csvLine.role}]->(movie)'
Return
Created 5 relationships, Set 5 properties
6. 驗證導入的數據
通過查找所有具有關系的節點來檢查結果數據集。
使用Neo4j 瀏覽器,運行以下 Cypher:
Cypher
MATCH (n)-[r]->(m) RETURN n, r, m
或者使用Neo4j Cypher Shell,運行命令:
Shell
bin/cypher-shell --database=neo4j 'MATCH (n)-[r]->(m) RETURN n, r, m'
Return
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| n | r | m |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| (:Movie {id: 3, title: "The Shawshank Redemption", year: 1994}) | [:ORIGIN] | (:Country {name: "USA"}) |
| (:Movie {id: 2, title: "The American President", year: 1995}) | [:ORIGIN] | (:Country {name: "USA"}) |
| (:Movie {id: 1, title: "Wall Street", year: 1987}) | [:ORIGIN] | (:Country {name: "USA"}) |
| (:Person {name: "Morgan Freeman", id: 4}) | [:ACTED_IN {role: "Carl Fox"}] | (:Movie {id: 1, title: "Wall Street", year: 1987}) |
| (:Person {name: "Charlie Sheen", id: 1}) | [:ACTED_IN {role: "Bud Fox"}] | (:Movie {id: 1, title: "Wall Street", year: 1987}) |
| (:Person {name: "Martin Sheen", id: 3}) | [:ACTED_IN {role: "Gordon Gekko"}] | (:Movie {id: 1, title: "Wall Street", year: 1987}) |
| (:Person {name: "Martin Sheen", id: 3}) | [:ACTED_IN {role: "President Andrew Shepherd"}] | (:Movie {id: 2, title: "The American President", year: 1995}) |
| (:Person {name: "Morgan Freeman", id: 4}) | [:ACTED_IN {role: "A.J. MacInerney"}] | (:Movie {id: 2, title: "The American President", year: 1995}) |
+---------------------------------------------------------------------------------------------------------------
```</neo4j-home>