# 一、图数据库
graph database 图数据库
# 什么是图数据库
图数据库是基于图论实现的一种NoSQL数据库,其数据存储结构和数据查询方式都是以图论为基础的,图数据库主要用于存储更多的连接数据。
图论〔Graph Theory〕是数学的一个分支。它以图为研究对象,图论中的图是由若干给定的点及连接两点的线所构成的图形。这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。
图数据库非常容易地存储多连接的数据。 它将每个配置文件数据作为节点存储在内部,它与相邻节点连接的节点,它们通过关系相互连接。这样检索或遍历是非常容易和更快的。
# 对比关系型数据库
关系型数据库(RDBMS) | 图数据库 |
---|---|
表 | 图 |
行 | 节点 |
列和数据 | 属性和数据 |
约束 | 关系 |
# 对比其他NoSQL数据库
NoSQL数据库大致可以分为四类:
- 键值(key/value)数据库
- 列存储数据库
- 文档型数据库
- 图数据库
分类 | 数据模型 | 举例 | 优势 | 劣势 |
---|---|---|---|---|
键值数据库(Key-Value) | 哈希表 | Redis | 查找速度快 | 数据无结构化,通常只被当作字符串或者二进制数据 |
列存储数据库(Column Family) | 列式数据存储 | HBase | 查找速度快;支持分布横向扩展;数据压缩率高 | 功能相对受限 |
文档型数据库(Document) | 键值对扩展 | MongoDB | 数据结构要求不严格;表结构可变;不需要预先定义表结构 | 查询性能不高,缺乏统一的查询语法 |
图数据库(Graph DB) | 节点和关系组成的图 | Neo4j、JanusGraph | 利用图结构相关算法(最短路径、节点度关系查找等) | 可能需要对整个图做计算,不利于图数据分布存储 |
# 图数据库的应用场景
- 社交领域:Facebook, Twitter,Linkedin用它来管理社交关系,实现好友推荐
- 零售领域:eBay,沃尔玛使用它实现商品实时推荐,给买家更好的购物体验
- 金融领域:摩根大通,花旗和瑞银等银行在用图数据库做风控处理
- 汽车制造领域:沃尔沃,戴姆勒和丰田等顶级汽车制造商依靠图数据库推动创新制造解决方案
- 电信领域:Verizon, Orange和AT&T 等电信公司依靠图数据库来管理网络,控制访问并支持客户
- 酒店领域:万豪和雅高酒店等顶级酒店公司依使用图数据库来管理复杂且快速变化的库存
# 二、Neo4j
# Neo4j简介
Neo4j是一个开源的NoSQL图形数据库,2007年发布,使用 scala和java 语言。
Neo4j是世界领先的图形数据库。该体系结构旨在优化节点和关系的管理、存储和遍历。图形数据库采用属性图方法,这对遍历性能和运行时操作都是有益的。
Neo4j提供专用内存管理和高效内存操作。
Neo4j是可扩展的,可以作为独立服务器部署,也可以跨生产环境的容错集群中的多台机器部署。生产应用程序的其他功能包括热备份和广泛的监控。
- 是世界上最先进的图数据库之一,提供原生的图数据存储,检索和处理;
- 采用属性图模型(Property graph model),极大的完善和丰富图数据模型;
- 专属查询语言 Cypher,直观,高效;
# Neo4j的特性
- 它遵循属性图数据模型
- 它通过使用Apache Lucence支持索引
- 它支持UNIQUE约束
- 它包含一个用于执行CQL命令的UI:Neo4j数据浏览器
- 它支持完整的ACID(原子性,一致性,隔离性和持久性)规则
- 它采用原生图形库与本地GPE(图形处理引擎)
- 它支持查询的数据导出到JSON和XLS格式
- 它提供了REST API,可以被任何编程语言(如Java,Spring,Scala等)访问
- 它提供了可以通过任何UI MVC框架(如Node JS)访问的Java脚本
- 它支持两种Java API:Cypher API和Native Java API来开发Java应用程序
# Neo4j的优点
- 它很容易表示连接的数据
- 检索/遍历/导航更多的连接数据是非常容易和快速的
- 它非常容易地表示半结构化数据
- Neo4j CQL查询语言命令是人性化的可读格式,非常容易学习
- 使用简单而强大的数据模型
- 它不需要复杂的连接来检索连接的/相关的数据
# Neo4j数据模型
# 图论基础
图是一组节点和连接这些节点的关系,图形以属性的形式将数据存储在节点和关系中,属性是用于表示数据的键值对。
在图论中,我们可以表示一个带有圆的节点,节点之间的关系用一个箭头标记表示。
# 属性图模型
属性图模型规则:
- 表示节点,关系和属性中的数据
- 节点和关系都包含属性
- 关系连接节点
- 属性是键值对
- 节点用圆圈表示,关系用方向键表示。
- 关系具有方向:单向和双向。
- 每个关系包含“开始节点”或“从节点”和“到节点”或“结束节点”
Neo4j图数据库遵循属性图模型来存储和管理其数据。
在属性图数据模型中,关系应该是定向的。如果我们尝试创建没有方向的关系,那么它将抛出一个错误消息。
在Neo4j中,关系也应该是有方向性的。如果我们尝试创建没有方向的关系,那么Neo4j会抛出一个错误消息,“关系应该是方向性的”。
Neo4j图数据库将其所有数据存储在节点和关系中,我们不需要任何额外的RDBMS数据库或NoSQL数据库来存储Neo4j数据库数据,它以图的形式存储数据。Neo4j使用本机GPE(图形处理引擎)来使用它的本机图存储格式。
# 图数据库数据模型
图数据库数据模型的主要构建块是:
- 节点
- 关系
- 属性
一个简单的属性图:
使用圆圈表示节点。 使用箭头表示关系,关系是有方向性的。 我们可以用Properties(键值对)来表示Node的数据。
# Neo4j的构建元素
Neo4j图数据库主要有以下构建元素:
- 节点
- 属性
- 关系
- 标签
- 数据浏览器 (Neo4j Browser)
# 节点
节点(Node)是图数据库中的一个基本元素,用来表示一个实体记录,就像关系数据库中的一条记录一样。在Neo4j中节点可以包含多个属性(Property)和多个标签(Label)。
- 节点是主要的数据元素
- 节点通过关系连接到其他节点
- 节点可以具有一个或多个属性(即,存储为键/值对的属性)
- 节点有一个或多个标签,用于描述其在图表中的作用
# 属性
属性(Property)是用于描述图节点和关系的键值对。其中Key是一个字符串,值可以通过使用任何Neo4j数据类型来表示 。
- 属性是命名值,其中名称(或键)是字符串
- 属性可以被索引和约束
- 可以从多个属性创建复合索引
# 关系
关系(Relationship)同样是图数据库的基本元素。当数据库中已经存在节点后,需要将节点连接起来构成图。关系就是用来连接两个节点。
关系也称为图论的边(Edge) ,其始端和末端都必须是节点,关系不能指向空,也不能从空发起。
关系和节点一样可以包含多个属性,但关系只能有一个类型(Type) 。
- 关系连接两个节点
- 关系是方向性的
- 节点可以有多个甚至递归的关系
- 关系可以有一个或多个属性(即存储为键/值对的属性)
基于方向性,Neo4j关系被分为两种主要类型:
- 单向关系
- 双向关系
# 标签
标签(Label)将一个公共名称与一组节点或关系相关联, 节点或关系可以包含一个或多个标签。
我们可以为现有节点或关系创建新标签, 我们可以从现有节点或关系中删除标签。
- 标签用于将节点分组
- 一个节点可以具有多个标签
- 对标签进行索引以加速在图中查找节点
- 本机标签索引针对速度进行了优化
# Neo4j Browser
一旦我们安装Neo4j,我们就可以访问Neo4j数据浏览器
http://localhost:7474/browser/ (opens new window)
# Neo4j使用场景
- 欺诈检测
- 实时推荐引擎
- 知识图谱
- 反洗钱
- 主数据管理
- 供应链管理
- 增强网络和IT运营管理能力
数据谱系
身份和访问管理
材料清单
社交网络
# 三、Neo4j安装
Neo4j下载地址:https://neo4j.com/download-center/ (opens new window)
安装方式:
- Neo4j Enterprise Server (企业版)
- Neo4j Community Server (社区版)
- Neo4j Desktop(桌面版)
# 安装Neo4j Community Server
下载
注意:
- neo4j最新版对应的java版本是jdk11
- jdk8可以下载Neo4j Community Edition 3.5.28
解压运行
解压到新目录(注意:目录名称不要有中文),比如: D:\neo4j\
# 将Neo4j作为控制台应用程序运行 <NEO4J_HOME>\bin\neo4j console # 将Neo4j作为服务使用进行安装 <NEO4J_HOME>\bin\neo4j install-service
1
2
3
4- console: 直接启动 neo4j 服务器
- install-service | uninstall-service | update-service : 安装/卸载/更新 neo4j 服务
- start/stop/restart/status: 启动/停止/重启/状态
- -V 输出更多信息
进入到bin目录,执行
neo4j console
1使用用户名neo4j和默认密码neo4j进行连接,然后会提示更改密码。
Neo4j Browser是开发人员用来探索Neo4j数据库、执行Cypher查询并以表格或图形形式查看结果的工具。
# Docker 安装Neo4j
Neo4j 4.4版Docker操作手册 (opens new window)
需要暴露端口:
- 7474 for HTTP.
- 7473 for HTTPS.
- 7687 for Bolt.
# 1、Neo4j 3.x.x
mkdir -p /usr/local/docker/neo4j
cd /usr/local/docker/neo4j
vi docker-compose.yml
2
3
docker-compose.yml
version: '3'
services:
neo4j:
image: neo4j:3.5.5
volumes:
- ./data:/data
- ./logs:/var/lib/neo4j/logs
- ./conf:/var/lib/neo4j/conf
- ./mnt:/var/lib/neo4j/import
- ./plugins:/plugins
restart: always
ports:
- 7474:7474
- 7687:7687
environment:
- NEO4J_dbms_memory_heap_maxSize=4G
- NEO4J_AUTH=neo4j/123456
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
登录
http://ip:7474/browser/
# 2、Neo4j 4.x.x
docker-compose.yml
version: '3'
services:
neo4j:
image: neo4j:4.4.6
volumes:
- ./data:/data #把容器内的数据目录挂载到宿主机的对应目录下
- ./logs:/logs #挂载日志目录
- ./conf:/conf #挂载配置目录
restart: always
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=neo4j/123456
2
3
4
5
6
7
8
9
10
11
12
13
14
登录
http://localhost:7474/
# 四、Neo4j - CQL使用
# Cypher
Cypher是一种用于图形的声明式查询语言。主要用于处理图形数据。
Neo4j使用属性图方法,其中关系与模型中的数据一起存储,而不是在查询时计算。
Cypher是一种强大的、图形优化的查询语言,能够理解并利用这些存储的连接。
当试图在数据中找到模式或洞察时,Cypher查询通常比大规模SQL连接更简单、更容易编写。
因为Neo4j没有表,所以不需要担心连接。
# CQL
CQL代表Cypher查询语言。
- 它是Neo4j图形数据库的查询语言。
- 它是一种声明性模式匹配语言。
- 它遵循SQL语法。
- 它的语法是非常简单且人性化、可读的格式。
# 常用命令
Neo4j 4.4版常用命令 (opens new window)
CQL命令 | 用法 |
---|---|
CREATE | 创建节点,关系和属性 |
MATCH | 检索有关节点,关系和属性数据 |
RETURN | 返回查询结果 |
WHERE | 提供条件过滤检索数据 |
DELETE | 删除节点和关系 |
REMOVE | 删除节点和关系的属性 |
ORDERBY | 排序检索数据 |
# CREATE创建
create语句是创建模型语句用来创建数据模型。
创建节点
#创建简单节点
create (n)
#创建多个节点
create (n),(m)
#创建带标签和属性的节点并返回节点
create (n:person {name:'如来'}) return n
2
3
4
5
6
7
创建关系
Neo4j图数据库遵循属性图模型来存储和管理其数据。
根据属性图模型,关系应该是定向的。 否则,Neo4j将抛出一个错误消息。
基于方向性,Neo4j关系被分为两种主要类型。
- 单向关系
- 双向关系
#使用新节点创建关系
CREATE (n:person {name:'杨戬'})-[r:师傅]->(m:person {name:'玉鼎真人'}) return type(r)
#使用已知节点创建带属性的关系
match (n:person {name:'沙僧'}),(m:person{name:'唐僧'})
create (n)-[r:`师傅`{relation:'师傅'}]->(m) return r
#检索关系节点的详细信息
match (n:person)-[r]-(m:person) return n,m
2
3
4
5
6
7
8
9
创建全路径
create p=(:person{name:'蛟魔王'})-[:义兄]->(:person{name:'牛魔王'})<-[:义兄]- (:person {name:'鹏魔王'}) return p
# MATCH查询
Neo4j CQL MATCH命令用于:
- 从数据库获取有关节点和属性的数据
- 从数据库获取有关节点,关系和属性的数据
MATCH (n:`西游`) RETURN n LIMIT 25
# RETURN返回
Neo4j CQL RETURN子句用于:
- 检索节点的某些属性
- 检索节点的所有属性
- 检索节点和关联关系的某些属性
- 检索节点和关联关系的所有属性
MATCH (n:`西游`) RETURN id(n),n.name,n.tail,n.relation
# WHERE子句
像SQL一样,Neo4j CQL在CQL MATCH命令中提供了WHERE子句来过滤MATCH查询的结果。
MATCH (n:person) where n.name='孙悟空' or n.name='猪八戒' RETURN n
#创建关系
match (n:person),(m:person) where n.name='孙悟空' and m.name='猪八戒'
create (n)-[r:师弟]->(m) return n.name,type(r),m.name
2
3
4
5
# DELETE删除
Neo4j使用CQL DELETE子句:
- 删除节点。
- 删除节点及相关节点和关系。
# 删除节点 (前提:节点不存在关系)
MATCH (n:person{name:"白龙马"}) delete n
# 删除关系
MATCH (n:person{name:"沙僧"})<-[r]-(m) delete r return type(r)
2
3
4
5
# REMOVE删除
有时基于客户端要求,我们需要向现有节点或关系添加或删除属性。我们使用Neo4j CQL REMOVE子句来删除节点或关系的现有属性。
- 删除节点或关系的标签
- 删除节点或关系的属性
#删除属性
MATCH (n:role {name:"fox"}) remove n.age return n
#创建节点
CREATE (m:role:person {name:"fox666"})
#删除标签
match (m:role:person {name:"fox666"}) remove m:person return m
2
3
4
5
6
7
# SET子句
有时,根据我们的客户端要求,我们需要向现有节点或关系添加新属性。要做到这一点,Neo4j CQL提供了一个SET子句。
- 向现有节点或关系添加新属性
- 添加或更新属性值
MATCH (n:role {name:"fox"}) set n.age=32 return n
# ORDER BY排序
Neo4j CQL在MATCH命令中提供了“ORDER BY”子句,对MATCH查询返回的结果进行排序。
我们可以按升序或降序对行进行排序。默认情况下,它按升序对行进行排序。 如果我们要按降序对它们
进行排序,我们需要使用DESC子句。
MATCH (n:`西游`) RETURN id(n),n.name order by id(n) desc
# UNION子句
与SQL一样,Neo4j CQL有两个子句,将两个不同的结果合并成一组结果
UNION
它将两组结果中的公共行组合并返回到一组结果中。 它不从两个节点返回重复的行。
限制:
结果列类型和来自两组结果的名称必须匹配,这意味着列名称应该相同,列的数据类型应该相同。
UNION ALL
它结合并返回两个结果集的所有行成一个单一的结果集。它还返回由两个节点重复行。
限制:
结果列类型,并从两个结果集的名字必须匹配,这意味着列名称应该是相同的,列的数据类型应该是相同的。
MATCH (n:role) RETURN n.name as name UNION MATCH (m:person) RETURN m.name as name MATCH (n:role) RETURN n.name as name UNION all MATCH (m:person) RETURN m.name as name
1
2
3
4
5
6
7
# LIMIT和SKIP子句
Neo4j CQL已提供 LIMIT 子句和 SKIP 来过滤或限制查询返回的行数。
LIMIT返回前几行,SKIP忽略前几行。
# 前两行
MATCH (n:`西游`) RETURN n LIMIT 2
# 忽略前两行
MATCH (n:person) RETURN n SKIP 2
2
3
4
# NULL值
Neo4j CQL将空值视为对节点或关系的属性的缺失值或未定义值。
当我们创建一个具有现有节点标签名称但未指定其属性值的节点时,它将创建一个具有NULL属性值的新节点。
match (n:`西游`) where n.label is null return id(n),n.name,n.tail,n.label
# IN操作符
与SQL一样,Neo4j CQL提供了一个IN运算符,以便为CQL命令提供值的集合。
match (n:`西游`) where n.name in['孙悟空','唐僧']
return id(n),n.name,n.tail,n.label
2
# INDEX索引
Neo4j SQL支持节点或关系属性上的索引,以提高应用程序的性能。
我们可以为具有相同标签名称的所有节点的属性创建索引。
我们可以在MATCH或WHERE或IN运算符上使用这些索引列来改进CQL Command的执行。
Neo4J索引操作
- Create Index 创建索引
- Drop Index 丢弃索引
# 创建索引
create index on :`西游` (name)
# 删除索引
drop index on :`西游` (name)
2
3
4
# UNIQUE约束
在Neo4j数据库中,CQL CREATE命令始终创建新的节点或关系,这意味着即使您使用相同的值,它也会插入一个新行。 根据我们对某些节点或关系的应用需求,我们必须避免这种重复。
像SQL一样,Neo4j数据库也支持对NODE或Relationship的属性的UNIQUE约束
UNIQUE约束的优点
- 避免重复记录。
- 强制执行数据完整性规则。
#创建唯一约束
create constraint on (n:xiyou) assert n.name is unique
#删除唯一约束
drop constraint on (n:xiyou) assert n.name is unique
2
3
4
# DISTINCT
这个函数的用法就像SQL中的distinct关键字,返回的是所有不同值。
match (n:`西游`) return distinct(n.name)
# 常用函数
函数 | 用法 |
---|---|
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)
# 关系函数
Neo4j CQL提供了一组关系函数,以在获取开始节点,结束节点等细节时知道关系的细节。
功能 | 描述 |
---|---|
STARTNODE | 它用于知道关系的开始节点 |
ENDNODE | 它用于知道关系的结束节点 |
ID | 它用于知道关系的ID |
TYPE | 它用于知道字符串表示中的一个关系的TYPE |
例:
match (a)-[r] ->(b) return id(r),type(r)
# Neo4j-admin使用
# 数据库备份
对Neo4j数据进行备份、还原、迁移的操作时,要关闭neo4j
cd %NEO4J_HOME%/bin
#关闭neo4j
neo4j stop
#备份
neo4j-admin dump --database=graph.db --to=/neo4j/backup/graph_backup.dump
2
3
4
5
# 数据库恢复
还原、迁移之前 ,要关闭neo4j服务。
#数据导入
neo4j-admin load --from=/neo4j/backup/graph_backup.dump --database=graph.db -- force
#重启服务
neo4j start
2
3
4
# 五、Spring Boot整合Neo4j
添加Neo4j依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
2
3
4
application.yml
spring:
data:
neo4j:
uri: bolt://localhost:7687
username: neo4j
password: 123456
2
3
4
5
6
创建实体
- @NodeEntity:标明是一个节点实体
- @RelationshipEntity:标明是一个关系实体
- @Id:实体主键
- @Property:实体属性
- @GeneratedValue:实体属性值自增
- @StartNode:开始节点(可以理解为父节点)
- @EndNode:结束节点(可以理解为子节点)
@Data
@Builder
@NodeEntity("person")
public class Person implements Serializable{
@Id
@GeneratedValue
private Long id;
@Property("name")
private String name;
}
@Data
@NoArgsConstructor
@RelationshipEntity(type = "徒弟")
public class PersonRelation implements Serializable {
@Id
@GeneratedValue
private Long id;
@StartNode
private Person parent;
@EndNode
private Person child;
@Property
private String relation;
public PersonRelation(Person parent, Person child, String relation) {
this.parent = parent;
this.child = child;
this.relation = relation;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
创建接口继承Neo4jRepository
@Repository
public interface PersonRelationRepository extends Neo4jRepository<PersonRelation,Long> {
}
@Repository
public interface PersonRepository extends Neo4jRepository<Person,Long> {
@Query("Match (p:person) -[*]->(s:person) where id(p)={0} return s")
List<Person> findChildList(Long pId);
@Query("Match (p:person {name:{0}}) -[*]->(s:person) return s")
List<Person> findChildList(String name);
@Query("Match (p:person) -[*]->(s:person {name:{0}}) return p")
List<Person> findParentList(String name);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17