一、图数据库
- 定义:图数据库是一种以“点(节点)”和“边(关系)”为基础的数据管理系统,既存储数据本身,也存储数据之间的关系。这样可以快速处理复杂的关联查询,并直观可视化数据关系
- 特点:
- 属于非关系型数据库,结构与传统关系型数据库不同
- 数据的关联信息被直接存储,查询关系更高效
- 可以为关系添加标签、方向和属性
- RAG中的应用:
- 图数据库可以存储知识点及其关联关系,使检索更精准高效
- 在 RAG 中,用于快速查找相关节点(文档、实体、概念)并传给生成模型
- 可以处理复杂的多跳关系查询,提高生成答案的上下文丰富度和准确性
二、Neo4j
1、概念
- Neo4j 是一个高性能的 NoSQL 图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的 Java 持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中
- Neo4j 也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下,而不是严格、静态的表中,但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处
- Neo4j 因其嵌入式、高性能、轻量级等优势,越来越受到关注。现实中很多数据都是用图来表达的,比如社交网络中人与人的关系、地图数据、或是基因信息等等。RDBMS 并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘。NoSQL 数据库的兴起,很好地解决了海量数据的存放问题,图数据库也是 NoSQL 的一个分支,相比于 NoSQL 中的其他分支,它很适合用来原生表达图结构的数据
- 通常来说,一个图数据库存储的结构就如同数据结构中的图,由顶点和边组成。 Neo4j 是图数据库中一个主要代表,其开源,且用Java 实现(需安装 JDK)。经过几年的发展,已经可以用于生产环境
- 图数据库的使用领域非常广泛,包括但不限于以下几个方面:
- 社交网络:图数据库可以用于存储和管理社交网络中的关系数据,从而支持好友推荐、社交活动组织等应用
- 金融行业:图数据库可以用于金融风险控制,例如信贷风险评估、欺诈行为检测等。此外,图数据库还可以用于构建复杂的金融网络模型,以支持投资策略分析、市场趋势预测等
- 电商领域:图数据库可以用于实现商品推荐,通过分析用户行为和商品之间的关联关系,为消费者提供个性化的购物体验
- 生物信息学:图数据库可以用于存储和管理生物信息学中的大量复杂数据,包括基因组学、蛋白质组学等,从而支持基因序列分析、疾病预测等应用
- 交通领域:图数据库可以用于交通规划和管理,例如路网规划、交通流量分析等
- 能源领域:图数据库可以用于能源管理,例如电网管理和能源交易等
- 物联网领域:图数据库可以用于物联网设备的实时监控和管理,例如设备故障预测、物流优化等
- 安全领域:图数据库可以用于网络安全管理,例如网络威胁检测、入侵防御等
- 供应链管理:图数据库可以用于供应链管理,例如供应商评估、物流优化等
- 知识图谱:图数据库可以用于知识图谱的构建和管理,从而支持语义搜索、智能问答等应用
2、数据模型
- Neo4j 是一个高性能图数据库,其数据模型基于属性图模型。属性图模型中,节点(Node)、关系(Relationship)和属性(Property)是基本的构成单元
2.1 节点(Nodes)
- 表示实体或对象,例如一个人、一个地点、一件商品或一篇文章
- 相当于关系型数据库中的“记录”或“行”
- 节点可以有标签(Labels),用于将其分类(例如
:Person,:Movie)
2.2 关系(Relationships)
- 表示节点之间的连接,是图数据库的核心
- 关系总是有方向(从一个节点指向另一个节点)、类型(例如
:FOLLOWS,:ACTED_IN,:PURCHASED)和属性 - 关系是图数据库的一等公民,是直接存储在数据库中,使遍历关系速度非常快
2.3 属性(Properties)
- 键值对形式,用于为节点和关系添加额外信息
- 例如,一个
:Person节点可以有name: 'Tom Hanks',born: 1956等属性;一个:ACTED_IN关系可以有roles: ['Forrest Gump']属性
2.4 标签(Labels)
- 附加在节点上的标签,用于将节点分组或分类
- 类似于关系型数据库中的“表”,但一个节点可以拥有多个标签
2.5 与 MySQL 的对比
| 图数据库(Neo4j) | 关系型数据库(MySQL) | 说明 |
|---|---|---|
| 节点(Node) | 行(Row) | 表示一个实体或对象 |
| 标签(Label) | 表(Table) | 用于分类节点,一个节点可以有多个标签 |
| 属性(Property) | 字段(Column) | 节点或关系的具体信息 |
| 关系(Relationship) | 外键关联(Foreign Key) | 节点之间的直接连接,查询关系无需额外 JOIN,遍历速度更快 |
2.6 案例注解
- 假设有以下命令:
(Tom:Actor {name: 'Tom Hanks'})-[:ACTED_IN {roles: ['Forrest']}]->(Forrest:Movie {title: 'Forrest Gump'})
-
含义:
- 节点
Tom:标签Actor,属性name='Tom Hanks' - 节点
Forrest:标签Movie,属性title='Forrest Gump' - 关系
ACTED_IN:方向从Tom指向Forrest,属性roles=['Forrest']
- 节点
-
一个带有
Actor标签和name属性的Tom Hanks节点,通过一个类型为ACTED_IN且带有roles属性的关系,连接到一个带有Movie标签和title属性的Forrest Gump节点
3、环境安装
3.1 Neo4j Desktop
- DOS 执行以下命令安装,否则自动安装在 C 盘,成功后没有提示,根据桌面快捷图标或者安装目录下的内容判断是否安装完成
# 指定neo4j-desktop安装路径(默认c盘),路径不能有空格
neo4j-desktop-2.0.3-x64.exe /S /D=D:\neo4j-desktop
- 启动
- 创建本地实例:在 Neo4j Desktop 中,
Create instance就是创建数据库实例的入口
3.2 JDK
- 安装
jdk-21_windows-x64_bin.exe,然后配置环境变量,例如:D:\Program Files\jdk21\bin
3.3 更改默认实例路径
- 默认情况下,Neo4j Desktop 的实例存储路径在
C:\Users\cc\.Neo4jDesktop2,配置环境变量解决,在系统变量下添加NEO4J_DESKTOP_DATA_PATH,值为数据存储的路径,重启后生效
4、Cypher
-
CQL(Cypher Query Language) 是 Neo4j 图数据库的查询语言,语法风格类似 SQL,用于对图数据进行查询与操作。CQL 提供了对节点、关系和路径的灵活操作,支持模式匹配、条件筛选、聚合计算、子查询等多种功能。借助 CQL,用户可以高效地探索和分析图数据,执行复杂的关联查询,从而更好地支持业务决策和数据挖掘应用
-
创建一个新的 database 来玩
CREATE DATABASE test;
- 常用命令:能看懂就行
| 类别 | 命令 | 作用 | 示例 |
|---|---|---|---|
| 查询 (MATCH) | MATCH (n) |
匹配图中所有节点 | MATCH (n) RETURN n LIMIT 5; |
MATCH (n:Label) |
匹配指定标签的节点 | MATCH (p:Person) RETURN p; |
|
MATCH (a)-[r]->(b) |
匹配关系 | MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a,b; |
|
WHERE |
条件过滤 | MATCH (p:Person) WHERE p.age > 30 RETURN p; |
|
RETURN |
返回结果 | MATCH (p:Person) RETURN p.name, p.age; |
|
ORDER BY |
排序 | MATCH (p:Person) RETURN p.name ORDER BY p.age DESC; |
|
LIMIT |
限制返回数量 | MATCH (p:Person) RETURN p LIMIT 10; |
|
DISTINCT |
去重 | MATCH (p:Person) RETURN DISTINCT p.city; |
|
| 数据操作 (写操作) | CREATE |
创建节点/关系 | CREATE (:Person {name:'Alice', age:25}); |
MERGE |
匹配或创建 | MERGE (p:Person {name:'Bob'}); |
|
SET |
更新属性 | MATCH (p:Person {name:'Alice'}) SET p.age=30; |
|
REMOVE |
删除属性/标签 | MATCH (p:Person {name:'Alice'}) REMOVE p.age; |
|
DELETE |
删除节点/关系 | MATCH (p:Person {name:'Alice'}) DELETE p; |
|
DETACH DELETE |
删除节点及其关系 | MATCH (p:Person {name:'Alice'}) DETACH DELETE p; |
|
| 聚合与分析 | COUNT() |
计数 | MATCH (p:Person) RETURN COUNT(p); |
AVG() |
平均值 | MATCH (p:Person) RETURN AVG(p.age); |
|
MAX() / MIN() |
最大/最小值 | MATCH (p:Person) RETURN MAX(p.age); |
|
COLLECT() |
聚合为列表 | MATCH (p:Person) RETURN COLLECT(p.name); |
|
| 数据库管理 | SHOW DATABASES; |
查看数据库列表 | SHOW DATABASES; |
CREATE DATABASE dbname; |
创建数据库 | CREATE DATABASE mydb; |
|
DROP DATABASE dbname; |
删除数据库 | DROP DATABASE mydb; |
|
USE dbname; |
切换数据库 | USE neo4j; |
4.1 CREATE 命令
CREATE命令用于在 Neo4j 中创建节点和关系。通过它,可以定义节点的属性、标签以及节点之间的关系。以下为常见的几种用法:
4.1.1 创建节点无属性
- 语法格式:
CREATE (<node-name>:<label-name>)
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
CREATE |
Neo4j Cypher 中的创建命令,用于创建节点或关系 |
<node-name> |
节点变量名,仅在当前 Cypher 语句中有效,用于引用节点,不会保存到数据库 |
<label-name> |
节点标签(Label),用于标识节点的类型或分类 |
( ) |
表示一个节点 |
: |
用于为节点指定标签 |
- 案例:
create (p:Person)
4.1.2 创建节点带属性
- 语法格式:
CREATE (
<node-name>:<label-name>
{
<Property1-name>:<Property1-Value>
........
<Propertyn-name>:<Propertyn-Value>
}
)
语法说明:
| 语法元素 | 更准确的描述 |
|---|---|
<node-name> |
节点变量名,用于在当前 Cypher 语句中引用该节点,不会作为节点名称保存到数据库 |
<label-name> |
节点的标签(Label),用于对节点进行分类 |
<Property1-name> ... <Propertyn-name> |
属性名(Property Key),表示节点属性的键 |
<Property1-value> ... <Propertyn-value> |
属性值(Property Value),表示对应属性键的值 |
{ ... } |
属性集合,由多个键值对组成 |
: |
用于指定节点标签 |
( ) |
表示一个节点 |
CREATE |
Cypher 创建语句,用于创建节点或关系 |
- 案例:
CREATE (p:Person {name: 'cc', age: 30})
4.1.3 在没有属性的节点之间创建关系
- 语法格式:
CREATE (<node1-name>:<label1-name>)-[:<relationship-type>]->(<node2-name>:<label2-name>)
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
CREATE |
Neo4j Cypher 中的创建命令,用于创建节点和关系 |
<node1-name> |
起始节点的变量名,仅在当前 Cypher 语句中有效,用于引用该节点 |
<label1-name> |
起始节点的标签(Label),用于标识节点类型 |
-[:<relationship-type>]-> |
表示从起始节点指向目标节点的有向关系 |
<relationship-type> |
关系类型(Relationship Type),用于描述两个节点之间的关系,通常使用大写字母和下划线命名 |
<node2-name> |
目标节点的变量名,仅在当前 Cypher 语句中有效 |
<label2-name> |
目标节点的标签(Label),用于标识节点类型 |
( ) |
表示节点 |
[ ] |
表示关系 |
-> |
表示关系方向,从左侧节点指向右侧节点 |
- 案例:创建两个
Person节点,并建立一个FRIEND类型的有向关系:a → b
CREATE (a:Person)-[:FRIENDS_WITH]->(b:Person)

4.1.4 使用属性创建节点之间的关系
- 语法格式:
CREATE (
<node1-name>:<label1-name> { <props1> }
)-[:<relationship-type> { <rel-props> }]->(
<node2-name>:<label2-name> { <props2> }
)
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
CREATE |
Neo4j Cypher 中的创建命令,用于创建节点及节点之间的关系 |
<node1-name> |
起始节点的变量名,仅在当前 Cypher 语句中有效,用于引用该节点 |
<label1-name> |
起始节点的标签(Label),用于标识节点类型 |
<props1> |
起始节点的属性集合,由多个键值对组成 |
<relationship-type> |
关系类型(Relationship Type),用于描述两个节点之间的关系 |
<rel-props> |
关系的属性集合,用于存储关系相关信息,如时间、权重、状态等 |
<node2-name> |
目标节点的变量名,仅在当前 Cypher 语句中有效,用于引用该节点 |
<label2-name> |
目标节点的标签(Label),用于标识节点类型 |
<props2> |
目标节点的属性集合,由多个键值对组成 |
( ) |
表示节点 |
[ ] |
表示关系 |
{ } |
表示属性集合(键值对) |
-> |
表示关系方向,从起始节点指向目标节点 |
- 案例:创建两个
Person节点,并创建一个FRIEND类型的关系,关系中包含since属性
CREATE (p1:Person {name: 'Alice'})-[:FRIENDS_WITH {since: 2020}]->(p2:Person {name: 'Bob'})

4.1.5 为节点创建多个标签
- 语法格式:
CREATE (<node-name>:<label1>:<label2> { <props> })
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
CREATE |
Neo4j Cypher 中的创建命令,用于创建节点 |
<node-name> |
节点变量名,仅在当前 Cypher 语句中有效,用于引用该节点 |
<label1> |
节点的第一个标签(Label),用于标识节点类型 |
<label2> |
节点的第二个标签(Label),一个节点可以同时拥有多个标签 |
<props> |
节点的属性集合,由多个键值对组成 |
( ) |
表示一个节点 |
: |
用于指定节点标签,多个标签之间使用 : 分隔 |
{ } |
表示属性集合(键值对) |
- 案例:创建一个同时具有
Employee和Manager两个标签的节点,并设置name、dept等属性
CREATE (e:Employee:Manager {name: 'Charlie', dept: 'IT'})
4.2 MERGE 命令
MERGE是 Cypher 中最强大也最需要谨慎使用的子句之一。它实现了"存在即匹配,不存在则创建"的原子操作
4.2.1 节点操作
- 创建或匹配单个节点:
-- 如果不存在name为马云的Person,则创建,如果存在,则什么都不做
MERGE (p:Person {name:"马云"}) RETURN p
- 如果你要创建多个名字,可以这样写
UNWIND ['马云', '马化腾', '任正非'] AS name
MERGE (p:Person {name: name}) RETURN p.name
- 创建时设置初始属性:
MERGE (p:Person {name: '张一鸣'})
ON CREATE SET
p.age = '48',
p.company = '抖音'
RETURN p
- 匹配时更新属性:
MERGE (p:Person {name: '马云'})
ON MATCH SET
p.age = 51
RETURN p
4.2.2 关系和路径操作
- 创建或匹配整个路径:
-- 如果整个路径不存在,则创建所有节点和关系
MERGE (p:Person {name:"马化腾",age:48}) - [r:FOUNDED {role:"创办人"}] -> (c:Company {name:"腾讯"}) RETURN p,r,c
- 先匹配节点,再创建关系(推荐方式):
-- 先匹配两个已存在的节点
MATCH (p:Person {name:"马化腾",age:48}),(c:Company {name:"腾讯"})
-- 然后创建或匹配他们之间的关系
MERGE (p) - [r:FOUNDED] -> (c) on CREATE set r.role ="创办人"
RETURN p,r,c
4.2.3 批量操作
- 批量 MERGE更新 多个节点的属性:
-- 批量处理
UNWIND [
{name: '马云', company: '阿里巴巴'},
{name: '马化腾', company: '腾讯'},
{name: '任正非', company: '华为'}
] AS person_data
MERGE (p:Person {name: person_data.name})
ON MATCH SET p.company = person_data.company
RETURN p
- 批量 MERGE创建多个节点:
UNWIND ['蔡崇信', '张勇', '彭蕾'] AS name
MERGE (p:Person {name: name}) RETURN p.name
- 批量创建关系:
MATCH (company:Company {name: '阿里巴巴'})
UNWIND ['蔡崇信', '彭蕾', '张勇'] AS cofounder_name
MERGE (person:Person {name: cofounder_name})
MERGE (person)-[r:WORKS_AT]->(company)
RETURN person,r
4.2.4 CREATE vs MERGE
| 特性 / 命令 | CREATE | MERGE |
|---|---|---|
| 作用 | 永远创建一个新的节点或关系 | 如果不存在就创建,存在就匹配(类似 “查找或创建”) |
| 重复数据 | 每次执行都会新增节点或关系,不检查重复 | 避免重复,先 MATCH 查找,找不到再 CREATE |
| 使用场景 | 确定要新增数据,允许重复 | 希望保证节点或关系唯一,避免重复 |
| 属性设置 | 可以直接用 SET 设置属性 |
可以用 ON CREATE SET(仅在创建时设置)和 ON MATCH SET(匹配时更新) |
| 效率 | 快,直接创建 | 先匹配再创建,略慢一些 |
| 例子 | cypher CREATE (p:Person {name:'Alice'}) |
cypher MERGE (p:Person {name:'Alice'}) |
4.3 MATCH 命令
MATCH命令用于在 Neo4j 中查找节点、关系和路径。它相当于 SQL 里的SELECT,是最常用的查询语句
4.3.1 匹配所有某标签的节点
- 语法格式:
MATCH (<node-name>:<label-name>)
RETURN <node-name>
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
MATCH |
Neo4j Cypher 中的匹配命令,用于查找符合条件的节点或关系 |
<node-name> |
节点变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的节点 |
<label-name> |
节点标签(Label),用于限定查询的节点类型 |
( ) |
表示一个节点模式 |
: |
用于指定节点标签 |
RETURN |
用于返回查询结果 |
- 案例:查询所有
Person标签的节点,并返回这些节点
MATCH (p:Person)
RETURN p;

4.3.2 匹配节点并按属性筛选
- 语法格式:
MATCH (<node-name>:<label-name> { <Property-name>: <Property-value> })
RETURN <node-name>
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
MATCH |
Neo4j Cypher 中的匹配命令,用于查找符合条件的节点或关系 |
<node-name> |
节点变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的节点 |
<label-name> |
节点标签(Label),用于限定查询的节点类型 |
<Property-name> |
节点属性名(Property Key),用于指定筛选条件中的属性键 |
<Property-value> |
节点属性值(Property Value),用于匹配指定属性的节点 |
{ } |
表示属性条件集合,由键值对组成 |
( ) |
表示节点模式 |
: |
用于指定节点标签或属性键值对 |
RETURN |
用于返回查询结果 |
- 案例:查询标签为
Person且name属性值为'cc'的节点,并返回该节点
MATCH (p:Person {name: 'cc'})
RETURN p;

4.3.3 匹配节点之间的关系
- 语法格式:
MATCH (<node1-name>:<label1-name>)-[:<relationship-type>]->(<node2-name>:<label2-name>)
RETURN <node1-name>, <node2-name>
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
MATCH |
Neo4j Cypher 中的匹配命令,用于查找符合条件的节点和关系 |
<node1-name> |
起始节点的变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的起始节点 |
<label1-name> |
起始节点的标签(Label),用于限定起始节点类型 |
<relationship-type> |
关系类型(Relationship Type),用于限定节点之间的关系类型,通常使用大写字母和下划线命名 |
<node2-name> |
目标节点的变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的目标节点 |
<label2-name> |
目标节点的标签(Label),用于限定目标节点类型 |
( ) |
表示节点模式 |
[ ] |
表示关系模式 |
-> |
表示关系方向,从起始节点指向目标节点 |
RETURN |
用于返回查询结果 |
- 案例:查询所有存在
FRIENDS_WITH关系的Person节点,并返回关系两端的节点
MATCH (a:Person)-[:FRIENDS_WITH]->(b:Person)
RETURN a, b;

4.3.4 匹配关系并返回关系属性
- 语法格式:
MATCH (<node1-name>:<label1-name>)-[r:<relationship-type>]->(<node2-name>:<label2-name>)
RETURN <node1-name>, r, <node2-name>
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
MATCH |
Neo4j Cypher 中的匹配命令,用于查找符合条件的节点和关系 |
<node1-name> |
起始节点的变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的起始节点 |
<label1-name> |
起始节点的标签(Label),用于限定起始节点类型 |
r |
关系变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的关系,并可访问关系属性 |
<relationship-type> |
关系类型(Relationship Type),用于限定节点之间的关系类型 |
<node2-name> |
目标节点的变量名,仅在当前 Cypher 语句中有效,用于引用匹配到的目标节点 |
<label2-name> |
目标节点的标签(Label),用于限定目标节点类型 |
( ) |
表示节点模式 |
[ ] |
表示关系模式 |
-> |
表示关系方向,从起始节点指向目标节点 |
RETURN |
用于返回查询结果 |
- 案例:查询所有
Person节点之间的FRIENDS_WITH关系,并返回两个人的名字以及建立好友关系的时间
MATCH (a:Person)-[r:FRIENDS_WITH]->(b:Person)
RETURN a.name, b.name, r.since;

4.3.5 匹配任意长度的路径
- 语法格式:
MATCH path = (<start-node>:<label1-name>)-[*min..max]->(<end-node>:<label2-name>)
RETURN path
- 语法说明:
| 语法元素 | 修改后的描述 |
|---|---|
MATCH |
Neo4j Cypher 中的匹配命令,用于查找符合条件的节点、关系或路径 |
path |
路径变量名,仅在当前 Cypher 语句中有效,用于保存匹配到的完整路径 |
<start-node> |
起始节点变量名,用于引用路径起点节点 |
<label1-name> |
起始节点的标签(Label),用于限定起始节点类型 |
[*min..max] |
可变长度关系模式,用于匹配指定长度范围内的路径,其中 min 为最小跳数,max 为最大跳数 |
<end-node> |
目标节点变量名,用于引用路径终点节点 |
<label2-name> |
目标节点的标签(Label),用于限定目标节点类型 |
( ) |
表示节点模式 |
[ ] |
表示关系模式 |
* |
表示匹配多跳关系(可变长度路径) |
-> |
表示路径方向,从起始节点指向目标节点 |
RETURN |
用于返回查询结果 |
-
在图数据库里,一条 路径 是由 节点 (nodes) 和 关系 (relationships) 组成的
- 每经过一条关系,就算一次 hop(跳)
- hops 数 = 路径上关系的数量
-
图里有这些节点和关系:
(Alice)-[:FRIENDS_WITH]->(Bob)-[:FRIENDS_WITH]->(Charlie)- 从 Alice → Bob :关系数 = 1 hop
- 从 Alice → Charlie :关系数 = 2 hops
-
在 Cypher 里的写法
- 匹配 1 hop:查找和 Alice 直接相连的朋友
MATCH (a:Person {name: 'Alice'})-[:FRIENDS_WITH]->(b:Person) RETURN b;- 匹配 2 hops:查找 Alice 的“朋友的朋友”
MATCH (a:Person {name: 'Alice'})-[:FRIENDS_WITH*2]->(b:Person) RETURN b;- 匹配 1 到 3 hops:查找 Alice 在 1~3 跳以内能到达的朋友
MATCH (a:Person {name: 'Alice'})-[:FRIENDS_WITH*1..3]->(b:Person) RETURN b; -
案例:查询从一个
Person节点到另一个Person节点之间,长度为 1 到 3 跳的所有路径,并返回完整路径
MATCH path = (a:Person {name: 'Alice'})-[*1..3]->(b:Person)
RETURN path;

4.4 CREATE 和 MATCH
- 创建员工、公司之间的关系,从创建节点 → 建立关系 → 查询结果完整步骤
- 第一步:创建员工节点
CREATE (p:Person {name: "马云", birthYear: 1964})
RETURN p;
- 第二步:创建公司节点
CREATE (c:Company {name: "阿里巴巴", foundedYear: 1999})
RETURN c;
- 第三步:建立关系(马云创办阿里巴巴)
MATCH (p:Person {name: "马云"}), (c:Company {name: "阿里巴巴"})
CREATE (p)-[r:FOUNDED {role: "创始人", startYear: 1999}]->(c)
RETURN p, r, c;
- 第四步:查询验证
MATCH (p:Person {name: "马云"})-[r:FOUNDED]->(c:Company)
RETURN p.name, r.role, r.startYear, c.name, c.foundedYear;
4.5 WHERE 命令
-
MATCH用于查找图中的节点和关系,WHERE用于对匹配到的结果增加过滤条件 -
布尔运算符
- Neo4j 支持以下布尔运算符在 Neo4j CQL WHERE 子句中使用以支持多个条件
布尔运算符 描述 AND 它是一个支持AND操作的Neo4j CQL关键字 OR 它是一个Neo4j CQL关键字来支持OR操作 NOT 它是一个Neo4j CQL关键字支持 NOT 操作 -
比较运算符
- Neo4j 支持以下的比较运算符,在 Neo4j CQL WHERE 子句中使用来支持条件
比较运算符 描述 = 它是Neo4j CQL“等于”运算符 <> 它是一个Neo4j CQL“不等于”运算符 < 它是一个Neo4j CQL“小于”运算符 > 它是一个Neo4j CQL“大于”运算符 <= 它是一个Neo4j CQL“小于或等于”运算符 >= 它是一个Neo4j CQL“大于或等于”运算符 -
WHERE 语法格式:
MATCH (<node-variable>:<Label>)
WHERE <条件表达式>
RETURN <返回的字段或表达式>
- 条件表达式语法格式:
<property-name> <comparison-operator> <value>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名,用于在查询中引用节点 |
<Label> |
节点的标签,用于限定匹配的节点类型 |
<条件表达式> |
用于过滤节点或关系的条件,可以是属性、比较运算、逻辑运算等 |
RETURN |
指定最终返回的结果内容 |
- 案例:
MATCH (p:Person)
WHERE p.age = 28
RETURN p;
4.6 SET 命令
SET用于修改节点或关系的属性,也可以用来为节点或关系添加标签
4.6.1 设置或更新节点属性
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
SET <node-variable>.<Property-name> = <Property-value>
RETURN <node-variable>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名,用于引用需要修改的节点 |
<Label> |
节点标签,用于限定节点类型 |
<条件> |
匹配节点的条件(可选) |
<Property-name> |
需要设置或更新的属性名称 |
<Property-value> |
属性值,可以是字符串、数字等 |
- 案例:
MATCH (p:Person {name: "马云"})
SET p.age = 57
RETURN p;
4.6.2 给节点添加标签
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
SET <node-variable>:<NewLabel>
RETURN <node-variable>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<NewLabel> |
新标签名称,节点将新增该标签 |
- 案例:
MATCH (p:Person {name: "马云"})
SET p:Founder
RETURN p;
4.6.3 更新关系属性
- 语法格式:
MATCH (<node1>:<Label1>)-[r:<RELATION_TYPE>]->(<node2>:<Label2>)
SET r.<Property-name> = <Property-value>
RETURN r
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<RELATION_TYPE> |
关系类型 |
<Property-name> |
关系属性名称 |
<Property-value> |
要设置的属性值 |
- 案例:
MATCH (p:Person {name: "马云"})-[r:FOUNDED]->(c:Company {name: "阿里巴巴"})
SET r.endYear = 2019
RETURN r;
4.6.4 同时设置多个属性
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
SET <node-variable> += { <Property1>: <Value1>, <Property2>: <Value2>, ... }
RETURN <node-variable>
- 案例:
MATCH (p:Person {name: "马云"})
SET p += {age: 57, country: "China"}
RETURN p;
4.7 ORDER BY 命令
ORDER BY用于对 MATCH 或 RETURN 查询的结果进行排序,可以按节点或关系的属性升序或降序排列ORDER BY必须放在 RETURN 或 WITH 之后- 语法格式:
MATCH (<node-variable>:<Label>)
RETURN <返回的字段或表达式>
ORDER BY <字段或表达式> [ASC|DESC]
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名 |
<Label> |
节点标签,用于限定查询对象 |
<字段或表达式> |
用于排序的属性或表达式 |
ASC |
升序(默认) |
DESC |
降序 |
- 案例:按年龄升序排序
MATCH (p:Person)
RETURN p.name, p.age
ORDER BY p.age ASC;
- 案例:按姓名降序排序
MATCH (p:Person)
RETURN p.name, p.age
ORDER BY p.name DESC;
- 案例:多属性排序,先按
country升序排序,再在同一国家内按age降序排序
MATCH (p:Person)
RETURN p.name, p.age, p.country
ORDER BY p.country ASC, p.age DESC;
4.8 LIMIT 命令
-
LIMIT用于限制查询结果的数量,常用于分页或者只取前几条数据 -
LIMIT必须放在 RETURN 或 WITH 后面 -
语法格式:
MATCH (<node-variable>:<Label>)
RETURN <返回的字段或表达式>
LIMIT <数量>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名 |
<Label> |
节点标签,用于限定查询对象 |
<返回的字段或表达式> |
查询返回的字段或表达式 |
<数量> |
限制返回的最大行数(正整数) |
- 案例:筛选中国的
Person节点,按age升序排序,再只返回年龄最大的前 5 个节点
MATCH (p:Person)
WHERE p.country = "China"
RETURN p.name, p.age
ORDER BY p.age ASC
LIMIT 5;
4.9 SKIP 命令
-
SKIP用于跳过查询结果的前几条记录,常与LIMIT搭配实现分页查询 -
SKIP必须放在 RETURN 或 WITH 后面,并且一般与ORDER BY搭配使用,否则分页结果不稳定 -
语法格式:
MATCH (<node-variable>:<Label>)
RETURN <返回的字段或表达式>
ORDER BY <字段或表达式>
SKIP <数量>
LIMIT <数量>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名 |
<Label> |
节点标签,用于限定查询对象 |
<返回的字段或表达式> |
查询返回的字段或表达式 |
<数量> |
SKIP:跳过的记录数,LIMIT:返回的记录数 |
- 案例:筛选中国的
Person节点,按age升序排序,跳过前 5 条,返回接下来的 5 条记录
MATCH (p:Person)
WHERE p.country = "China"
RETURN p.name, p.age
ORDER BY p.age DESC
SKIP 5
LIMIT 5;
4.10 NULL
NULL表示 节点或关系属性不存在或未定义,类似 SQL 中的空值- 在 Cypher 查询中,如果引用不存在的属性,返回结果就是
NULL - 设置默认值避免 NULL,使用
coalesce(a, b)函数,返回第一个非 NULL 的值 - 特性:
| 特性 | 说明 |
|---|---|
| 默认值 | 节点或关系没有某个属性时,查询该属性返回 NULL |
| 逻辑判断 | NULL 在布尔表达式中不会被当作 TRUE 或 FALSE,需要用 IS NULL 或 IS NOT NULL 判断 |
| 计算参与 | NULL 参与运算结果仍为 NULL(例如 5 + NULL = NULL) |
| 排序 | 排序时,NULL 默认排在最后(ASC)或最前(DESC) |
4.11 IN
-
IN用于判断某个值是否包含在指定的列表(数组)中,常用于条件筛选 -
语法格式:
MATCH (<node-variable>:<Label>)
WHERE <值> IN <列表>
RETURN <返回字段>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名 |
<Label> |
节点标签,用于限定查询对象 |
<值> |
节点属性或表达式 |
<列表> |
用方括号 [] 表示的列表,可以是字符串、数字等 |
RETURN |
指定返回的字段或表达式 |
- 案例:关系属性包含在列表中
MATCH (p:Person)-[r:FOUNDED]->(c:Company)
WHERE r.role IN ["创始人", "联合创始人"]
RETURN p.name, r.role, c.name;
4.14 UNION 和 UNION ALL
-
UNION和UNION ALL用于 合并两条或多条查询语句的结果 -
它将两组结果中的公共行组合并返回到一组结果中。 它不从两个节点返回重复的行
-
UNION ALL 和 UNION 使用方式基本相同,只是返回的结果不会过滤掉重复行
-
结果列类型和来自两组结果的名称必须匹配,这意味着列名称应该相同,列的数据类型应该相同,如果这两个查询不返回相同的列名和数据类型,那么它抛出一个错误
-
查询结果的列的前缀不同也会报错,所以需要用 AS 关键字给查询的列取别名
-
语法格式:
<查询语句1>
UNION [ALL]
<查询语句2>
- 区别对比表:
| 特性 | UNION | UNION ALL |
|---|---|---|
| 是否去重 | 是,自动去重重复行 | 否,保留所有重复行 |
| 使用场景 | 不希望结果重复时 | 希望保留所有原始结果,包括重复 |
| 效率 | 较低,需要去重 | 较高,不去重 |
| 语法 | 查询1 UNION 查询2 |
查询1 UNION ALL 查询2 |
- 案例:
MATCH (p:Person)
WHERE p.country = "China"
RETURN p.name
UNION
MATCH (p:Person)
WHERE p.age > 50
RETURN p.name;
4.15 REMOVE 命令
REMOVE用于 删除节点或关系的属性,或 删除节点的标签REMOVE不会删除节点或关系本身,只删除属性或标签
4.15.1 删除属性
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
REMOVE <node-variable>.<Property-name>
RETURN <node-variable>
- 语法说明:
| 语法元素 | 描述 |
|---|---|
<node-variable> |
节点变量名 |
<Label> |
节点标签 |
<Property-name> |
要删除的属性名称 |
- 案例:删除马云的 birthYear 属性
MATCH (p:Person {name: "马云"})
REMOVE p.birthYear
RETURN p;
4.15.2 删除节点标签
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
REMOVE <node-variable>:<Label-to-Remove>
RETURN <node-variable>
- 案例:删除
马云节点的Founder标签,但保留Person标签
MATCH (p:Person {name: "马云"})
REMOVE p:Founder
RETURN p;
4.15.3 删除关系属性
- 语法格式:
MATCH (<node1>:<Label1>)-[r:<RELATION_TYPE>]->(<node2>:<Label2>)
REMOVE r.<Property-name>
RETURN r;
- 案例:删除
FOUNDED关系的endYear属性
MATCH (p:Person {name: "马云"})-[r:FOUNDED]->(c:Company {name: "阿里巴巴"})
REMOVE r.endYear
RETURN r;
4.16 DELETE 命令
DELETE用于 删除节点或关系本身- 注意:如果节点有关系,必须先删除关系或使用
DETACH DELETE - DELETE 只删除节点或关系本身,不删除属性(使用
REMOVE删除属性)
4.16.1 删除节点
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
DELETE <node-variable>
- 案例:删除
马云节点本身,如果节点存在关系,会报错
MATCH (p:Person {name: "马云"})
DELETE p;

4.16.2 删除节点及其所有关系
- 语法格式:
MATCH (<node-variable>:<Label> { <条件> })
DETACH DELETE <node-variable>
- 案例:删除
马云节点及其所有连接关系,不会报错
MATCH (p:Person {name: "马云"})
DETACH DELETE p;
4.16.3 删除关系
- 语法格式:
MATCH (<node1>:<Label1>)-[r:<RELATION_TYPE>]->(<node2>:<Label2>)
DELETE r;
- 案例:删除
马云与阿里巴巴之间的FOUNDED关系,但节点保留
MATCH (p:Person {name: "马云"})-[r:FOUNDED]->(c:Company {name: "阿里巴巴"})
DELETE r;
4.16.4 清空
- 语法格式:
MATCH (n)
DETACH DELETE n;
4.17 REMOVE vs DELETE
| 操作 | 会删除内容 | 是否保留属性/元数据 |
|---|---|---|
DETACH DELETE |
节点 + 关系 + 节点属性 + 关系属性 | 不保留节点/关系数据,索引/约束仍在 |
REMOVE |
删除单个属性或标签 | 只删除指定属性/标签,节点/关系本身保留 |
4.18 约束
- 约束用于保证数据的唯一性和完整性,Neo4j 会自动维护约束相关的索引
4.18.1 节点属性唯一性约束
-
作用:确保某个标签的节点的某个属性值是唯一的
-
批量添加 id 属性:
UNWIND ['蔡崇信', '张勇', '彭蕾'] AS name
MERGE (p:Person {name: name})
SET p.id = randomUUID()
- 创建唯一性约束:
-- 创建唯一性约束(如果不存在)
CREATE CONSTRAINT unique_person_id IF NOT EXISTS
FOR (p:Person)
REQUIRE p.id IS UNIQUE
- 验证约束:
-- 尝试插入重复ID会报错
CREATE (:Person {id: 'eac4831e-60ab-4ace-9463-4ee500bcf926', name: 'cc')}
4.18.2 节点属性存在性约束
- 作用:确保某个标签的所有节点都拥有某个属性
-- 创建存在性约束
CREATE CONSTRAINT person_name_exists IF NOT EXISTS
FOR (p:Person)
REQUIRE p.name IS NOT NULL
- 验证约束:
-- 尝试创建没有name属性的Person会报错
CREATE (:Person {age: 55}) -- 这会失败
CREATE (:Person {name: '马云', age: 55}) -- 这会成功
4.18.3 查看和删除约束
-- 查看约束
SHOW CONSTRAINTS
-- 删除约束
DROP CONSTRAINT unique_person_id IF EXISTS
4.19 索引
- 索引用于加速查询性能,特别是基于属性的查找
4.19.1 单属性索引
- 作用:加速基于单个属性的查询
-- 创建单属性索引
CREATE INDEX person_name_index IF NOT EXISTS
FOR (p:Person)
ON (p.name)
- 使用场景:
-- 这个查询会使用索引
MATCH (p:Person {name: '马云'}) RETURN p
MATCH (p:Person) WHERE p.name = '马云' RETURN p
4.19.2 复合索引
- 作用:加速基于多个属性组合的查询
-- 创建复合索引
CREATE INDEX person_name_age_index IF NOT EXISTS
FOR (p:Person)
ON (p.name, p.age)
- 使用场景:
-- 这些查询会使用复合索引
MATCH (p:Person) WHERE p.name = '马云' AND p.age = 55 RETURN p
MATCH (p:Person) WHERE p.name = '马云' RETURN p -- 也会使用索引
4.19.3 全文索引
- 定义全文索引:
CREATE FULLTEXT INDEX personFulltextIndex
FOR (n:Person|Company)
ON EACH [n.name, n.age, n.id]
- 查询全文索引:
CALL db.index.fulltext.queryNodes("personFulltextIndex", "阿里巴巴")
YIELD node, score
RETURN node.name, node.description, score
ORDER BY score DESC
全文搜索引擎会为每个匹配的结果计算一个相关性分数(Score),你可以根据这个分数对结果进行排序,让最相关的结果排在最前面。
3.4.4 查看和删除索引
--查看索引
SHOW INDEXES
-- 删除索引
DROP INDEX person_name_index IF EXISTS
-- 删除全文索引
CALL db.index.fulltext.drop("personFulltextIndex")
三、APOC 插件
- APOC(Awesome Procedures on Cypher) 是 Neo4j 官方提供的一个扩展库,提供了大量增强功能,包括:
- 数据导入导出(CSV、JSON 等)
- 节点和关系批量创建与操作
- 图算法(路径查找、社区检测等)
- 字符串、集合、日期等工具函数
- 动态关系类型创建(可以把关系名从属性变成边类型)
- APOC 就像 Neo4j 的“工具箱”,可以完成很多原生 Cypher 做不到或者比较麻烦的操作

四、py2neo 库
-
Py2neo 是一个 Python 库,用于与 Neo4j 数据库进行交互。它提供了高级的 API 和工具,使得在 Python 应用程序中使用 Neo4j 更加方便。Py2neo 支持 Bolt 和 HTTP 协议,并提供了高级 API、对象关系映射(ORM)、管理工具、Cypher 查询语言等功能
-
操作有两个方案:
-
写 Cypher
-
调方法
-
-
安装命令:
pip install py2neo -i https://repo.huaweicloud.com/repository/pypi/simple/
1、连接
- 案例代码:
from py2neo import Graph
graph = Graph(profile="neo4j://127.0.0.1:7687",
auth=("neo4j", "rootroot"),
name="neo4j"
)
print(graph)
2、创建节点和关系
- 案例代码:
from py2neo import Node, Relationship
from Neo4jUtil import connect_to_neo4j
graph = connect_to_neo4j()
# 创建节点
cc_node = Node('Person', name='cc')
zs_node = Node('Person', name='zs')
graph.create(cc_node)
graph.create(zs_node)
# 创建关系
friend_rel = Relationship(cc_node, 'FRIEND', zs_node)
graph.create(friend_rel)
print('节点和关系创建成功!')
3、查询节点和关系
result = graph.nodes.match("Person", name="cc")返回的result其实是NodeMatcher.Match对象(py2neo.matching.Match类实例),它是一个可迭代对象(迭代时返回Node节点),带有一些方法和属性:
| 属性/方法 | 类型 | 作用/说明 |
|---|---|---|
result.where() |
方法 | 添加额外的条件过滤(Cypher WHERE 子句) |
result.first() |
方法 | 返回第一个匹配到的节点(或 None) |
result.all() |
方法 | 返回所有匹配节点,列表形式 |
result.count() |
方法 | 返回匹配的节点数量 |
result.get(name="cc") |
方法 | 返回单个匹配节点(若有多个,抛异常) |
result.exists() |
方法 | 是否存在匹配的节点,返回 True/False |
result.order_by("n.name") |
方法 | 按指定属性排序(Cypher ORDER BY) |
result.skip(n) |
方法 | 跳过前 n 个结果(Cypher SKIP) |
result.limit(n) |
方法 | 限制返回结果数量(Cypher LIMIT) |
result.__iter__() |
方法 | 允许直接 for node in result: 遍历节点 |
result.__getitem__(i) |
方法 | 可以用索引取节点,如 result[0] |
result.__len__() |
方法 | len(result),得到结果数 |
result.graph |
属性 | 绑定的 Graph 对象 |
result.labels |
属性 | 匹配的标签集合,例如 "Person" |
result.conditions |
属性 | 查询时附加的条件 |
result = graph.run(query)这里的result是py2neo.data.Cursor对象(准确叫py2neo.database.work.Cursor),它是一个 查询结果游标,支持迭代、取记录、转表格等:
| 属性/方法 | 类型 | 作用/说明 |
|---|---|---|
result.keys() |
方法 | 返回列名列表(类似 SQL 的字段名) |
result.peek() |
方法 | 返回下一个记录但不移动游标 |
result.next() |
方法 | 返回下一条记录(超出会抛异常) |
result.forward(n=1) |
方法 | 游标向前移动 n 步,不返回数据 |
result.__iter__() |
方法 | 可以 for record in result: 遍历结果 |
result.__next__() |
方法 | 迭代时获取下一个 Record |
result.__getitem__(i) |
方法 | 按索引取某条记录,比如 result[0] |
result.data() |
方法 | 返回结果的 列表[dict],每一行是一个字典 |
result.to_table() |
方法 | 返回结果的二维表(列表嵌套) |
result.to_data_frame() |
方法 | 转换成 Pandas DataFrame |
result.stats() |
方法 | 返回查询的统计信息(如写操作数量) |
result.close() |
方法 | 关闭游标 |
result.graph |
属性 | 绑定的 Graph 对象 |
result._metadata |
属性 | 内部的元信息(列信息、统计等) |
- 案例代码:
from py2neo import *
from Neo4jUtil import connect_to_neo4j
# 查询单个节点
graph = connect_to_neo4j()
result = graph.nodes.match("Person", name="cc")
print("查询单个节点:\n", result.all())
# 查询多个节点
result = graph.nodes.match("Person")
print("查询多个节点:\n", result.all())
# 使用 Cypher 查询关系
cql = """
MATCH (a:Person)-[r:FRIEND]->(b:Person)
RETURN a, r, b
"""
result = graph.run(cql)
print("使用 Cypher 语句查询关系:\n", result.data())
4、更新节点属性
- 案例代码:
from py2neo import *
from Neo4jUtil import connect_to_neo4j
graph = connect_to_neo4j()
cc_node = graph.nodes.match("Person", name="cc").first()
# 直接更新
cc_node['age'] = 28
graph.push(cc_node)
# 使用 Cypher 更新
cql = """
MATCH (p:Person {name:'zs'})
SET p.age = $age
"""
graph.run(cql, age=26)
print("更新成功")
5、删除指定关系
- 案例代码:
from Neo4jUtil import connect_to_neo4j
graph = connect_to_neo4j()
graph.run("""
MATCH (a:Person {name:'cc'})-[r:FRIEND]->(b:Person {name:'zs'})
DELETE r
""")
print("关系已删除")
6、删除单个节点
- 案例代码:
from Neo4jUtil import connect_to_neo4j
graph = connect_to_neo4j()
zs_node = graph.nodes.match("Person", name="zs").first()
graph.delete(zs_node)
print("删除成功")
7、删除节点及其关系
- 案例代码:
from Neo4jUtil import connect_to_neo4j
graph = connect_to_neo4j()
graph.run("MATCH (p:Person {name:'cc'}) DETACH DELETE p")
浙公网安备 33010602011771号