1 圖數據庫Neo4j介紹
1.1 什么是圖數據庫(Graph Database)
隨着社交、電商、金融、零售、物聯網等行業的快速發展,現實社會織起了了一張龐大而復雜的關系網,傳統數據庫很難處理關系運算。大數據行業需要處理的數據之間的關系隨數據量呈幾何級數增長,急需一種支持海量復雜數據關系運算的數據庫,圖數據庫應運而生。
世界上很多著名的公司都在使用圖數據庫,比如:
- 社交領域:Facebook、Twitter、Linkedin用它來管理社交關系,實現好友推薦
- 零售領域:eBay、沃爾瑪使用它實現商品實時推薦,給買家更好的購物體驗
- 金融領域:摩根大通、花旗和瑞銀等銀行在用圖數據庫做風控處理
- 汽車制造領域:沃爾沃、戴姆勒和豐田等頂級汽車制造商依靠圖數據庫推動創新制造解決方案
- 電信領域:Verizon、Orange和AT&T等電信公司依靠圖數據庫來管理網絡,控制訪問並支持客戶360
- 酒店領域:萬豪和雅高酒店等頂級酒店公司依使用圖數據庫來管理復雜且快速變化的庫存
圖數據庫並非指存儲圖片的數據庫,而是以圖數據結構存儲和查詢數據。
圖數據庫是基於圖論實現的一種NoSQL數據庫,其數據存儲結構和數據查詢方式都是以圖論為基礎的,圖數據庫主要用於存儲更多的
車接數據。
![]()
圖論[Graph Theory]是數學的一個分支。 它以圖為研究對象圖論中的圖是由若干給定的點及連接兩點的線所構成的圖形,這種圖
形通常用來描述某些事物之間的某種特定關系,用點代表事物,用連接兩點的線表示相應兩個事物間具有這種關系。

在上圖中,輪廓"A"具有圓圈以連接到其他輪廓:家庭圈(B, C, D)和朋友圈(B, C)。
再次,如果我們打開配置文件"B",我們可以觀察以下連接的數據。

像這樣,這些應用程序包含大量的結構化,半結構化和非結構化的連接數據。在RDBMS數據庫中表示這種非結構化連接數據並不容
易。如果我們在RDBMS數據庫中存儲這種更多連接的數據,那么檢索或遍歷是非常困難和緩慢的。所以要表示或存儲這種更連接的數
據,我們應該選擇一個流行的圖數據庫。
圖數據庫非常容易地存儲這種更多連接的數據。它將每 個配置文件數據作為節點存儲在內部,它與相鄰節點連接的節點,它們通過關
系相互連接。他們存儲這種連接的數據與上面的圖表中的相同,這樣檢索或遍歷是非常容易和更快的。
關系查詢性能對比
在數據關系中心,圖形數據庫在查詢速度方面非常高效,即使對於深度和復雜的查詢也是如此。在關系型數據庫和圖數據庫(Neo4j)之間
進行了實驗:在一個社交網絡里找到最大深度為5的朋友的朋友,他們的數據集包括100萬人,每人約有50個朋友。
實驗結果如下:
深度 | MySQL執行時間(s) | Neo4J執行時間(s) | 返回記錄數 |
---|---|---|---|
2 | 0.016 | 0.01 | ~2500 |
3 | 30.267 | 0.168 | ~110,000 |
4 | 1,543.505 | 1.359 | -600,000 |
5 | 未完成 | 2.132 | -800,000 |
對比關系型數據庫
關系型數據庫(RDBMS) | 圖數據庫 |
---|---|
表 | 圖 |
行 | 節點 |
列和數據 | 屬性和數據 |
約束 | 關系 |
在關系型數據庫中,Person和Department之間用外鍵表示關系:
在圖數據庫中,節點和關系取代表,外鍵和join:
在圖數據庫中,無論何時運行類似JOIN的操作, 數據庫都會使用此列表並直接訪問連接的節點,無需進行昂貴的搜索和匹配計算。
對比其他NoSQL數據庫
NoSQL數據庫大致可以分為四類:
- 鍵值(key/value)數據庫
- 列存儲數據庫
- 文檔型數據庫
- 圖數據庫
分類 | 數據模型 | 優勢 | 劣勢 | 舉例 |
---|---|---|---|---|
鍵值數據庫 | 哈希表 | 查找速度快 | 數據無結構化,通常只被當作字符串或者二進制數據 | Redis |
列存儲數據庫 | 列式數據存儲 | 查找速度快;支持分布橫向擴展;數據壓縮率高 | 功能相對受限 | HBase |
文檔型數據庫 | 鍵值對擴展 | 數據結構要求不嚴格;表結構可變;不需要預先定義表結構 | 查詢性能不高,缺乏統一的查詢語法 | MongoDB |
圖數據庫 | 節點和關系組成的圖 | 利用圖結構相關算法(最短路徑、節點度關系查找等) | 可能需要對整個圖做計算,不利於圖數據分布存儲 | Neo4j、JanusGraph |
1.2 什么是Neo4j
Neo4j是一個開源的NoSQL圖形數據庫,2003年開始開發,使用scala和java語言,2007年開始發布。
- 是世界上最先進的圖數據庫之一 ,提供原生的圖數據存儲,檢索和處理
- 采用屬性圖模型(Property graph model),極大的完善和豐富圖數據模型
- 專屬查詢語言Cypher,直觀、高效
Neo4j的特性:
- SQL就像簡單的查詢語言Neo4j CQL
- 它遵循屬性圖數據模型
- 它通過使用Apache Lucence支持索引
- 它支持UNIQUE約束
- 它包含一個用於執行CQL命令的UI:Neo4j數據瀏覽器
- 它支持完整的ACID(原子性,一致性,隔離性和持久性)規則
- 它采用原生圖形庫與本地GPE(圖形處理引擎)
- 它支持查詢的數據導出到SON和XLS格式
- 它提供了REST API,可以被任何編程語言(如ava, Spring, Scala等)訪問
- 它提供了可以通過任何UI MVC框架(如Node JS)訪問的Java腳本
- 它支持兩種ava API:Cypher API和Native Java API來開發Java應用程序
Neo4j的優點:
- 它很容易表示連接的數據
- 檢索/遍歷/導航更多的連接數據是非常容易和快速的
- 它非常容易地表示半結構化數據
- Neo4j CQL查詢語言命令是人性化的可讀格式,非常容易學習
- 使用簡單而強大的數據模型
- 它不需要復雜的連接來檢索連接的/相關的數據,因為它很容易檢索它的相鄰節點或關系細節沒有連接或索引
1.3 Neo4j數據模型
圖論基礎
最簡單的可能圖是單個節點:

我們可以使用節點表示社交網絡(如Google+個人資料), 它不包含任何屬性。向Google+個人資料添加一些屬性:

在兩個節點之間創建關系:

此處在兩個Profile之間創建關系名稱"關注”。這意味着Profile 1關注了Profile 2。
屬性圖模型
Neo4j圖數據庫遵循屬性圖模型來存儲和管理其數據。
屬性圖模型規則
- 表示節點,關系和屬性中的數據.
- 節點和關系都包含屬性
- 關系連接節點
- 屬性是鍵值對
- 節點用圓圈表示,關系用方向鍵表示。
- 關系具有方向:單向和雙向。
- 每個關系包含”開始節點”或”從節點"和”到節點"或”結束節點”
在屬性圖數據模型中,關系應該是定向的。如果我們嘗試創建沒有方向的關系,那么它將拋出一個錯誤消息。在Neo4j中, 關系也應
該是有方向性的。如果我們嘗試創建沒有方向的關系,那么Neo4j會拋出一個錯誤消息,"關系應該是方向性的”。
Neo4j圖數據庫將其所有數據存儲在節點和關系中,我們不需要任何額外的RDBMS數據庫或NoSQL數據庫來存儲Neo4j數據庫數據,
它以圖的形式存儲數據。Neo4j使用本機GPE (圖形處理引擎)來使用它的本機圖存儲格式。
圖數據庫數據模型的主要構建塊是:
- 節點
- 關系
- 屬性
簡單的屬性圖的例子:
這里我們使用圓圈表示節點。使用箭頭表示關系, 關系是有方向性的。我們可以用Properties (鍵值對)來表示Node的數據。在這個例
子中,我們在Node的Circle中表示了每個Node的Id屬性。
1.4 Neo4j的構建元素
Neo4j圖數據庫主要有以下構建元素:
- 節點
- 屬性
- 關系
- 標簽
- 數據瀏覽器
節點
節點(Node)是圖數據庫中的一個基本元素,來表示一個實體記錄, 就像關系數據庫中的一條記錄-樣。在Neo4j中節點可以包含多個
屬性(Property)和多個標簽(Label)。
- 節點是主要的數據元素
- 節點通過關系連接到其他節點
- 節點可以具有一個或多個屬性(即,存儲為鍵/值對的屬性)
- 節點有一個或多個標簽,用於描述其在圖表中的作用
屬性
屬性(Property)是用於描述圖節點和關系的鍵值對。其中Key是一個字符串, 值可以通過使用任何Neo4j數據類型來表示
- 屬性是命名值,其中名稱(或鍵)是字符串
- 屬性可以被索引和約束
- 可以從多個屬性創建復合索引
關系
關系(Relationship) 同樣是圖數據庫的基本元素。當數據庫中已經存在節點后,需要將節點連接起來構成圖。關系也稱為圖論的邊(Edge) ,其始端和末端都必須是節點,關系不能指向空也不能從空發起。
關系和節點一樣可以包含多個屬性,但關系只能有一個類型(Type)。
- 關系連接兩個節點
- 關系是方向性的
- 節點可以有多個甚至遞歸的關系
- 關系可以有一個或多個屬性(即存儲為鍵/值對的屬性)
基於方向性,Neo4j關系被分為兩種主要類型:
- 單向關系
- 雙向關系
標簽
標簽(Label)將一個公共名稱與一組節點或關系相關聯,節點或關系可以包含一個或多個標簽。我們可以為現有節點或關系創建新標簽,我們可以從現有節點或關系中刪除標簽。
- 標簽用於將節點分組
- 一個節點可以具有多個標簽
- 對標簽進行索引以加速在圖中查找節點
- 本機標簽索引針對速度進行了優化
Neo4j Browser
一旦我們安裝Neo4j, 我們就可以訪問Neo4j數據瀏覽器
1.5 使用場景
欺詐檢測
實時推薦引擎
知識圖譜
……
2 環境搭建
2.1 安裝Neo4j Community Server
下載地址:https://neo4j.com/download-center/
安裝方式:
- Neo4j Enterprise Server
- Neo4j Community Server
解壓:
$ tar -zxvf neo4j-community-4.4.3-unix.tar.gz
啟動:
$ cd neo4j-community-4.4.3/bin/
$ ./neo4j start
Directories in use:
home: /root/neo4j-community-4.4.3
config: /root/neo4j-community-4.4.3/conf
logs: /root/neo4j-community-4.4.3/logs
plugins: /root/neo4j-community-4.4.3/plugins
import: /root/neo4j-community-4.4.3/import
data: /root/neo4j-community-4.4.3/data
certificates: /root/neo4j-community-4.4.3/certificates
licenses: /root/neo4j-community-4.4.3/licenses
run: /root/neo4j-community-4.4.3/run
Starting Neo4j.
Started neo4j (pid:134371). It is available at http://localhost:7474
There may be a short delay until the server is ready.
3 Neo4j - CQL使用
3.1 Neo4j - CQL簡介
Neo4j的Cypher語言是為處理圖形數據而構建的,CQL代表Cypher查詢語言。 像Oracle數據庫具有查詢語言SQL, Neo4j具有CQL作為查詢語言。
- 它是Neo4j圖形數據庫的查詢語言
- 它是一種聲明性模式匹配語言
- 它遵循SQL語法。
- 它的語法是非常簡單且人性化、可讀的格式
CQL命令 | 用法 |
---|---|
CREATE | 創建節點,關系和屬性 |
MATCH | 檢索有關節點,關系和屬性數據 |
RETURN | 返回查詢結果 |
WHERE | 提供條件過濾檢索數據 |
DELETE | 刪除節點和關系 |
REMOVE | 刪除節點和關系的屬性 |
ORDER BY | 排序檢索數據 |
SET | 添加或更新標簽 |
三個共同朋友的社交圖:
使用Cypher語言來描述關系
(fox)<-[:knows]-(Zhou Yu)-[:knows]->(Zhuge)-[:knows]->(fox)
3.2 常用命令
文檔地址:https://neo4j.com/docs/cypher-manual/current/introduction/
CREATE創建
create語句是創建模型語句用來創建數據模型
創建節點
// 創建簡單節點
CREATE (n)
// 創建多個節點
CREATE (n), (m)
創建一個帶標簽和屬性的節點並返回該節點
CREATE (n:Person{
name: "Sean Lau Ching-wan", born: 1964})
RETURN n
<id>: 171
born: 1964
name: Sean Lau Ching-wan
創建關系
Neo4j圖數據庫遵循屬性圖模型來存儲和管理其數據。
根據屬性圖模型,關系應該是定向的。否則, Neo4j將拋出一個錯誤消息。
基於方向性,Ne04j關系被分為兩種主要類型。
- 單向關系
- 雙向關系
使用新節點創建關系
CREATE (n:Person {
name: 'Yau Nai-hoi', born: 1968})-[r:FOLLOWS]->(m:Person{
name: 'Johnnie To Kei-fung', born:1955})
RETURN type(r)
type(r) | |
---|---|
1 | "FOLLOWS" |
使用已知節點創建帶屬性的關系
MATCH (n:Person{
name: "Patrick Yau Tat-Chi"}),(m:Person{
name: "Johnnie To Kei-fung"})
CREATE (n)-[r:FOLLOWS]->(m)
MATCH查詢
Neo4j CQL RETURN子句用於
- 檢索節點的某些屬性
- 檢索節點的所有屬性
- 檢索節點和關聯關系的某此屬性
- 檢索節點和關聯關系的所有屬性
MATCH (n:Movie {
title: 'The Green Mile'})
RETURN n
<id>: 130
released: 1999
tagline: Walk a mile you'll never forget.
title: The Green Mile
WHERE子句
像SQL-樣,Neo4j CQL在CQL MATCH命令中提供了WHERE子句來過濾MATCH查詢的結果。
MATCH (n:Movie)
WHERE n.title = "The Green Mile"
RETURN n
DELETE刪除
Neo4j使用CQL DELETE子句
- 刪除節點
- 刪除節點及相關節點和關系。
刪除關系
MATCH (n:Person{
name: "Johnnie To Kei-fung"})<-[r]-(m)
DELETE r
RETURN type(r)
刪除節點(前提:節點不存在關系)
MATCH (n:Person{
name: "Patrick Yau Tat-Chi"})
DELETE n
REMOVE刪除
有時基於客戶端要求,我們需要向現有節點或關系添加或刪除屬性。我們使用Neo4j CQL REMOVE子句來刪除節點或關系的現有屬性。
- 刪除節點或關系的標簽
- 刪除節點或關系的屬性
移除屬性
MATCH (n:Person{
name: "Johnnie To Kei-fung"}) REMOVE n.born
RETURN n
<id>: 173
name: Johnnie To Kei-fung
移除標簽
新增一個節點,有多個標簽
CREATE (n:Person:Director{
born: 1958, name: "Tony Leung Ka-fai"})
刪除一個標簽
MATCH (n:Person:Director{
born: 1958, name: "Tony Leung Ka-fai"})
REMOVE n:Director
RETURN n;
SET子句
有時,根據我們的客戶端要求,我們需要向現有節點或關系添加新屬性。要做到這一點Neo4j CQL提供了一個SET子句。
- 向現有節點或關系添加新屬性
- 添加或更新屬性值
MATCH (n:Person{
name: "Johnnie To Kei-fung"}) SET n.born = 1955
RETURN n
ORDER BY排序
Neo4j CQL在MATCH命令中提供了"ORDER BY"子句,對MATCH查詢返回的結果進行排序。
我們可以按升序或降序對行進行排序。默認情況下,它按升序對行進行排序。如果我們要按降序對它們進行排序, 我們需要使用DESC子
句
MATCH (n:Person)
RETURN n ORDER BY n.name DESC
LIMIT 5
"n" |
---|
LIMIT和SKIP子句
Neo4j CQLE提供LIMIT子句和SKIP來過濾或限制查詢返回的行數。
LIMIT返回前幾行,SKIP忽略前幾行。
前2行
MATCH (n)
RETURN n
LIMIT 2
忽略前2行
MATCH (n)
RETURN n SKIP 2
NULL值
Neo4j CQL將空值視為對節點或關系的屬性的缺失值或未定義值。
當我們創建一個具有現有節點標簽名稱但未指定其屬性值的節點時,它將創建一個具有NUL屬性值的新節點。
MATCH (n:Person)
WHERE n.name IS NULL
RETURN n
IN操作符
與5QL一樣,Neo4j CQL提供了一個IN運算符。 以便為CQL命令提供值的集合。
MATCH (n:Person)
WHERE n.name IN ["Carrie-Anne Moss", "Lilly Wachowski"]
RETURN n;
INDEX索引
Neo4j SQL支持芍點或美系屬性上的索引以提高應用程序的性能。
我們可以為具有相同標簽名稱的所有節點的屬性創建索引。
我們可以在MATCH或WHERE或IN運算符上使用這些索引列來改進CQL Command的執行。
Neo4J索引操作
- Create Index創建索引
- Drop Index丟棄索引
增加索引
CREATE INDEX FOR (n:Person) ON (n.name)
UNIQUE約束
在Neo4]數據庫中,CQL CREATE命令始終創建新的節點或關系,這意味着即使您使用相同的值,它也會插入一個新行。根據我們對某些
節點或關系的應用需求,我們必須避免這種重復。
像SQL-樣,Neo4j數據庫也支持對NODE或Relationship的屬性的UNIQUE約束
UNIQUE約束的優點
- 避免重復記錄
- 強制執行數據完整性規則
CREATE CONSTRAINT ON (n:Person) ASSERT n.name IS UNIQUE
DROP CONSTRAINT ON (n:Person) ASSERT n.name IS UNIQUE
DISTINCT
這個函數的用法就像SQL中的distinct關鍵字,返回的是所有不同值。
MATCH (n:Person)
RETURN DISTINCT (n.name)
3.3 常用函數
函數 | 用法 |
---|---|
String字符串 | 它們用於使用String字面量 |
Aggregation聚合 | 它們用於對CQL查詢結果執行一些聚合操作 |
Relationship關系 | 他們用於獲取關系的細節,如startnode, endnode等 |
字符串函數
與SQL一樣。Neo4J CQL提供了一組String函數,用於在CQL查詢中獲取所需的結果。
功能 | 描述 |
---|---|
UPPER | 它用於將所有字母更改為大寫字母 |
LOWER | 它用於將所有字母改為小寫字母 |
SUBSTRING | 它用於獲取給定String的子字符串 |
REPLACE | 它用於替換一個字符串的子字符串 |
MATCH (e)
RETURN id(e), e.name, substring(e.name, 0, 2)
AGGREGATION聚合
和SQL-樣。Neo4j CQL提供了一-些在RETURN子句中使用的聚合函數。它類似於 SQL中的GROUP BY子句。
我們可以使用MATCH命令中的RETURN +聚合函數來處理一組節點並返回一些聚合值。
聚集功能 | 描述 |
---|---|
COUNT | 它返回由MATCH命令返回的行數 |
MAX | 它從MATCH命令返回的一組行返回最大值 |
MIN | 它返回由MATCH命令返回的一組行的最小值 |
SUM | 它返回由MATCH命令返回的所有行的求和值 |
AVG | 它返回由MATCH命令返回的所有行的平均值 |
MATCH (e)
RETURN count(e)
關系函數
關系函數I
Neo4j CQL提供了一組關系函數,以在獲取開始節點,結束節點等細書時知道關系的細節。
功能 | 描述 |
---|---|
STARTNODE | 它用於知道關系的開始節點 |
ENDNODE | 它用於知道關系的結束節點 |
ID | 它用於知道關系的ID |
TYPE | 它用於知道字符串表示中的一個關系的TYPE |
MATCH (a)-[r] ->(b)
RETURN id(r), type(r)
3.4 neo4j-admin使用
數據庫備份
對Neo4j數據進行備份、還原、遷移的操作時,要關閉neo4j
$ ./neo4j-admin dump --database=graph.db --to=/root/graph_backup.dump
數據庫恢復
還原、遷移之前,要關閉neo4j服務。
$ ./neo4j-admin load --from=/root/graph_backup.dump --database=graph.db
4 Spring Boot整合Neo4j
4.1 spring-data-neo4j
版本:Spring Boot 2.3.12.RELEASE、Spring Data Neo4j 5.3.9.RELEASE
文檔地址:https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#reference
添加Neo4j依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
添加配置
注意:不同版本依賴配置可能不一樣,可通過neo4j自動配置類查看
# neo4j配置
spring.data.neo4j.uri=neo4j://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=12345678
創建實體
@NodeEntity
:標明是一個節點實體
@RelationshipEntity
:標明是一個關系實體
@ld
:實體主鍵
@Property
:實體屬性
@GeneratedValue
:實體屬性值自增
@StartNode
:開始節點(可以理解為父節點)
@EndNode
:結束節點(可以理解為子節點)
package com.tuling.neo4jspringboot.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Property;
@Data
@NoArgsConstructor
@AllArgsConstructor
@NodeEntity("Person")
public class Person {
/**
* id
*/
@Id
@GeneratedValue
private Long id;
/**
* 名字
*/
@Property
private String name;
/**
* 出生年份
*/
@Property
private Long born;
}
package com.tuling.neo4jspringboot.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.neo4j.ogm.annotation.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@RelationshipEntity("COUPLE")
public class PersonRelationship {
/**
* id
*/
@Id
@GeneratedValue
private Long id;
/**
* 開始節點
*/
@StartNode
private Person start;
/**
* 結束節點
*/
@EndNode
private Person end;
}
創建接口繼承Neo4jRepository
package com.tuling.neo4jspringboot.dao;
import com.tuling.neo4jspringboot.entity.Person;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PersonRepository extends Neo4jRepository<Person, Long> {
}
package com.tuling.neo4jspringboot.dao;
import com.tuling.neo4jspringboot.entity.PersonRelationship;
import org.springframework.data.neo4j.repository.Neo4jRepository;
public interface PersonRelationshipRepository extends Neo4jRepository<PersonRelationship, Long> {
}