1. 程式人生 > 其它 >圖資料庫Neo4j實戰

圖資料庫Neo4j實戰

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"
{"born":1954,"name":"Zach Grenier"}
{"born":1968,"name":"Yau Nai-hoi"}
{"born":1972,"name":"Wil Wheaton"}
{"born":1942,"name":"Werner Herzog"}
{"born":1956,"name":"Vincent Ward"}

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> {
}