Springboot集成Neo4j
1.为什么图形数据库?
生活在一个互联的世界中,大多数领域需要处理丰富的连接集以了解真正发生的事情。通常,我们发现项目之间的联系与项目本身一样重要。
虽然现有的关系数据库可以存储这些关系,但它们通过昂贵的JOIN
操作或交叉查找来导航它们,通常与严格的模式相关联。事实证明,“关系”数据库处理关系的能力很差。在图形数据库中,没有 JOIN 或查找。关系以更灵活的格式与数据元素(节点)一起本地存储。系统的一切都针对快速遍历数据进行了优化;每个核心每秒数百万个连接。
图形数据库存储节点和关系而不是表或文档。数据的存储就像您在白板上勾画想法一样。您的数据的存储不会将其限制在预定义的模型中,从而允许以非常灵活的方式思考和使用它。
图数据库是以图结构的形式存储数据的数据库。 它以节点,关系和属性的形式存储应用程序的数据。 正如RDBMS以表的“行,列”的形式存储数据,GDBMS以图的形式存储数据。
图形数据库数据模型的主要构建块是:
-
节点
-
关系
-
属性
节点是图中的实体。
-
节点可以用labels 标记,代表它们在您的域中的不同角色。(例如,
Person
)。 -
节点可以包含任意数量的键值对或 属性。(例如,
name
) -
节点标签还可以将元数据(例如索引或约束信息)附加到某些节点。
关系在两个节点实体(例如,Person ->
LOVES ->
Person)之间提供定向的、命名的连接。
-
关系总是有方向、类型、开始节点和结束节点,并且它们可以有属性,就像节点一样。
-
在不牺牲性能的情况下,节点可以具有任意数量或类型的关系。
-
尽管关系总是定向的,但它们可以在任何方向上有效地导航。
对比其他数据库
关系型数据库对比
关系型数据库(RDBMS) | 图数据库 |
---|---|
表 | 图 |
行 | 节点 |
列和数据 | 属性和数据 |
约束 | 关系 |
Nosql型数据库对比
分类 | 数据模型 | 优势 | 劣势 | 举例 |
---|---|---|---|---|
键值数据库 | 哈希表 | 查找速度快 | 数据无结构化,通常只被当作字符串或者二进制数据 | Redis |
列存储数据库 | 列式数据存储 | 查找速度快;支持分布横向扩展;数据压缩率高 | 功能相对受限 | HBase |
文档型数据库 | 键值对扩展 | 数据结构要求不严格;表结构可变;不需要预先定义表结构 | 查询性能不高,缺乏统一的查询语法 | MongoDB |
图数据库 | 节点和关系组成的图 | 利用图结构相关算法(最短路径、节点度关系查找等) | 可能需要对整个图做计算,不利于图数据分布存储 | Neo4j、JanusGraph |
2.什么是Neo4j?
Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。
Neo4j是一个网络——面向网络的数据库——也就是说,它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络上而不是表中。网络(从数学角度叫做图)是一个灵活的数据结构,可以应用更加敏捷和快速的开发模式。
- 是世界上最先进的图数据库之一 ,提供原生的图数据存储,检索和处理
- 采用属性图模型(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查询语言命令是人性化的可读格式,非常容易学习
- 使用简单而强大的数据模型
- 它不需要复杂的连接来检索连接的/相关的数据,因为它很容易检索它的相邻节点或关系细节没有连接或索引
3.图形理论基础
图是一组节点和连接这些节点的关系。图形数据存储在节点和关系在属性的形式。属性是键值对表示数据。
图形是一组节点和连接这些节点的关系。 图形以属性的形式将数据存储在节点和关系中。 属性是用于表示数据的键值对。
在图形理论中,我们可以表示一个带有圆的节点,节点之间的关系用一个箭头标记表示。
节点和属性
节点和关系
复杂的节点关系
4.Neo4j数据模型
Neo4j图数据库主要有以下组成元素:
- 节点
- 属性
- 关系
- 标签
节点
节点(Node)是图数据库中的一个基本元素,来表示一个实体,在Neo4j中节点可以包含多个属性(Property)和多个标签(Label)。
- 节点通过关系连接到其他节点
- 节点可以具有一个或多个属性(即,存储为键/值对的属性)
- 节点有一个或多个标签,用于描述其在图表中的作用
属性
属性(Property)是用于描述图节点和关系的键值对
- 属性是命名值,其中名称(或键)是字符串
- 属性可以被索引和约束
- 可以从多个属性创建复合索引
关系
节点与节点连接起来构成图。关系也称为图论的边,其始端和末端都必须是节点,关系必须指向与节点,不能指向到空,开始与结束必须有节点。
关系和节点一样可以包含多个属性,但关系只能有一个类型(Type)。
- 关系连接两个节点
- 关系是方向性的
- 节点可以有多个甚至递归的关系
- 关系可以有一个或多个属性(即存储为键/值对的属性)
基于方向性,Neo4j关系被分为两种主要类型:
- 单向关系
- 双向关系
标签
标签(Label)用于描述节点和关系的补充属性,节点或关系可以包含一个或多个标签。
- 标签用于将节点分组
- 一个节点可以具有多个标签
- 对标签进行索引以加速在图中查找节点
5.使用场景
...............
# 进入opt目录
cd opt
# 在opt目录下创建neo4j目录
mkdir neo4j
cd neo4j
# 在neo4j目录下创建data、logs、conf、import目录
mkdir data logs conf import
# 授权目录logs、data,次数如果不授权,启动容器后会报错
chmod 777 logs
chmod 777 data
# 查看neo4j镜像
docker search neo4j
# 拉取镜像
docker pull neo4j
# 启动neo4j容器
docker run -d --name neo4j --restart=always \
-p 7474:7474 -p 7687:7687 \
-v /opt/neo4j/data:/data \
-v /opt/neo4j/logs:/logs \
-v /opt/neo4j/conf:/var/lib/neo4j/conf \
-v /opt/neo4j/import:/var/lib/neo4j/import \
--env NEO4J_AUTH=neo4j/123456 neo4j# 查看启动日志
docker logs -f neo4j
# 进入配置文件目录
cd /opt/neo4j/conf
vim neo4j.conf# neo4j.conf配置内容如下
dbms.tx_log.rotation.retention_policy=100M sizedbms.memory.pagecache.size=512M
dbms.default_listen_address=0.0.0.0
dbms.connector.bolt.listen_address=0.0.0.0:7687
dbms.connector.http.listen_address=0.0.0.0:7474
dbms.directories.logs=/logs# 配置完后重启容器生效
docker restart neo4j
Cypher语言是为处理图形数据而构建的,CQL代表Cypher查询语言。 像Mysql数据库具有查询语言SQL, Neo4j具有CQL作为查询语言。
- 它是Neo4j图形数据库的查询语言
- 它是一种声明性模式匹配语言
- 它遵循SQL语法。
- 它的语法是非常简单且人性化、可读的格式
CQL命令 | 用法 |
---|---|
CREATE | 创建节点,关系和属性 |
MATCH | 检索有关节点,关系和属性数据 |
RETURN | 返回查询结果 |
WHERE | 提供条件过滤检索数据 |
DELETE | 删除节点和关系 |
REMOVE | 删除节点和关系的属性 |
ORDER BY | 排序检索数据 |
SET | 添加或更新标签 |
CQL数据类型 | |
---|---|
boolean | 用于表示布尔文字:true,false。 |
byte | 用于表示8位整数。 |
short | 用于表示16位整数。 |
int | 用于表示32位整数。 |
long | 用于表示64位整数。 |
float | I用于表示32位浮点数。 |
double | 用于表示64位浮点数。 |
char | 用于表示16位字符。 |
String | 用于表示字符串。 |
CQL描述实体之间的标签、属性、关系信息。如:
(a) <- [:knows] - (c) -[:knows] -> (b) -[:knows] -> (a)
1、基本命令
文档地址:Introduction - Neo4j Cypher Manual
CREATE创建
创建节点
CREATE (
: )
语法说明
语法元素 | 描述 |
---|---|
CREATE | 它是一个Neo4j CQL命令。 |
它是我们要创建的节点名称。 | |
它是一个节点标签名称 |
创建具有属性的节点
CREATE (
:
{
:
........
:
}
)
语法说明:
语法元素 | 描述 |
---|---|
它是我们将要创建的节点名称。 | |
它是一个节点标签名称 | |
属性是键值对。 定义将分配给创建节点的属性的名称 | |
属性是键值对。 定义将分配给创建节点的属性的值 |
创建关系
Neo4j图数据库遵循属性图模型来存储和管理其数据。
根据属性图模型,关系应该是定向的。否则, Neo4j将抛出一个错误消息。
基于方向性,Ne04j关系被分为两种主要类型。
- 单向关系
- 双向关系
新节点无属性关系
CREATE
(: )-
[: ]->
(: )
RETURN
语法说明:
语法元素 | 描述 |
---|---|
CREATE,RETURN | 他们是Neo4J CQL关键字。 |
它用于创建关系的“From Node”的名称。 | |
它用于创建关系的“From Node”的标签名称。 | |
它用于创建关系的“To Node”的名称。 | |
它用于创建关系的“To Node”的标签名称。 | |
这是一个关系的名称。 | |
它是一个关系的标签名称。 |
注意 -
在此语法中,RETURN子句是可选的。
新节点与属性的关系
CREATE
(: { })-
[: { }]
->(: { })
RETURN
{
: ,
: ,
...
:
}
语法说明:
语法元素 | 描述 |
---|---|
CREATE,RETURN | 他们是Neo4J CQL关键字。 |
它用于创建关系的“From Node”的名称。 | |
它用于创建关系的“From Node”的标签名称。 | |
它用于创建关系的“To Node”的名称。 | |
它用于创建关系的“To Node”的标签名称。 | |
这是一个关系的名称。 | |
它是一个关系的标签名称。 |
注意 -
在此语法中,RETURN子句是可选的。
CREATE (v1:TXVIDEO{title:"a",updated_by:"123",uploaded_date:"2022-12-09"})-[movie:ACTION_MOVIES{rating:1}]->(v2:TXVIDEO2{title:"b",updated_by:"456",uploaded_date:"2022-12-13"})
使用已知节点创建带属性的关系
MATCH (
: ),( : )
CREATE
()-[ :
{}]->( )
RETURN
语法说明:
语法元素 | 描述 |
---|---|
MATCH,CREATE,RETURN | 他们是Neo4J CQL关键词。 |
它是用于创建关系的“From Node”的名称。 | |
它是用于创建关系的“From Node”的标签名称。 | |
它是用于创建关系的“To Node”的名称。 | |
它是用于创建关系的“To Node”的标签名称。 | |
这是一个关系的名称。 | |
它是一个关系的标签名称。 | |
它是分配给新创建关系的属性(名称 - 值对)的列表。 |
{
: ,
: ,
...
:
}
语法元素 | 描述 |
---|---|
它是分配给新创建关系的属性的名称。 其中x是1,2,... n个值 | |
这是一个分配给新创建关系的Property的值。 其中x是1,2,... n个值 |
MATCH (c:Customer),(cc:CreditCard) CREATE (c)-[r:DO_SHOPPING_WITH{price:55000}]->(cc) RETURN r
这里关系名称为“DO_SHOPPING_WITH” 关系标签为“r”。
shopdate和price是关系“r”的属性。
cust和Customer分别是客户节点的节点名称和节点标签名称。
cc和CreditCard分别是CreditCard节点的节点名和节点标签名。
没有属性的关系与现有节点
MATCH (
: ),( : )
CREATE
()-[ : { }]->( )
RETURN
语法说明:
语法元素 | 描述 |
---|---|
MATCH,CREATE,RETURN | 他们是Neo4J CQL关键字。 |
它用于创建关系的“From Node”的名称。 | |
它用于创建关系的“From Node”的标签名称。 | |
它用于创建关系的“To Node”的名称。 | |
它用于创建关系的“To Node”的标签名称。 | |
这是一个关系的名称。 | |
它是一个关系的标签名称。 |
注意:
在此语法中,RETURN子句是可选的。
MATCH (e:Customer),(cc:CreditCard) CREATE (e)-[r:DO_SHOPPING_WITH ]->(cc)
这里关系名称为“DO_SHOPPING_WITH”
关系标签为“r”。
e和Customer分别是客户节点的节点名称和节点标签名称。
cc和CreditCard分别是CreditCard节点的节点名和节点标签名。
创建标签
Label是Neo4j数据库中的节点或关系的名称或标识符。
单个标签到节点
CREATE (
: )
多个标签到节点
CREATE (
: : .....: )
单个标签到关系
CREATE (
: )-
[: ]
->(: )
语法说明
语法元素 | 描述 |
---|---|
CREATE 创建 | 它是一个Neo4J CQL关键字。 |
它是From节点的名称。 | |
它是To节点的名称。 | |
它是From节点的标签名称 | |
它是To节点的标签名称。 | |
它是一个关系的名称。 | |
它是一个关系的标签名称。 |
CREATE (p1:Profile1)-[r1:LIKES]->(p2:Profile2)
这里p1和profile1是节点名称和节点标签名称“From Node”
p2和Profile2是“To Node”的节点名称和节点标签名称
r1是关系名称
LIKES是一个关系标签名称
MATCH查询
- 检索节点的某些属性
- 检索节点的所有属性
- 检索节点和关联关系的某此属性
- 检索节点和关联关系的所有属性
MATCH (
: )
语法元素 | 描述 |
---|---|
这是我们要创建一个节点名称。 | |
这是一个节点的标签名称 |
# 查询Dept下的内容MATCH (dept:Dept) return dept# 查询Employee标签下 id=123,name="Lokesh"的节点MATCH (p:Employee {id:123,name:"Lokesh"}) RETURN p## 查询Employee标签下name="Lokesh"的节点,使用(where命令)MATCH (p:Employee)WHERE p.name = "Lokesh"RETURN p
RETURN-返回
- 检索节点的某些属性
- 检索节点的所有属性
- 检索节点和关联关系的某些属性
- 检索节点和关联关系的所有属性
RETURN
. ,
........
.
语法说明:
语法元素 | 描述 |
---|---|
它是我们将要创建的节点名称。 | |
属性是键值对。 |
MATCH (dept: Dept)RETURN dept.deptno,dept.dname,dept.location
WHERE子句
像SQL-样,Neo4j CQL在CQL MATCH命令中提供了WHERE子句来过滤MATCH查询的结果。
WHERE
WHERE
语法说明:
语法元素 | 描述 |
---|---|
WHERE | 它是一个Neo4j CQL关键字。 |
它是节点或关系的属性名称。 | |
它是Neo4j CQL比较运算符之一。 | |
它是一个字面值,如数字文字,字符串文字等。 |
布尔运算符
布尔运算符 | 描述 |
---|---|
AND | 它是一个支持AND操作的Neo4j CQL关键字。 |
OR | 它是一个Neo4j CQL关键字来支持OR操作。 |
NOT | 它是一个Neo4j CQL关键字支持NOT操作。 |
XOR | 它是一个支持XOR操作的Neo4j CQL关键字。 |
比较运算符
布尔运算符 | 描述 |
---|---|
= | 它是Neo4j CQL“等于”运算符。 |
<> | 它是一个Neo4j CQL“不等于”运算符。 |
< | 它是一个Neo4j CQL“小于”运算符。 |
> | 它是一个Neo4j CQL“大于”运算符。 |
<= | 它是一个Neo4j CQL“小于或等于”运算符。 |
>= | 它是一个Neo4j CQL“大于或等于”运算符。 |
MATCH (emp:Employee) WHERE emp.name = 'Abc' OR emp.name = 'Xyz'RETURN emp
使用WHERE子句创建关系
MATCH (
: ),( : )
WHERE
CREATE ()-[ :
{}]->( )
语法说明:
语法元素 | 描述 |
---|---|
MATCH,WHERE,CREATE | 他们是Neo4J CQL关键字。 |
它是一个用于创建关系的节点一标签名称。 | |
它是一个用于创建关系的节点名称。 | |
它是一个用于创建关系的节点一标签名称。 | |
它是一个用于创建关系的节点名称。 | |
它是一个Neo4J CQL WHERE子句条件。 | |
这是新创建的节点一和节点二之间的关系的标签名称。 | |
这是新创建的节点1和节点2之间的关系的名称。 | |
这是一个新创建节点一和节点二之间关系的属性列表(键 - 值对)。 |
MATCH (cust:Customer),(cc:CreditCard) WHERE cust.id = 11 AND cc.id= 23 CREATE (cust)-[r:DO_SHOPPING_WITH{price:55000}]->(cc) RETURN r
DELETE删除
Neo4j使用CQL DELETE子句
- 删除节点
- 删除节点及相关节点和关系。
删除节点(前提:节点不存在关系)
DELETE
MATCH (e: Employee) DELETE e
删除节点和关系
DELETE
, ,
语法元素 | 描述 |
---|---|
DELETE | 它是一个Neo4j CQL关键字。 |
它是用于创建关系 | |
它是用于创建关系 | |
它是一个关系名称,它在 |
MATCH (cc: CreditCard)-[rel]-(c:Customer)
DELETE cc,c,rel
REMOVE-删除
- 删除节点或关系的标签
- 删除节点或关系的属性
移除属性
REMOVE
. ,
. ,
....
.
CREATE (book:Book {id:122,title:"Neo4j Tutorial",pages:340,price:250})
MATCH (book : Book) RETURN book
MATCH (book { id:122 })
REMOVE book.price
RETURN book
移除标签
REMOVE
: ,
....
:
新增一个节点,有多个标签
CREATE (n:Person:Director{born: 1222, name: "abci"})
删除一个标签
MATCH (n:Person:Director{born: 1222, name: "abci"})REMOVE n:DirectorRETURN n
SET子句
- 向现有节点或关系添加新属性
- 添加或更新属性值
SET
<属性名称列表>语法:
. ,
. ,
....
.
语法说明:
语法元素 | 描述 |
---|---|
这是一个节点的标签名称。 | |
它是一个节点的属性名。 |
MATCH (book:Book)SET book.title = 'abc'RETURN book
ORDER BY排序
MATCH查询返回的结果进行升序或降序排序。默认情况下,它按升序对行进行排序。如果我们要按降序对它们进行排序, 我们需要使用DESC子句
ORDER BY
[DESC]
. ,
. ,
....
.
MATCH (emp:Employee)RETURN emp.empid,emp.name,emp.salary,emp.deptnoORDER BY emp.name DESC
UNION合并
与SQL一样,Neo4j CQL有两个子句,将两个不同的结果合并成一组结果
- UNION
- UNION ALL
UNION子句
它将两组结果中的公共行组合并返回到一组结果中。 它不从两个节点返回重复的行。
UNION
UNION ALL
MATCH (cc:CreditCard)RETURN cc.id as id,cc.number as number,cc.name as name, cc.valid_from as valid_from,cc.valid_to as valid_toUNIONMATCH (dc:DebitCard)RETURN dc.id as id,dc.number as number,dc.name as name, dc.valid_from as valid_from,dc.valid_to as valid_to
MATCH (cc:CreditCard)RETURN cc.id as id,cc.number as number,cc.name as name, cc.valid_from as valid_from,cc.valid_to as valid_toUNION ALLMATCH (dc:DebitCard)RETURN dc.id as id,dc.number as number,dc.name as name, dc.valid_from as valid_from,dc.valid_to as valid_to
LIMIT和SKIP子句
过滤或限制查询返回的行数。LIMIT返回前几行,SKIP忽略前几行。
LIMIT
SKIP
前2行
MATCH (n)RETURN nLIMIT 2
忽略前2行
MATCH (n)RETURN n SKIP 2
MERGE-合并
-
创建节点,关系和属性
-
为从数据库检索数据
MERGE命令是CREATE命令和MATCH命令的组合。
MERGE = CREATE + MATCH
如果存在,则返回结果,不存在,则创建新的节点/关系并返回结果。
MERGE (
:
{
:
.....
:
})
语法说明:
语法元素 | 描述 |
---|---|
MERGE | 它是一个Neo4j CQL关键字。 |
它是节点或关系的名称。 | |
它是节点或关系的标签名称。 | |
它是节点或关系的属性名称。 | |
它是节点或关系的属性值。 | |
: | 使用colon(:)运算符来分隔节点或关系的属性名称和值。 |
创建具有属性:Id,Name的Profile节点
MERGE (gp2:GoogleProfile2{ Id: 201402,Name:"Nokia"})
创建具有相同属性的同一个Profile节点:Id,Name。
MERGE (gp2:GoogleProfile2{ Id: 201402,Name:"Nokia"})
检索所有Profile节点详细信息并观察结果
MATCH (gp2:GoogleProfile2)
RETURN gp2.Id,gp2.Name
NULL值
Neo4j CQL将空值视为对节点或关系的属性的缺失值或未定义值。当我们创建一个具有现有节点标签名称但未指定其属性值的节点时,它将创建一个具有NUL属性值的新节点。
MATCH (e:Employee) WHERE e.id IS NOT NULLRETURN e.id,e.name,e.sal,e.deptno
IN操作符
与SQL一样,Neo4j CQL提供了一个IN运算符。 以便为CQL命令提供值的集合。
MATCH (n:Person)WHERE n.name IN ["Carrie-Anne Moss", "Lilly Wachowski"]RETURN n;
2、ID属性
在Neo4j中,“Id”是节点和关系的默认内部属性。 这意味着,当我们创建一个新的节点或关系时,Neo4j数据库服务器将为内部使用分配一个数字。 它会自动递增。相当于Mysql中的自动主键。
CREATE (tweet:Tweet{message:"Hello"})
MATCH (tweet:Tweet{message:"Hello"})
RETURN tweet
注意
- 节点的Id属性的最大值约为35亿。
- Id的最大值关系的属性的大约35亿。
索引
Neo4j SQL支持节点或关系属性上的索引,以提高应用程序的性能。
- Create Index 创建索引
- Drop Index 丢弃索引
1.创建索引
CREATE INDEX ON :
( )
CREATE INDEX ON :Customer (name)
2.丢弃索引
DROP INDEX ON :
( )
DROP INDEX ON :Customer (name)
3.复合索引
create index on:Person(age,gender)
4.全文索引
常规索引只能对字符串进行精确匹配或前后缀索引,而全文索引可以匹配字符串任何位置的词语。使用db.index.fulltext.createNodeIndex 和 db.index.fulltext.createRelationshipIndex可以分别为节点和关系创建全文索引。在创建索引时,必须指定唯一的名称,用于查询和删除索引时要引用。
call db.index.fulltext.createNodeIndex("索引名",[Label,Label],[属性,属性])
5.查看索引
call db.indexes 或:schema
唯一索引
为了防止重复,设置唯一约束。
- 避免重复记录
- 强制执行数据完整性规则
创建唯一索引
CREATE CONSTRAINT ON (变量:
) ASSERT 变量. IS UNIQUE
语法元素 | 描述 |
---|---|
CREATE CONSTRAINT ON | 它是一个Neo4j CQL关键字。 |
它是节点或关系的标签名称。 | |
ASSERT | 它是一个Neo4j CQL关键字。 |
它是节点或关系的属性名称。 | |
IS UNIQUE | 它是一个Neo4j CQL关键字,通知Neo4j数据库服务器创建一个唯一约束。 |
CREATE CONSTRAINT ON (cc:CreditCard) ASSERT cc.number IS UNIQUE
删除唯一索引
DROP CONSTRAINT ON (
) ASSERT IS UNIQUE
语法元素 | 描述 |
---|---|
DROP CONSTRAINT ON | 它是一个Neo4j CQL关键字。 |
它是节点或关系的标签名称。 | |
ASSERT | 它是一个Neo4j CQL关键字。 |
它是节点或关系的属性名称。 | |
IS UNIQUE | 它是一个Neo4j CQL关键字,通知Neo4j数据库服务器创建一个唯一约束。 |
DROP CONSTRAINT ON (cc:CreditCard) ASSERT cc.number IS UNIQUE
查看约束
call db.constraints
#或
:schema
DISTINCT
像SQL中的distinct关键字,返回的是所有不同值。
MATCH (n:Person)RETURN DISTINCT (n.name)
3、 常用函数
函数 | 用法 |
---|---|
String字符串 | 它们用于使用String字面量 |
Aggregation聚合 | 它们用于对CQL查询结果执行一些聚合操作 |
Relationship关系 | 他们用于获取关系的细节,如startnode, endnode等 |
字符串函数
功能 | 描述 |
---|---|
UPPER | 它用于将所有字母更改为大写字母 |
LOWER | 它用于将所有字母改为小写字母 |
SUBSTRING | 它用于获取给定String的子字符串 |
REPLACE | 它用于替换一个字符串的子字符串 |
MATCH (e)RETURN id(e), e.name, substring(e.name, 0, 2)
AGGREGATION-聚合
聚集功能 | 描述 |
---|---|
COUNT | 它返回由MATCH命令返回的行数 |
MAX | 它从MATCH命令返回的一组行返回最大值 |
MIN | 它返回由MATCH命令返回的一组行的最小值 |
SUM | 它返回由MATCH命令返回的所有行的求和值 |
AVG | 它返回由MATCH命令返回的所有行的平均值 |
MATCH (e:Employee) RETURN COUNT(*)
关系函数
功能 | 描述 |
---|---|
STARTNODE | 它用于知道关系的开始节点 |
ENDNODE | 它用于知道关系的结束节点 |
ID | 它用于知道关系的ID |
TYPE | 它用于知道字符串表示中的一个关系的TYPE |
STARTNODE (
)
ENDNODE ()
MATCH (a)-[movie:ACTION_MOVIES]->(b) RETURN STARTNODE(movie)MATCH (a)-[movie:ACTION_MOVIES]->(b) RETURN ENDNODE(movie)
ID和TYPE关系函数来检索关系的Id和类型详细信息。
MATCH (a)-[movie:ACTION_MOVIES]->(b) RETURN ID(movie),TYPE(movie)
shortestPath 查询最短路径
应用理论:6层关系理论:任何两个事物之间的关系都不会超过6层 查询最短路径的必要性 allShortestPaths [*..n] 用于表示获取n层关系
match p = shortestpath((:hero{name:"孙尚香"})-[*..3]-(:hero{name:"武则天"})) return pmatch p = allshortpath((:hero{name:"孙尚香"})-[*..3]-(:hero{name:"武则天"})) return p
正则
(n)-->(m)Relationship from n to m.(n)-[*1..5]->(m)Variable length path of between 1 and 5 relationshipsfrom n to m.
collect
查询如下3个表的全部内容:哪些公司卖哪些货?
MATCH (s:Supplier)-->(:Product)-->(c:Category)RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories
collect(distinct c.categoryName) 单独对c.categoryName去重
4、数据库备份
5.导出与导入
数据库导出
neo4j-admin dump --database=
--to=
数据库导入
neo4j-admin load --from=
--database= [--force]
6、调优
两个命令:
- Explain :解释机制,加入该关键字的Cypher语句可以分析其执行过程。
- Profile:画像机制,了解执行计划详细与查询的结果
profile match (p:Person) return p
7、事务
Neo4j支持ACID特性
- 所有对Neo4j数据库的数据修改操作都必须封装在事务中
- READ_COMMITTED默认的事务级别。
- 死锁保护已经内置到核心事务管理。
- 除特殊说明,Neo4j的API操作都是线程安全的,Neo4j数据库的操作也就没有必要使用外部的同步方法。
一、原生API
org.neo4j neo4j 3.5.5 org.neo4j neo4j-ogm-bolt-driver 3.2.14
package com.lean.neo4j.test;import org.apache.commons.collections4.MapUtils;import org.apache.commons.lang3.time.StopWatch;import org.neo4j.driver.v1.*;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;// Neo4j Server(服务器模式)//嵌入式模式public class Neo4jServerMain { private static final Integer DATA_SIZE = 10000; public static void main(String[] args) {// inertNeo4j(); queryData(); } public static void queryData(){ Driver driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "123456")); Session session = driver.session(); String cql = "MATCH p=shortestPath((n:backPerson {userName:$startName})-[*]-(n2:backPerson {userName:$endName} )) RETURN p";// String cql = "MATCH (n1:backPerson)-[r]->(n2:backPerson) RETURN r, n1, n2 LIMIT 25"; StatementResult result = session.run(cql, Values.parameters("startName", "user1939", "endName", "user1921"));// StatementResult result = session.run(cql); while (result.hasNext()) { Record record = result.next(); System.out.println(record.toString()); } session.close(); driver.close(); } private static void inertNeo4j() { // 构造数据, 数据和pg 库里面的数据一样 List
二、SpringBoot整合Neo4j
文档地址:Spring Data Neo4j
springboot 2.7 Neo4j
pom
org.springframework.boot spring-boot-starter-data-neo4j
添加配置
spring: neo4j: uri: bolt://localhost:7687 authentication: username: neo4j password: 123456 #database: yourDatabase
注解
@Node:应用于类级别以指示此类是映射到数据库的候选者。
@Id:应用于字段级别以标记用于标识目的的字段。
@GeneratedValue:在字段级别应用,@Id以指定应如何生成唯一标识符。
@Property:应用于字段级别以修改从属性到特性的映射。
@CompositeProperty:在字段级别应用于应作为复合读回的 Map 类型的属性。请参阅复合属性。
@Relationship:应用于字段级别以指定关系的详细信息。
@DynamicLabels:应用于字段级别以指定动态标签的来源。
@RelationshipProperties:应用于类级别以指示此类作为关系属性的目标。
@TargetNode: 应用在注解为 的类的某个字段上@RelationshipProperties,从另一端的角度来标记该关系的目标。
package com.lean.neo4j.entity;import lombok.Data;import org.springframework.data.annotation.Version;import org.springframework.data.neo4j.core.schema.*;import org.springframework.data.neo4j.core.support.UUIDStringGenerator;import java.util.ArrayList;import java.util.List;@Data@Node("Movie")public class Movie { @Id @GeneratedValue// @GeneratedValue(UUIDStringGenerator.class) private Long id; //支持乐观锁定 //判断这个实体是新的还是之前已经持久化过。 //@Version private String title; //映射属性 @Property("tagline") private String description; //INCOMING 指向自己 //OUTGOING 指向别人 //动态关系 指向自己 @Relationship(type = "ACTED_IN", direction = Relationship.Direction.INCOMING) private List actorsAndRoles = new ArrayList<>(); //关系 指向别人 @Relationship(type = "DIRECTED", direction = Relationship.Direction.INCOMING) private List directors = new ArrayList<>(); public Movie(String title, String description) { this.title = title; this.description = description; }}
package com.lean.neo4j.entity;import lombok.Data;import org.springframework.data.neo4j.core.schema.GeneratedValue;import org.springframework.data.neo4j.core.schema.Id;import org.springframework.data.neo4j.core.schema.Node;@Data@Node("Person")public class Person { @Id @GeneratedValue// @GeneratedValue(value = MyIdGenerator2.class)// @GeneratedValue(generatorRef = "myIdGenerator") private Long id; private String name; private Integer born; public Person(Integer born, String name) { this.born = born; this.name = name; } public Integer getBorn() { return born; } public String getName() { return name; }}
package com.lean.neo4j.entity;import lombok.Data;import org.springframework.data.neo4j.core.schema.RelationshipId;import org.springframework.data.neo4j.core.schema.RelationshipProperties;import org.springframework.data.neo4j.core.schema.TargetNode;import java.util.List;@Data@RelationshipPropertiespublic class Roles { @RelationshipId private Long id; private final List roles; @TargetNode private Person person; public Roles(Person person, List roles) { this.person = person; this.roles = roles; } public List getRoles() { return roles; }}
package com.lean.neo4j.entity;import org.springframework.data.neo4j.core.Neo4jClient;import org.springframework.data.neo4j.core.schema.IdGenerator;import org.springframework.stereotype.Component;@Componentclass MyIdGenerator implements IdGenerator { private final Neo4jClient neo4jClient; public MyIdGenerator(Neo4jClient neo4jClient) { this.neo4jClient = neo4jClient; } @Override public String generateId(String primaryLabel, Object entity) { return neo4jClient.query("YOUR CYPHER QUERY FOR THE NEXT ID") .fetchAs(String.class).one().get(); }}
package com.lean.neo4j.entity;import org.springframework.data.neo4j.core.schema.IdGenerator;import org.springframework.util.StringUtils;import java.util.concurrent.atomic.AtomicInteger;public class MyIdGenerator2 implements IdGenerator { private final AtomicInteger sequence = new AtomicInteger(0); @Override public String generateId(String primaryLabel, Object entity) { return StringUtils.uncapitalize(primaryLabel) + "-" + sequence.incrementAndGet(); }}
package com.lean.neo4j.entity;import org.springframework.data.neo4j.core.schema.GeneratedValue;import org.springframework.data.neo4j.core.schema.Id;import org.springframework.data.neo4j.core.schema.Node;@Nodepublic class SystemEntity { @Id @GeneratedValue private Long id; private String name; public SystemEntity() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
1.Neo4jTemplate 操作
@Autowired private Neo4jTemplate neo4jTemplate; @Test void TestNoRepository() { // 删除所有节点和关系(删除节点会响应删除关联关系),避免后续创建节点重复影响 neo4jTemplate.deleteAll(Movie.class); neo4jTemplate.deleteAll(Person.class); // 创建节点 Movie movie = new Movie("流浪地球", "是由中国电影股份有限公司、北京京西文化旅游股份有限公司、郭帆文化传媒(北京)有限公司、北京登峰国际文化传播有限公司联合出品,由郭帆执导,吴京特别出演、屈楚萧、赵今麦、李光洁、吴孟达等领衔主演的科幻冒险电影"); // 添加关系 movie.getActorsAndRoles().add(new Roles(new Person(1994, "刘启"), Collections.singletonList("初级驾驶员"))); movie.getActorsAndRoles().add(new Roles(new Person(2002, "刘培强"), Collections.singletonList("中国航天员"))); movie.getActorsAndRoles().add(new Roles(new Person(1952, "韩子昂"), Collections.singletonList("高级驾驶员"))); movie.getActorsAndRoles().add(new Roles(new Person(2002, "韩朵朵"), Collections.singletonList("初中生"))); movie.getActorsAndRoles().add(new Roles(new Person(1981, "王磊"), Collections.singletonList("救援队队长"))); movie.getActorsAndRoles().add(new Roles(new Person(1991, "李一一"), Collections.singletonList("技术观察员"))); movie.getActorsAndRoles().add(new Roles(new Person(1974, "何连科"), Collections.singletonList("救援队队员"))); movie.getActorsAndRoles().add(new Roles(new Person(1991, "Tim"), Collections.singletonList("中美混血儿"))); movie.getDirectors().add(new Person(1974, "吴京")); // 存入图数据库持久化 neo4jTemplate.save(movie); // 查询 操作 两种方式 // 1.手写cypherQuery toExecutableQuery // 2.调用neo4jTemplate提供的方法. List personList = neo4jTemplate.findAll(Person.class); System.out.println(personList); Map map = new HashMap<>(); map.put("usedName", "王磊"); QueryFragmentsAndParameters parameters = new QueryFragmentsAndParameters("MATCH (n:Person) where n.name = $usedName return n",map); Person person = neo4jTemplate.toExecutableQuery(Person.class, parameters).getSingleResult().get(); System.out.println(person); // 3. 通过属性关系查询节点 map = new HashMap<>(); map.put("roles",Collections.singletonList("救援队队员")); // 方法1.使用toExecutableQuery查询 parameters = new QueryFragmentsAndParameters("MATCH (n:Person) -[relation:ACTED_IN]-> (m:Movie) WHERE relation.roles = $roles RETURN n",map); Optional role = neo4jTemplate.toExecutableQuery(Person.class, parameters).getSingleResult(); System.out.println(role); // 方法2.使用findOne查询 role = neo4jTemplate.findOne("MATCH (person:Person) -[relation:ACTED_IN]-> (movie:Movie) WHERE relation.roles = $roles RETURN person",map,Person.class); System.out.println(role); Long userId = person.getId(); // 更新 person.setName("王磊2"); neo4jTemplate.save(person); Optional person2 = neo4jTemplate.findById(userId, Person.class); System.out.println(person2); }
2.继承Neo4jRepository
@Repositorypublic interface MovieRepository extends Neo4jRepository { //@Query("MATCH (n:Movie) WHERE id = $0 RETURN n") Movie findMovieById(Long id); Movie findMovieByTitle(String title);}import com.lean.neo4j.entity.Person;import org.springframework.data.neo4j.repository.Neo4jRepository;import org.springframework.stereotype.Repository;@Repositorypublic interface PersonRepository extends Neo4jRepository { Person findPersonEntityByName(String name);}package com.lean.neo4j.mapper;import com.lean.neo4j.entity.SystemEntity;import org.springframework.data.neo4j.repository.Neo4jRepository;import org.springframework.data.neo4j.repository.query.Query;import org.springframework.data.repository.query.Param;import org.springframework.stereotype.Repository;@Repositorypublic interface SystemRepository extends Neo4jRepository { @Query("MATCH (a),(b) WHERE id(a)=$from and id(b)=$to MERGE (a)-[:invoke]->(b)") void addInvokeRelation(@Param("from") Long from, @Param("to") Long to); @Query("MATCH (a),(b) WHERE id(a)=$from and id(b)=$to MERGE (a)-[:consume]->(b)") void addConsumeRelation(@Param("from") Long from, @Param("to") Long to); @Query("MATCH (a),(b) WHERE id(a)=$from and id(b)=$to MERGE (a)-[:produce]->(b)") void addProduceRelation(@Param("from") Long from, @Param("to") Long to); @Query("MATCH (n:SystemEntity) where id=$id RETURN n") SystemEntity findSystemById(@Param("id") Long id); //等价写法@Query("MATCH (n:SystemEntity {name: $name}) RETURN n") @Query("MATCH (n:SystemEntity) where n.name=$name RETURN n") SystemEntity findSystemByName(@Param("name") String name); @Query("MATCH (a:SystemEntity{id:$from})-[r:invoke]-(b:SystemEntity{id:$to}) DELETE r") void deleteConsumeRelation(@Param("from") Long from, @Param("to") Long to);}
@Autowired private MovieRepository movieRepository; @Autowired private PersonRepository personRepository; @Test void testByRepository() { // 删除所有节点和关系(删除节点会响应删除关联关系),避免后续创建节点重复影响 movieRepository.deleteAll(); personRepository.deleteAll(); // 创建节点 Movie movie = new Movie("流浪地球", "是由中国电影股份有限公司、北京京西文化旅游股份有限公司、郭帆文化传媒(北京)有限公司、北京登峰国际文化传播有限公司联合出品,由郭帆执导,吴京特别出演、屈楚萧、赵今麦、李光洁、吴孟达等领衔主演的科幻冒险电影"); // 添加关系 movie.getActorsAndRoles().add(new Roles(new Person(1994, "刘启"), Collections.singletonList("初级驾驶员"))); movie.getActorsAndRoles().add(new Roles(new Person(2002, "刘培强"), Collections.singletonList("中国航天员"))); movie.getActorsAndRoles().add(new Roles(new Person(1952, "韩子昂"), Collections.singletonList("高级驾驶员"))); movie.getActorsAndRoles().add(new Roles(new Person(2002, "韩朵朵"), Collections.singletonList("初中生"))); movie.getActorsAndRoles().add(new Roles(new Person(1981, "王磊"), Collections.singletonList("救援队队长"))); movie.getActorsAndRoles().add(new Roles(new Person(1991, "李一一"), Collections.singletonList("技术观察员"))); movie.getActorsAndRoles().add(new Roles(new Person(1974, "何连科"), Collections.singletonList("救援队队员"))); movie.getActorsAndRoles().add(new Roles(new Person(1991, "Tim"), Collections.singletonList("中美混血儿"))); movie.getDirectors().add(new Person(1974, "吴京")); // 存入图数据库持久化 neo4jTemplate.save(movie); // 查询 Person person = personRepository.findPersonEntityByName("刘启"); System.out.println(JSON.toJSONString(person)); Movie movie1 = movieRepository.findMovieByTitle("流浪地球"); System.out.println(JSON.toJSONString(movie1)); Movie movie2 = movieRepository.findMovieById(movie.getId()); System.out.println(JSON.toJSONString(movie2)); // 注意:repository的save方法【对应的实体若id一致】则为修改,否则为新建。 person.setBorn(1997); personRepository.save(person); person = personRepository.findPersonEntityByName("刘启"); System.out.println(person); }
@Autowired private SystemRepository systemRepository; @Test public void addSystemNode() { systemRepository.deleteAll(); SystemEntity systemEntity = new SystemEntity(); systemEntity.setName("系统A"); // 45 systemRepository.save(systemEntity); System.out.println("系统A" + "----------" + systemEntity.getId()); SystemEntity systemEntity1 = new SystemEntity(); systemEntity1.setName("系统B");// 46 systemRepository.save(systemEntity1); System.out.println("系统B" + "----------" + systemEntity1.getId()); SystemEntity systemEntity2 = new SystemEntity(); systemEntity2.setName("系统C");// 47 systemRepository.save(systemEntity2); System.out.println("系统C" + "----------" + systemEntity2.getId()); SystemEntity systemEntity3 = new SystemEntity(); systemEntity3.setName("系统D");// 48 systemRepository.save(systemEntity3); System.out.println("系统D" + "----------" + systemEntity3.getId()); SystemEntity systemEntity4 = new SystemEntity(); systemEntity4.setName("系统E");// 49 systemRepository.save(systemEntity4); System.out.println("系统E" + "----------" + systemEntity4.getId()); SystemEntity systemEntity5 = new SystemEntity(); systemEntity5.setName("系统F");// 50 systemRepository.save(systemEntity5); System.out.println("系统F" + "----------" + systemEntity5.getId()); } @Test public void addInvokeRelation() { systemRepository.addInvokeRelation(45L, 46L); systemRepository.addInvokeRelation(45L, 47L); systemRepository.addInvokeRelation(48L, 45L); systemRepository.addInvokeRelation(48L, 47L); systemRepository.addInvokeRelation(48L, 47L); } @Test public void addConsumeRelation() { systemRepository.addConsumeRelation(49L, 50L); systemRepository.addConsumeRelation(48L, 49L); } @Test public void deleteConsumeRelation2() { Long from = 48L, to = 45L; systemRepository.deleteConsumeRelation(from, to); } @Test public void addProduceRelation() { Long from = 45L, to = 50L; systemRepository.addProduceRelation(from, to); } @Test public void findSystemById() { Long id = 45L; SystemEntity systemEntity = systemRepository.findSystemById(id); System.out.println(JSON.toJSONString(systemEntity)); } @Test public void getAllSystemNode() { Iterable systemEntities = systemRepository.findAll(); for (SystemEntity systemEntity : systemEntities) { System.out.println("查询所有的节点为:" + JSON.toJSONString(systemEntity)); System.out.println(JSON.toJSONString(systemEntity)); } }
参考来源:官方网址
来源地址:https://blog.csdn.net/weixin_43549578/article/details/127906980
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341