# 大模型技术之Neo4j
大语言模型(LLM)狂飙突进,但也暴露出一个软肋:幻觉和知识陈旧。为了让模型输出更可信、更实时,业界正广泛采用 检索增强生成(RAG) 技术,而 图数据库 正是 RAG 架构中承载结构化知识的绝佳载体——它将实体及其关系直接建模为节点与边,天然适合表达知识图谱。
Neo4j 是图数据库领域的“头号玩家”,它不仅查询直观、性能强劲,还与 LangChain、LlamaIndex 等主流 AI 框架深度集成。对于 AI 开发者来说,掌握 Neo4j 就等于拥有了一座可随时调用的“记忆宫殿”。这篇专栏将带你从零开始,用最短的时间打通 Neo4j 的任督二脉。

# 1. 认识 Neo4j:不只是数据库
传统关系型数据库用表格和外键描述关联,一旦涉及多跳查询(比如“张艺谋合作过的演员还演过哪些电影”),SQL 就会变得异常臃肿。图数据库则直接用节点(Node)代表实体,用关系(Relationship)代表实体间的连接,数据模型和人对现实世界的认知方式高度一致。
Neo4j 由同名公司用 Java 开发,采用原生图存储与查询引擎,是目前最流行、社区最活跃的图数据库。它被广泛用在社交网络、推荐系统、知识图谱、反欺诈等场景,也是 Graph RAG 方案的首选基础设施。
适用场景速查:如果你需要处理“谁认识谁”“A通过什么路径影响B”“某节点半径三跳内所有相关对象”这类问题,Neo4j 就是比关系型数据库更合适的答案。
# 2. 环境搭建:10 分钟跑起来
Neo4j 提供了三种主要使用方式:
- Neo4j Desktop:带图形界面的本地工具,适合学习与原型开发。
- Neo4j Aura:官方云服务,免安装免运维。
- OS Deployment:直接部署在服务器上,适合生产环境。
为了让你对底层有更实在的感知,我们选择在 Windows 上通过 OS Deployment 安装 Neo4j 5.26(LTS)社区版。
# 2.1 安装 JDK
Neo4j 依赖 JVM,5.26 版本要求 JDK 17 或 JDK 21。从 Oracle 官网下载对应安装包(也可从本文配套资料获取),双击安装。完成后在终端输入:
java --version
若能正常显示版本号,说明 JDK 就绪。

# 2.2 安装并启动 Neo4j
在 Neo4j 下载中心 (opens new window) 选择社区版压缩包,下载后解压到你喜欢的目录(比如 D:\neo4j)。

接下来配置环境变量:
- 新建系统变量
NEO4J_HOME,值为 Neo4j 的解压路径(例如D:\neo4j)。 - 在
Path变量中添加%NEO4J_HOME%\bin。
验证配置:
neo4j --version
将 Neo4j 注册为系统服务并启动:
neo4j windows-service install
neo4j start
2
服务启动后,在浏览器中打开 http://localhost:7474。初始用户名和密码都是 neo4j,首次登录需修改密码。此时你会看到 Neo4j 自带的 Web 客户端,一切就绪。

# 3. Cypher 速成:用图表的方式思考
Cypher 是 Neo4j 的声明式查询语言,风格接近 SQL,但专为图数据设计。它的核心理念是:画出你想匹配的模式,引擎就帮你返回对应的子图。
# 3.1 图数据模型三要素
- 节点(Node):实体。例如“王宝强”“唐探1900”。可用标签(Label)区分类型(如
:Person、:Movie),可携带若干属性(Property)。

- 关系(Relationship):连接两个节点的有向边。必须指定一个类型(Type),也可以附加属性。

- 路径(Path):节点与关系组成的链条,是图查询返回的核心结构。

在 Cypher 中,我们用 () 表示节点,-[]-> 表示关系,像搭积木一样把模式拼出来。


# 3.2 数据的创建与查询
创建节点
CREATE (n1:Person:Actor:Director {name: '王宝强', gender: '男'})
CREATE (n2:Movie {title: '唐探1900', released: '2025-01-29'})
2
查询节点
MATCH (n) RETURN n // 全图扫描
MATCH (n:Person) RETURN n // 按标签筛选
MATCH (n:Person {name: '王宝强'}) RETURN n // 按属性精确定位
2
3
创建关系:先定位首尾节点,再用 CREATE 画出连接。
MATCH (n1:Person {name: '王宝强'}), (n2:Movie {title: '唐探1900'})
CREATE (n1)-[:ACTED_IN {role: '阿鬼'}]->(n2)
2
查询关系
MATCH (n1:Person {name: '王宝强'})-[r]->(n2:Movie {title: '唐探1900'})
RETURN r
2
一步构建路径:在一条 CREATE 语句中同时生成节点和关系,更高效。
CREATE
(n1:Person:Actor:Singer {name: '刘德华', gender: '男'})-
[:ACTED_IN {roles: ['刘建明']}]->
(n2:Movie {title: '无间道', released: '2002-12-12'})
2
3
4
查询路径
MATCH path = (n1:Person)-[r:ACTED_IN]->(n2:Movie)
RETURN path
2
# 3.3 修改与删除
使用 SET 和 REMOVE 动态调整属性或标签:
MATCH (n:Person {name: '王宝强'})
SET n.birth = '1984-05-29', n:Singer
MATCH (n:Person {name: '王宝强'})-[r:ACTED_IN]->(m:Movie {title: '唐探1900'})
REMOVE r.role
SET r.roles = ['阿鬼']
2
3
4
5
6
删除操作 DELETE 必须先清掉所有关联关系,否则会报错:
MATCH (n1:Person {name: '王宝强'})-[r:ACTED_IN]->(n2:Movie {title: '唐探1900'})
DELETE n1, r, n2
2
# 3.4 灵活的 MERGE
MERGE 是 MATCH + CREATE 的组合:存在就复用,不存在就新建。非常适合做幂等插入。
MERGE (n2:Movie {title: '唐探1900', released: '2025-01-29'})
MERGE (n1:Person:Actor:Director {name: '王宝强', gender: '男'})
ON CREATE SET n1.create_time = datetime()
ON MATCH SET n1.update_time = datetime()
2
3
4
# 4. 数据类型与常用函数
Cypher 的内置类型和函数让数据清洗与加工变得顺手。
# 4.1 数据类型速查
| 类型 | 示例 | 说明 |
|---|---|---|
| String | 'Neo4j', "王宝强" | 单/双引号 |
| Integer | 42, 2025 | 整数 |
| Float | 3.14, 99.99 | 浮点数 |
| Boolean | true, false | 布尔 |
| List | ['王宝强', '刘昊然'] | 有序列表 |
| Map | {year: 2025, month:6} | 键值对结构 |
# 4.2 函数即用
字符串处理
RETURN toUpper('neo4j') -- 'NEO4J'
RETURN substring('neo4j', 0, 3) -- 'neo'
RETURN replace('neo4j', 'o','O') -- 'neO4j'
RETURN trim(' hello ') -- 'hello'
2
3
4
数学运算
RETURN abs(-5) -- 5
RETURN round(3.6) -- 4.0
RETURN floor(3.8) -- 3.0
RETURN rand() -- 0~1 随机数
2
3
4
集合操作
RETURN size(['a','b','c']) -- 3
RETURN head(['a','b','c']) -- 'a'
RETURN '刘昊然' IN ['王宝强','刘昊然'] -- true
2
3
日期时间
RETURN date() -- 当前日期
RETURN datetime() -- 当前日期时间
2
# 5. 高级查询实战
光有基础操作还不够,真实业务中需要组合出千变万化的查询。为了演示,我们先在 Neo4j 中灌入一套“人物-电影”数据,模型如下:

你可以在 Neo4j 浏览器中执行下方脚本,一键构建好示例图谱(包含 9 位演员/导演、10 部电影,以及他们之间的导演、参演、关注关系)。
// =======================
// 清空旧数据
// =======================
MATCH (n) DETACH DELETE n;
// =======================
// 创建人物节点(9人)
// =======================
CREATE
(:Person {name:'张艺谋', birth:'1951-11-14'}),
(:Person {name:'陈凯歌', birth:'1952-08-12'}),
(:Person {name:'巩俐', birth:'1965-12-31'}),
(:Person {name:'葛优', birth:'1957-04-19'}),
(:Person {name:'章子怡', birth:'1979-02-09'}),
(:Person {name:'刘德华', birth:'1961-09-27'}),
(:Person {name:'吴京', birth:'1974-04-03'}),
(:Person {name:'贾玲', birth:'1982-04-29'}),
(:Person {name:'郭帆', birth:'1980-12-15'});
// =======================
// 创建电影节点(10部)
// =======================
CREATE
(:Movie {title:'红高粱', year:1987, rating:8.4, genre:['文艺','历史']}),
(:Movie {title:'活着', year:1994, rating:9.2, genre:['剧情','历史']}),
(:Movie {title:'霸王别姬', year:1993, rating:9.6, genre:['剧情','爱情']}),
(:Movie {title:'英雄', year:2002, rating:7.5, genre:['动作','武侠']}),
(:Movie {title:'无间道', year:2002, rating:9.1, genre:['犯罪','悬疑']}),
(:Movie {title:'一代宗师', year:2013, rating:8.0, genre:['动作','传记']}),
(:Movie {title:'流浪地球', year:2019, rating:8.5, genre:['科幻','灾难']}),
(:Movie {title:'战狼2', year:2017, rating:7.1, genre:['动作','军事']}),
(:Movie {title:'你好,李焕英', year:2021, rating:7.7, genre:['喜剧','家庭']}),
(:Movie {title:'满江红', year:2023, rating:7.2, genre:['悬疑','历史']});
// =======================
// 创建导演关系(9条)
// =======================
MATCH
(zhang:Person {name:'张艺谋'}),
(chen:Person {name:'陈凯歌'}),
(liu:Person {name:'刘德华'}),
(wu:Person {name:'吴京'}),
(jia:Person {name:'贾玲'}),
(guo:Person {name:'郭帆'}),
(m1:Movie {title:'红高粱'}),
(m2:Movie {title:'活着'}),
(m3:Movie {title:'霸王别姬'}),
(m4:Movie {title:'英雄'}),
(m5:Movie {title:'无间道'}),
(m6:Movie {title:'战狼2'}),
(m7:Movie {title:'你好,李焕英'}),
(m8:Movie {title:'流浪地球'}),
(m9:Movie {title:'满江红'})
CREATE
(zhang)-[:DIRECTED {award:true}]->(m1),
(zhang)-[:DIRECTED {award:true}]->(m2),
(zhang)-[:DIRECTED {award:false}]->(m4),
(zhang)-[:DIRECTED {award:false}]->(m9),
(chen)-[:DIRECTED {award:true}]->(m3),
(liu)-[:DIRECTED {award:false}]->(m5),
(wu)-[:DIRECTED {award:false}]->(m6),
(jia)-[:DIRECTED {award:true}]->(m7),
(guo)-[:DIRECTED {award:true}]->(m8);
// =======================
// 创建参演关系(11条)
// =======================
MATCH
(gong:Person {name:'巩俐'}), (ge:Person {name:'葛优'}),
(zhangyi:Person {name:'章子怡'}), (liu:Person {name:'刘德华'}),
(wu:Person {name:'吴京'}), (zhang:Person {name:'张艺谋'}),
(jia:Person {name:'贾玲'}),
(m1:Movie {title:'红高粱'}), (m2:Movie {title:'活着'}),
(m3:Movie {title:'霸王别姬'}), (m4:Movie {title:'英雄'}),
(m5:Movie {title:'无间道'}), (m6:Movie {title:'流浪地球'}),
(m7:Movie {title:'满江红'}), (m8:Movie {title:'战狼2'}),
(m9:Movie {title:'你好,李焕英'})
CREATE
(gong)-[:ACTED_IN {role:'九儿', award:true}]->(m1),
(gong)-[:ACTED_IN {role:'家珍', award:false}]->(m2),
(ge)-[:ACTED_IN {role:'福贵', award:true}]->(m2),
(ge)-[:ACTED_IN {role:'袁四爷', award:false}]->(m3),
(zhangyi)-[:ACTED_IN {role:'如月', award:false}]->(m4),
(zhangyi)-[:ACTED_IN {role:'宫二', award:true}]->(m7),
(liu)-[:ACTED_IN {role:'刘建明', award:false}]->(m5),
(wu)-[:ACTED_IN {role:'刘培强', award:true}]->(m6),
(zhang)-[:ACTED_IN {role:'秦桧', award:false}]->(m7),
(wu)-[:ACTED_IN {role:'冷锋', award:true}]->(m8),
(jia)-[:ACTED_IN {role:'贾晓玲', award:true}]->(m9);
// =======================
// 创建关注关系(11条)
// =======================
MATCH
(gong:Person {name:'巩俐'}), (zhang:Person {name:'张艺谋'}),
(zhangyi:Person {name:'章子怡'}), (chen:Person {name:'陈凯歌'}),
(ge:Person {name:'葛优'}), (liu:Person {name:'刘德华'}),
(wu:Person {name:'吴京'}), (jia:Person {name:'贾玲'}),
(guo:Person {name:'郭帆'})
CREATE
(gong)-[:FOLLOWS]->(zhang),
(zhangyi)-[:FOLLOWS]->(zhang),
(zhang)-[:FOLLOWS]->(chen),
(ge)-[:FOLLOWS]->(chen),
(liu)-[:FOLLOWS]->(zhang),
(gong)-[:FOLLOWS]->(zhangyi),
(wu)-[:FOLLOWS]->(zhang),
(jia)-[:FOLLOWS]->(zhang),
(guo)-[:FOLLOWS]->(zhang),
(liu)-[:FOLLOWS]->(wu),
(zhang)-[:FOLLOWS]->(guo);
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# 5.1 过滤:不只是 WHERE
WHERE 子句是筛选数据的看门人,支持比较、逻辑、集合、字符串匹配和空值判断。
-- 1970年后出生的演员
MATCH (p:Person)
WHERE p.birth > '1970-01-01'
RETURN p.name, p.birth
2
3
4
-- 高分且老电影
MATCH (m:Movie)
WHERE m.rating > 8.0 AND m.year < 2000
RETURN m.title, m.year, m.rating
2
3
4
-- 历史类影片
MATCH (m:Movie)
WHERE '历史' IN m.genre
RETURN m.title, m.genre
2
3
4
-- 姓张的人
MATCH (p:Person)
WHERE p.name CONTAINS '张'
RETURN p.name
2
3
4
# 5.2 排序与分页
ORDER BY 控制升降序,SKIP 和 LIMIT 实现分页,和 SQL 几乎一个思路。
MATCH (m:Movie)
RETURN m.title, m.rating
ORDER BY m.rating DESC
LIMIT 3
2
3
4
MATCH (m:Movie)
RETURN m.title, m.year
ORDER BY m.year DESC
SKIP 5
LIMIT 5
2
3
4
5
# 5.3 聚合统计
Cypher 的聚合函数(count、avg、sum、max、min、collect 等)会自动按非聚合字段分组,无需显式 GROUP BY。
-- 演员人数(去重)
MATCH (p:Person)-[:ACTED_IN]->()
RETURN count(DISTINCT p) AS 演员人数
2
3
-- 每人参演电影数
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
RETURN p.name, count(m) AS 参演电影数
2
3
-- 导演作品列表
MATCH (p:Person)-[:DIRECTED]->(m:Movie)
RETURN p.name, collect(m.title) AS 导演作品
2
3
# 5.4 联合与子查询
UNION 和 UNION ALL 用于拼接多个结果集,注意列数和类型必须一致。
MATCH (p:Person {name:'张艺谋'})-[:DIRECTED]->(m:Movie)
RETURN m.title AS title, '导演' AS role
UNION
MATCH (p:Person {name:'张艺谋'})-[:ACTED_IN]->(m:Movie)
RETURN m.title AS title, '演员' AS role
2
3
4
5
子查询用 CALL (变量) { ... } 包裹,可对每行输入执行独立匹配:
MATCH (p:Person)-[:DIRECTED]->()
WITH DISTINCT p
CALL (p) {
MATCH (p)-[:DIRECTED]->(m:Movie)
RETURN m.title AS title, m.rating AS rating
ORDER BY rating DESC
LIMIT 1
}
RETURN p.name AS 导演, title AS 最高评分作品, rating AS 评分
2
3
4
5
6
7
8
9
这里的 WITH DISTINCT p 负责将中间结果去重后传递到子查询,CALL (p) 则让每一行数据都执行一次内部匹配。
# 5.5 灵活的模式匹配
标签表达式:&(与)、|(或)、!(非)组合节点标签。
MATCH (n:(Person|Movie)) RETURN n -- Person 或 Movie
MATCH (n:(!Person)) RETURN n -- 不是 Person
2
关系也可以使用类型表达式:
MATCH (:Person {name: '张艺谋'})-[:ACTED_IN|DIRECTED]->(m:Movie)
RETURN DISTINCT m.title
2
无方向查询:去掉关系箭头,匹配任意方向。
MATCH (p1:Person {name: '巩俐'})-[:ACTED_IN]-(m:Movie)-[:ACTED_IN]-(p2:Person)
RETURN path
2
变长路径:用 {m,n} 指定跳数范围,非常适合做社交网络扩散分析。
-- 张艺谋粉丝的粉丝(2跳)
MATCH path= (a:Person)-[:FOLLOWS]->{2}(b:Person{name:'张艺谋'})
RETURN path
2
3
# 6. 约束:让数据干净起来
Neo4j 支持多种约束来维护数据完整性。在社区版中我们最常用的是属性唯一性约束,它可以确保某个属性在指定标签的所有节点(或指定类型的关系)中不重复。
创建唯一约束
CREATE CONSTRAINT unique_user_id
FOR (u:User)
REQUIRE u.userId IS UNIQUE;
2
3
此后,如果尝试插入相同 userId 的节点:
CREATE (u:User {userId: 'u001', name: 'Alice'});
CREATE (u:User {userId: 'u001', name: 'Charlie'}); // 报错!
2
Neo4j 会抛出 ConstraintValidationFailed,杜绝脏数据进入图谱。
查看已有约束:
SHOW CONSTRAINTS;
删除约束(例如重构数据模型时):
DROP CONSTRAINT unique_user_id;
小贴士:企业版还支持属性存在约束、属性类型约束和复合键约束,但社区版足以覆盖大多数入门和学习场景。
# 7. 用 Python 撬动 Neo4j
生产环境中,我们往往通过代码与图数据库交互。Neo4j 官方 Python 驱动简洁高效,安装只需一行:
pip install neo4j
# 7.1 建立连接
Driver 对象是连接池的入口,线程安全但创建成本高,应用中应该全局复用。推荐使用 with 语句自动管理资源。
from neo4j import GraphDatabase
URI = "neo4j://localhost"
AUTH = ("neo4j", "password")
with GraphDatabase.driver(URI, auth=AUTH) as driver:
driver.verify_connectivity()
print("Connection established.")
2
3
4
5
6
7
8
# 7.2 执行查询
execute_query() 是执行 Cypher 最便捷的方式,它返回一个命名元组,包含记录列表、执行摘要和字段名。
records, summary, keys = driver.execute_query(
"""
MATCH (p:Person{name:$name})-[r:DIRECTED]->(m:Movie)
WHERE m.year > $year
RETURN p.name AS director, m.year AS year, m.title AS movie
""",
parameters_={"name": "张艺谋", "year": 1990},
database_="neo4j"
)
print(f"查询返回了 {len(records)} 条记录")
for record in records:
print(f"{record['director']}在{record['year']}年拍摄了《{record['movie']}》")
2
3
4
5
6
7
8
9
10
11
12
13
通过参数化查询($name、$year),你既提升了性能,也规避了 Cypher 注入风险。execute_query 足以满足大多数事务性操作;如需更精细的事务控制,驱动也提供了 session 级别的 API,留给读者延伸探索。
# 写在最后
从单机安装到 Python 集成,你已经走完了 Neo4j 入门全流程。回顾一下关键收获:
- 图数据库用节点+关系直击问题本质。
- Cypher 让你像画图一样查询数据,学习曲线平滑。
- 高级模式匹配、聚合、分页、约束等功能足以应对复杂业务。
- Python 驱动让 Neo4j 无缝融入现代 AI 技术栈。
在大模型时代,图谱不仅是知识的容器,更是将符号逻辑与深度学习结合的关键桥梁。无论你是在构建 Graph RAG,还是做用户画像、风控分析,Neo4j 都能成为你的得力助手。动手把今天的内容跑一遍,你会发现,图的世界比想象中更精彩。