TL;DR
系列方向: 从图数据库基础开始,以 Neo4j 为主要技术平台,逐步学习图数据建模、Cypher 查询语言、关系遍历、性能优化和 Python 应用开发,最终完成一个可以运行的图数据库业务项目。
本篇重点: 不只是了解图数据库是什么,而是通过一个用户关系业务场景,理解节点、关系和属性的实际作用,并使用 Docker 部署 Neo4j,完成第一个可运行的图数据库项目。
一、先从一个实际业务问题开始
假设我们正在开发一个社交平台。
平台中有大量用户,每个用户都可能与其他用户建立好友关系。
现在产品提出了几个需求:
- 查询张三的所有好友。
- 查询张三的好友的好友。
- 找出张三和李四之间的共同好友。
- 推荐可能认识的人。
- 分析用户之间的多层关系。
这些需求听起来并不复杂,但随着关系层级不断增加,数据查询也会逐渐变得复杂。
例如,查询一个用户的直接好友,传统 SQL 通过 JOIN 就可以实现。
但如果要查询好友的好友、好友的好友的好友,甚至需要分析多层关系路径,查询逻辑就会越来越复杂。
这时候,我们可以考虑使用图数据库。
图数据库的核心思路是:
把用户看作节点,把用户之间的好友关系看作边,通过关系遍历完成查询。
这也是本系列选择 Neo4j 作为学习平台的原因。
二、认识 Neo4j
Neo4j 是一款以图结构存储和查询数据的数据库。
它采用属性图模型,主要由三个部分组成:
- Node:节点,表示一个实体。
- Relationship:关系,表示实体之间的联系。
- Property:属性,用于描述节点或关系的特征。
举个例子:
text
张三 ──好友──> 李四
李四 ──好友──> 王五
张三 ──关注──> 王五
在 Neo4j 中,可以为节点添加标签和属性,也可以为关系添加类型、方向和属性。
例如:
cypher
CREATE
(zhang:User {
name: '张三',
age: 25
}),
(li:User {
name: '李四',
age: 26
}),
(zhang)-[:FRIEND {
since: '2024-01-01'
}]->(li);
这里:
- User 是节点标签。
- name、age 是节点属性。
- FRIEND 是关系类型。
- since 是关系属性。
- 箭头表示关系方向。
需要注意,Neo4j 的关系有明确的方向,但具体业务是否需要双向关系,要根据建模方式决定。
三、搭建 Neo4j 开发环境
本系列使用 Neo4j Community Edition 作为入门环境。
为了方便后续文章复现,建议使用 Docker 部署。
3.1 环境要求
| 软件 | 用途 |
|---|---|
| Docker | 容器运行环境 |
| Neo4j | 图数据库 |
| Neo4j Browser | 图形化查询工具 |
| 浏览器 | 访问数据库管理界面 |
Docker 安装完成后,先检查版本:
bash
docker --version
确认 Docker 服务正常运行。
3.2 启动 Neo4j
执行以下命令:
bash
docker run -d \
--name neo4j-lab \
-p 7474:7474 \
-p 7687:7687 \
-e NEO4J_AUTH=neo4j/Neo4j123456 \
-v neo4j_data:/data \
-v neo4j_logs:/logs \
neo4j:5-community
这里先固定使用 Neo4j 5 Community 版本,保证本系列代码环境一致。
为什么不直接使用 latest?
因为学习项目最好固定版本,避免后续镜像升级导致功能和运行行为发生变化。
参数说明:
| 参数 | 作用 |
|---|---|
| -d | 后台运行 |
| --name | 设置容器名称 |
| -p 7474:7474 | Web 管理界面 |
| -p 7687:7687 | Bolt 数据库连接 |
| NEO4J_AUTH | 设置初始账号密码 |
| /data | 持久化数据库文件 |
| /logs | 持久化日志 |
这里的密码只用于本地学习环境,不要用于生产环境。
3.3 检查容器状态
bash
docker ps
如果容器已经启动,可以查看日志:
bash
docker logs neo4j-lab
如果出现数据库启动完成的信息,说明服务基本已经正常运行。
如果启动失败,先检查容器日志,不要直接重复创建容器。
3.4 打开 Neo4j Browser
浏览器访问:
text
http://localhost:7474
连接参数:
text
Connect URL:
bolt://localhost:7687
Username:
neo4j
Password:
Neo4j123456
登录后就可以看到 Neo4j Browser 的查询界面。
到这里,我们已经有了一个可以使用的图数据库环境。
四、创建第一个图数据库
环境搭建完成后,我们不急着导入大量数据。
先通过一个简单案例理解 Neo4j 的基本操作。
4.1 创建用户节点
在 Neo4j Browser 中执行:
cypher
CREATE
(:User {
user_id: 1,
name: '张三',
age: 25
}),
(:User {
user_id: 2,
name: '李四',
age: 26
}),
(:User {
user_id: 3,
name: '王五',
age: 27
});
这条语句创建了三个 User 节点。
查询所有用户:
cypher
MATCH (u:User)
RETURN u;
Neo4j Browser 会以图形方式展示节点。
4.2 创建用户之间的关系
现在假设:
- 张三和李四是好友。
- 李四和王五是好友。
- 张三关注了王五。
执行:
cypher
MATCH
(zhang:User {name: '张三'}),
(li:User {name: '李四'}),
(wang:User {name: '王五'})
CREATE
(zhang)-[:FRIEND]->(li),
(li)-[:FRIEND]->(wang),
(zhang)-[:FOLLOW]->(wang);
再次执行:
cypher
MATCH (u:User)-[r]->(v:User)
RETURN u, r, v;
现在可以看到用户节点之间已经建立了不同类型的关系。
4.3 查询张三的好友
cypher
MATCH
(u:User {name: '张三'})
-[:FRIEND]->(friend:User)
RETURN friend.name AS friend_name;
预期结果:
| friend_name |
|---|
| 李四 |
4.4 查询张三好友的好友
cypher
MATCH
(u:User {name: '张三'})
-[:FRIEND]->(:User)
-[:FRIEND]->(friend:User)
RETURN friend.name AS friend_name;
预期结果:
| friend_name |
|---|
| 王五 |
这里最值得关注的是查询表达方式。
我们不需要像传统 SQL 那样不断增加 JOIN,而是直接描述需要匹配的关系路径。
这就是 Cypher 的一个重要特点。
五、理解 MATCH、CREATE 和 RETURN
刚才已经执行了几条 Cypher 语句,现在总结一下最基础的三个关键字。
CREATE:创建节点或关系
创建一个用户:
cypher
CREATE (:User {
name: '赵六',
age: 28
});
创建两个节点之间的关系:
cypher
MATCH
(a:User {name: '张三'}),
(b:User {name: '赵六'})
CREATE (a)-[:FRIEND]->(b);
MATCH:匹配节点和关系
查询所有用户:
cypher
MATCH (u:User)
RETURN u;
查询年龄大于 25 岁的用户:
cypher
MATCH (u:User)
WHERE u.age > 25
RETURN u.name, u.age;
RETURN:返回查询结果
cypher
MATCH (u:User)
RETURN u.name AS username;
这里 AS 用于设置返回字段的别名。
这三个关键字是后续学习 Cypher 的基础。
六、一个容易忽略的问题:重复创建数据
刚才使用 CREATE 创建用户和好友关系。
但如果重复执行创建语句,就可能产生重复节点和重复关系。
例如:
cypher
CREATE (:User {
user_id: 1,
name: '张三',
age: 25
});
执行两次,就会创建两个张三节点。
这在实际项目中是需要避免的。
后续我们会重点学习 MERGE,以及如何通过唯一性约束保证数据一致性。
这里先记住一个原则:
CREATE 负责创建,MERGE 负责按照指定模式匹配或创建。
七、本篇实践总结
本篇完成了以下内容:
- 认识了 Neo4j 和图数据库的基本概念。
- 使用 Docker 启动 Neo4j。
- 通过 Neo4j Browser 连接数据库。
- 创建用户节点。
- 创建好友和关注关系。
- 使用 MATCH 查询一层和两层关系。
虽然案例很简单,但已经建立了一个可以继续扩展的用户关系图。
接下来我们会逐渐增加用户数量、关系类型和业务场景。
另外,本篇使用的是小规模演示数据,重点是理解图模型和 Cypher 查询方式,还不能据此判断图数据库在大规模数据下的性能优势。