一、图数据库

  • 定义:图数据库是一种以“点(节点)”和“边(关系)”为基础的数据管理系统,既存储数据本身,也存储数据之间的关系。这样可以快速处理复杂的关联查询,并直观可视化数据关系
  • 特点
    • 属于非关系型数据库,结构与传统关系型数据库不同
    • 数据的关联信息被直接存储,查询关系更高效
    • 可以为关系添加标签、方向和属性
  • 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)

image-20250922202935384

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'})

image-20250922203118260

4.1.5 为节点创建多个标签

  • 语法格式:
CREATE (<node-name>:<label1>:<label2> { <props> })
  • 语法说明:
语法元素 修改后的描述
CREATE Neo4j Cypher 中的创建命令,用于创建节点
<node-name> 节点变量名,仅在当前 Cypher 语句中有效,用于引用该节点
<label1> 节点的第一个标签(Label),用于标识节点类型
<label2> 节点的第二个标签(Label),一个节点可以同时拥有多个标签
<props> 节点的属性集合,由多个键值对组成
( ) 表示一个节点
: 用于指定节点标签,多个标签之间使用 : 分隔
{ } 表示属性集合(键值对)
  • 案例:创建一个同时具有 EmployeeManager 两个标签的节点,并设置 namedept 等属性
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;

image-20250923091006276

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 用于返回查询结果
  • 案例:查询标签为 Personname 属性值为 'cc' 的节点,并返回该节点
MATCH (p:Person {name: 'cc'})
RETURN p;

image-20250923091204679

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;

image-20250923091456136

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;

image-20250923091652674

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;

image-20250923091824744

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 必须放在 RETURNWITH 之后
  • 语法格式:
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 必须放在 RETURNWITH 后面

  • 语法格式:

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 必须放在 RETURNWITH 后面,并且一般与 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 在布尔表达式中不会被当作 TRUEFALSE,需要用 IS NULLIS 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

  • UNIONUNION 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;

image-20250923102607722

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 做不到或者比较麻烦的操作

image-20250923133401512

四、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)这里的 resultpy2neo.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")