安装使用(windows)
- 下载
官网找到社区版本Neo4j community
注意: 3.* 对应java8, 5.*对应java21
-
环境变量配置
新建
NEO4J_HOME,并在变量值neo4j-community文件所在根目录
PATH中新增bin文件夹配置%NEO4J_HOME%\bin -
测试
cd neo4j-community-3.5.32\bin && neo4j.bat console
shell
D:\neo4j-community-2025.12.1\bin>neo4j.bat console
Directories in use:
home: D:\neo4j-community-2025.12.1
config: D:\neo4j-community-2025.12.1\conf
logs: D:\neo4j-community-2025.12.1\logs
plugins: D:\neo4j-community-2025.12.1\plugins
import: D:\neo4j-community-2025.12.1\import
data: D:\neo4j-community-2025.12.1\data
certificates: D:\neo4j-community-2025.12.1\certificates
licenses: D:\neo4j-community-2025.12.1\licenses
run: D:\neo4j-community-2025.12.1\run
Starting Neo4j.
2026-01-19 13:43:01.202+0000 INFO Logging config in use: File 'D:\neo4j-community-2025.12.1\conf\user-logs.xml'
2026-01-19 13:43:01.226+0000 INFO Starting...
2026-01-19 13:43:01.726+0000 INFO This instance is ServerId{168fd9ce} ()
2026-01-19 13:43:02.459+0000 INFO ======== Neo4j 2025.12.1 ========
2026-01-19 13:43:03.648+0000 INFO Anonymous Usage Data is being sent to Neo4j, see https://neo4j.com/docs/usage-data/
2026-01-19 13:43:04.121+0000 INFO Bolt enabled on localhost:7687.
2026-01-19 13:43:04.658+0000 INFO HTTP enabled on localhost:7474.
2026-01-19 13:43:04.658+0000 INFO Remote interface available at http://localhost:7474/
2026-01-19 13:43:04.658+0000 INFO id:
2026-01-19 13:43:04.658+0000 INFO name: system
2026-01-19 13:43:04.658+0000 INFO creationDate: 2026-01-19T13:43:03.323Z
2026-01-19 13:43:04.658+0000 INFO Started.
Neo4j 增删改查 - 入门版
一、就像跟朋友聊天一样简单
把 Neo4j 想象成一个人际关系笔记本:
- 节点 = 一个人(比如:张三)
- 标签 = 这个人是谁(比如:
朋友、同事、家人) - 关系 = 怎么认识的(比如:
认识、喜欢、同事)
二、增(CREATE) - 添加信息
1. 添加一个人
cypher
-- 添加一个朋友叫张三,28岁,北京人
CREATE (:朋友 {名字:'张三', 年龄:28, 城市:'北京'})
2. 添加多个人
cypher
CREATE (:朋友 {名字:'李四', 年龄:25}),
(:同事 {名字:'王五', 部门:'技术部'}),
(:家人 {名字:'妈妈', 关系:'母亲'})
3. 添加关系(连接两个人)
cypher
-- 先找到两个人
MATCH (张三:朋友 {名字:'张三'})
MATCH (李四:朋友 {名字:'李四'})
-- 让他们成为朋友(2010年认识的)
CREATE (张三)-[:认识 {认识时间:'2010年', 关系:'好朋友'}]->(李四)
一句话版本:
cypher
-- 直接创建两个人并连接
CREATE (:朋友 {名字:'小明'})-[:喜欢]->(:食物 {名字:'披萨'})
三、查(MATCH) - 查看信息
1. 查看所有人
cypher
-- 查看所有朋友
MATCH (p:朋友) RETURN p
-- 查看朋友的名字和年龄
MATCH (p:朋友) RETURN p.名字, p.年龄
2. 按条件查找
cypher
-- 找北京的朋友
MATCH (p:朋友 {城市:'北京'}) RETURN p.名字
-- 找年龄大于25的朋友
MATCH (p:朋友) WHERE p.年龄 > 25 RETURN p.名字, p.年龄
3. 查看关系
cypher
-- 张三认识谁?
MATCH (张三:朋友 {名字:'张三'})-[关系]->(谁)
RETURN 谁.名字, 关系.认识时间
-- 谁和谁是朋友?
MATCH (a:朋友)-[r:认识]->(b:朋友)
RETURN a.名字, b.名字, r.关系
四、改(SET) - 修改信息
1. 修改属性
cypher
-- 给张三添加电话号码
MATCH (p:朋友 {名字:'张三'})
SET p.电话 = '13800138000'
-- 修改张三的年龄
MATCH (p:朋友 {名字:'张三'})
SET p.年龄 = 29
-- 一次修改多个属性
MATCH (p:朋友 {名字:'张三'})
SET p.城市 = '上海',
p.职业 = '工程师',
p.更新时间 = '2023-01-01'
2. 添加标签
cypher
-- 张三同时也是同事
MATCH (p {名字:'张三'})
SET p:同事
-- 有多个标签(既是朋友又是同事)
MATCH (p {名字:'李四'})
SET p:朋友:同事:VIP会员
五、删(DELETE) - 删除信息
1. 删除属性
cypher
-- 删除张三的电话号码
MATCH (p:朋友 {名字:'张三'})
REMOVE p.电话
-- 删除年龄属性
MATCH (p:朋友 {名字:'张三'})
REMOVE p.年龄
2. 删除关系
cypher
-- 删除张三和李四的"认识"关系
MATCH (张三:朋友 {名字:'张三'})-[r:认识]->(李四:朋友 {名字:'李四'})
DELETE r
3. 删除节点(小心!)
cypher
-- 删除张三这个人
MATCH (p:朋友 {名字:'张三'})
DELETE p
-- 先删除关系,再删除节点(安全做法)
MATCH (p:朋友 {名字:'张三'})-[r]-()
DELETE r, p
六、完整例子:朋友圈管理
cypher
-- 1. 添加朋友
CREATE (:朋友 {名字:'小明', 年龄:25, 城市:'北京'}),
(:朋友 {名字:'小红', 年龄:23, 城市:'上海'}),
(:朋友 {名字:'小刚', 年龄:28, 城市:'广州'})
-- 2. 建立朋友关系
MATCH (小明:朋友 {名字:'小明'})
MATCH (小红:朋友 {名字:'小红'})
CREATE (小明)-[:认识 {时间:'2022年', 怎么认识:'大学同学'}]->(小红)
-- 3. 查看所有朋友
MATCH (p:朋友) RETURN p.名字, p.年龄, p.城市
-- 4. 小明搬家到深圳
MATCH (p:朋友 {名字:'小明'})
SET p.城市 = '深圳'
-- 5. 删除小刚(他不玩朋友圈了)
MATCH (p:朋友 {名字:'小刚'})
DELETE p
-- 6. 查看剩余的朋友
MATCH (p:朋友) RETURN p.名字
七、需要记住的公式
1. 增加:CREATE (标签:名字 {属性:值})
2. 查询:MATCH (条件) RETURN 显示什么
3. 修改:MATCH (条件) SET 属性=新值
4. 删除:MATCH (条件) DELETE 什么
八、千万要注意!
⚠️ 删除前先查询
cypher
-- 错误:直接删除会删掉所有!
DELETE p -- 别这样!
-- 正确:先看看要删什么
MATCH (p:朋友) RETURN p -- 先查看
MATCH (p:朋友 {名字:'张三'}) DELETE p -- 再删除
⚠️ 关系不能单独存在
cypher
-- 错误:有关系的节点不能直接删
MATCH (p:朋友 {名字:'小明'}) DELETE p -- 会报错!
-- 正确:先删关系,再删节点
MATCH (p:朋友 {名字:'小明'})-[r]-()
DELETE r, p
九、最常用命令总结
| 想做什么 | 命令模板 |
|---|---|
| 添加一个人 | CREATE (:标签 {名字:'张三'}) |
| 找人 | MATCH (p:标签 {名字:'张三'}) RETURN p |
| 修改信息 | MATCH (p {名字:'张三'}) SET p.新属性='值' |
| 删除人 | MATCH (p {名字:'张三'}) DELETE p |
| 建立关系 | CREATE (张三)-[:关系]->(李四) |
| 删除关系 | MATCH ()-[r:关系]->() DELETE r |
简单练习
打开 Neo4j Browser(网页界面),依次输入:
cypher
-- 1. 创建你的第一个节点
CREATE (:我 {名字:'[你的名字]', 爱好:'编程'})
-- 2. 查看是否创建成功
MATCH (n:我) RETURN n
-- 3. 添加更多信息
MATCH (n:我)
SET n.年龄 = 20,
n.城市 = '北京'
-- 4. 再查看一次
MATCH (n:我) RETURN n
-- 5. 创建朋友
CREATE (:朋友 {名字:'AI助手', 类型:'人工智能'})
-- 6. 建立关系
MATCH (我:我), (朋友:朋友 {名字:'AI助手'})
CREATE (我)-[:使用]->(朋友)
-- 7. 查看整个关系图
MATCH (a)-[r]->(b)
RETURN a, r, b
就是这样!你已经学会了 Neo4j 的基本操作 🎉
记住:CREATE 添加,MATCH 查找,SET 修改,DELETE 删除
Neo4j 关系的增删改查 - 超详细版
一、关系的核心概念
简单比喻:
节点 = 两个人(张三、李四)
关系 = 他们之间的连接线(认识、同事、朋友)
关系属性 = 线上的标签(认识多久、关系多好)
二、增(CREATE)关系
1. 基础创建:连接两个现有节点
cypher
-- 先找到两个节点
MATCH (张三:人 {名字:'张三'})
MATCH (李四:人 {名字:'李四'})
-- 创建关系(A 认识 B)
CREATE (张三)-[:认识]->(李四)
-- 创建双向关系(互相认识)
CREATE (张三)-[:认识]->(李四)
CREATE (李四)-[:认识]->(张三)
-- 或者用更简洁的方式
CREATE (张三)-[:认识]->(李四),
(李四)-[:认识]->(张三)
2. 创建时添加属性
cypher
-- 创建带详细信息的"认识"关系
CREATE (张三)-[:认识 {
认识时间: '2020-01-01',
地点: '北京',
介绍人: '王五',
亲密程度: 7
}]->(李四)
3. 一次性创建节点和关系
cypher
-- 最常用的方式!
CREATE (张三:人 {名字:'张三'})
-[:同事 {
部门: '技术部',
共事开始: '2021-03-15'
}]->
(李四:人 {名字:'李四'})
-- 创建三角形关系网
CREATE (小明:学生 {名字:'小明'}),
(小红:学生 {名字:'小红'}),
(小刚:学生 {名字:'小刚'}),
(小明)-[:同班]->(小红),
(小红)-[:同班]->(小刚),
(小刚)-[:同桌]->(小明)
4. 创建不同类型的关系
cypher
-- 一个人可以有多种关系
MATCH (张三:人 {名字:'张三'})
MATCH (公司:公司 {名称:'阿里巴巴'})
-- 同时创建工作和朋友关系
CREATE (张三)-[:工作于 {
职位: '工程师',
入职时间: '2020-01-01',
工资: 25000
}]->(公司),
(张三)-[:朋友]->(:人 {名字:'王五'}),
(张三)-[:喜欢]->(:爱好 {名称:'篮球'})
三、查(MATCH)关系
1. 查找特定关系
cypher
-- 查找所有"认识"关系
MATCH ()-[r:认识]->()
RETURN r
-- 查找具体的两个人之间的关系
MATCH (张三:人 {名字:'张三'})-[r]-(李四:人 {名字:'李四'})
RETURN type(r) as 关系类型, r as 关系详情
2. 查找关系的属性
cypher
-- 查看关系的具体信息
MATCH (:人 {名字:'张三'})-[r:认识]->(:人 {名字:'李四'})
RETURN r.认识时间, r.地点, r.亲密程度
-- 按关系属性筛选
MATCH ()-[r:认识]->()
WHERE r.亲密程度 > 5 AND r.认识时间 > '2021-01-01'
RETURN r
3. 查找关系路径
cypher
-- 找通过朋友认识的人(朋友的朋友)
MATCH (我:人 {名字:'张三'})-[:认识]->(朋友)-[:认识]->(朋友的朋友)
RETURN 朋友.名字 as 直接朋友, 朋友的朋友.名字 as 间接朋友
-- 查找多层关系(最多3层)
MATCH (我:人 {名字:'张三'})-[:认识*1..3]->(陌生人)
RETURN 陌生人.名字, count(*) as 关系层数
4. 查找关系统计
cypher
-- 谁的朋友最多?
MATCH (p:人)-[:认识]->(朋友)
RETURN p.名字, count(朋友) as 朋友数量
ORDER BY 朋友数量 DESC
-- 关系的平均亲密程度
MATCH ()-[r:认识]->()
RETURN avg(r.亲密程度) as 平均亲密程度
四、改(SET)关系
1. 修改关系属性
cypher
-- 增加或修改关系属性
MATCH (张三:人 {名字:'张三'})-[r:认识]->(李四:人 {名字:'李四'})
SET r.亲密程度 = 8,
r.最近联系 = date(),
r.备注 = '很好的朋友'
-- 增加新属性
MATCH (:人 {名字:'张三'})-[r:同事]->(:人 {名字:'李四'})
SET r.项目合作 = '支付宝项目',
r.配合评分 = 9.5
2. 修改关系类型(不能直接改,需要重新创建)
cypher
-- 错误:不能直接修改关系类型
-- MATCH ()-[r:认识]->() SET r:朋友 -- 不行!
-- 正确做法:先删除旧关系,再创建新关系
MATCH (张三:人 {名字:'张三'})-[r:认识]->(李四:人 {名字:'李四'})
-- 保存旧属性
WITH 张三, 李四, r.认识时间 as 旧时间, r.地点 as 旧地点
-- 删除旧关系
DELETE r
-- 创建新关系并保留旧属性
CREATE (张三)-[:朋友 {
成为朋友时间: 旧时间,
认识地点: 旧地点,
好友等级: 'A级'
}]->(李四)
3. 批量修改关系
cypher
-- 给所有"同事"关系添加公司信息
MATCH ()-[r:同事]->()
WHERE r.公司 IS NULL
SET r.公司 = '默认公司',
r.更新时间 = timestamp()
-- 修改符合条件的多个关系
MATCH (a)-[r:交易]->(b)
WHERE r.金额 > 10000
SET r.状态 = '大额交易',
r.需要审核 = true,
r.审核人 = '财务部'
五、删(DELETE)关系
1. 删除特定关系
cypher
-- 删除两个人之间的"认识"关系
MATCH (张三:人 {名字:'张三'})-[r:认识]->(李四:人 {名字:'李四'})
DELETE r
-- 删除特定属性的关系
MATCH ()-[r:认识]->()
WHERE r.亲密程度 < 3 -- 删除不亲密的关系
DELETE r
2. 删除某人所有的某种关系
cypher
-- 删除张三所有的"认识"关系
MATCH (张三:人 {名字:'张三'})-[r:认识]-()
DELETE r
-- 删除张三所有的关系(不管什么类型)
MATCH (张三:人 {名字:'张三'})-[r]-()
DELETE r
3. 批量删除关系
cypher
-- 删除所有过期的"临时"关系
MATCH ()-[r:临时关系]->()
WHERE r.过期时间 < date()
DELETE r
-- 删除所有空的关系(没有属性)
MATCH ()-[r]->()
WHERE r IS NOT NULL AND keys(r) = []
DELETE r
4. 安全删除(先检查再删除)
cypher
-- 安全做法:先看看要删什么
MATCH (张三:人 {名字:'张三'})-[r]->()
RETURN type(r) as 关系类型, count(r) as 数量
-- 确认无误后再删
-- 或者用事务方式
BEGIN
MATCH (张三:人 {名字:'张三'})-[r:认识]->()
DELETE r
RETURN count(r) as 已删除数量
COMMIT
六、综合实例:社交网络管理
cypher
-- 1. 创建社交网络
CREATE (张三:用户 {名字:'张三', 年龄:28}),
(李四:用户 {名字:'李四', 年龄:25}),
(王五:用户 {名字:'王五', 年龄:30}),
(公司:企业 {名称:'腾讯'}),
-- 建立关系
(张三)-[:关注 {时间:'2023-01-01'}]->(李四),
(张三)-[:关注 {时间:'2023-02-01'}]->(王五),
(李四)-[:关注 {时间:'2023-01-15'}]->(张三),
(张三)-[:工作于 {职位:'工程师'}]->(公司),
-- 2. 查询张三的关注关系
MATCH (张三:用户 {名字:'张三'})-[r:关注]->(被关注)
RETURN 被关注.名字, r.时间
ORDER BY r.时间 DESC
-- 3. 修改关系:张三取消对李四的关注
MATCH (张三:用户 {名字:'张三'})-[r:关注]->(李四:用户 {名字:'李四'})
DELETE r
RETURN '已取消关注'
-- 4. 添加新关系:张三关注了新朋友
MATCH (张三:用户 {名字:'张三'})
MATCH (新人:用户 {名字:'赵六'})
CREATE (张三)-[:关注 {
时间: date(),
来源: '系统推荐',
兴趣匹配度: 85
}]->(新人)
-- 5. 修改关系属性:更新关注时间
MATCH (张三:用户 {名字:'张三'})-[r:关注]->(王五:用户 {名字:'王五'})
SET r.最近互动 = datetime(),
r.互动次数 = COALESCE(r.互动次数, 0) + 1
-- 6. 分析关系网络
-- 谁被最多人关注?
MATCH (用户:用户)<-[r:关注]-()
RETURN 用户.名字, count(r) as 粉丝数
ORDER BY 粉丝数 DESC
-- 互相关注的好友
MATCH (a:用户)-[:关注]->(b:用户),
(b:用户)-[:关注]->(a:用户)
RETURN a.名字 as 用户A, b.名字 as 用户B
七、高级关系操作
1. 关系方向操作
cypher
-- 忽略方向查询(A和B有关系,不管谁指向谁)
MATCH (张三:人)-[:认识]-(李四:人)
RETURN 张三.名字, 李四.名字
-- 只查询指向自己的关系
MATCH (张三:人)<-[r:认识]-(别人)
RETURN 别人.名字 as 谁关注我, r.时间
-- 只查询自己指向别人的关系
MATCH (张三:人)-[r:认识]->(别人)
RETURN 别人.名字 as 我关注谁, r.时间
2. 关系路径查找
cypher
-- 找到张三到王五的最短路径
MATCH path = shortestPath(
(张三:人 {名字:'张三'})-[:认识|同事|朋友*]-(王五:人 {名字:'王五'})
)
RETURN path, length(path) as 关系层数
-- 找到所有可能的联系路径(最多3步)
MATCH path = (张三:人 {名字:'张三'})-[:认识*1..3]-(陌生人)
RETURN 陌生人.名字, [node in nodes(path) | node.名字] as 路径
3. 关系聚合查询
cypher
-- 统计关系的各种信息
MATCH (:人)-[r:交易]->(:商家)
RETURN
count(r) as 总交易数,
sum(r.金额) as 总金额,
avg(r.金额) as 平均金额,
max(r.金额) as 最大交易,
min(r.金额) as 最小交易
八、重要注意事项
⚠️ 关系不能单独存在
cypher
-- 错误:删除节点时不删除关系
MATCH (n:人 {名字:'张三'})
DELETE n -- 如果张三有关系,会报错!
-- 正确:先删关系,再删节点
MATCH (n:人 {名字:'张三'})-[r]-()
DELETE r, n
⚠️ 关系必须有方向
cypher
-- 创建时必须指定方向
CREATE (A)-[:关系]->(B) -- 正确
CREATE (A)-[:关系]-(B) -- 错误!少了一个箭头
-- 但查询时可以忽略方向
MATCH (A)-[:关系]-(B) -- 查询时这样可以
⚠️ 关系类型不能有空格
cypher
-- 错误
CREATE ()-[:好友 关系]->() -- 有空格
-- 正确
CREATE ()-[:好友关系]->() -- 无空格
CREATE ()-[:好友_关系]->() -- 用下划线
九、实战练习
cypher
-- 练习:家庭关系管理
-- 1. 创建家庭成员
CREATE (爷爷:家人 {名字:'爷爷', 辈分:'祖辈'}),
(爸爸:家人 {名字:'爸爸', 辈分:'父辈'}),
(我:家人 {名字:'小明', 辈分:'子辈'}),
(儿子:家人 {名字:'小亮', 辈分:'孙辈'})
-- 2. 建立家庭关系
CREATE (爷爷)-[:父亲]->(爸爸),
(爸爸)-[:父亲]->(我),
(我)-[:父亲]->(儿子),
(爷爷)-[:祖父]->(我),
(爷爷)-[:曾祖父]->(儿子)
-- 3. 查询:我的所有祖先
MATCH (我:家人 {名字:'小明'})<-[:父亲*]-(祖先)
RETURN 祖先.名字, 祖先.辈分
-- 4. 修改:添加关系属性
MATCH (爸爸:家人 {名字:'爸爸'})-[r:父亲]->(我:家人 {名字:'小明'})
SET r.出生年份 = 1980,
r.教育程度 = '大学'
-- 5. 删除:如果关系录入错误
MATCH (某人)-[r:父亲]->(儿子:家人 {名字:'小亮'})
WHERE 某人.名字 = '爸爸' -- 发现录错了,爸爸不是小亮的父亲
DELETE r
-- 6. 重新建立正确关系
MATCH (我:家人 {名字:'小明'})
MATCH (儿子:家人 {名字:'小亮'})
CREATE (我)-[:父亲 {
关系确认: true,
确认时间: date()
}]->(儿子)
十、快速参考表
| 操作 | 命令 | 说明 |
|---|---|---|
| 创建关系 | CREATE (A)-[:类型]->(B) |
最基本的创建 |
| 带属性创建 | CREATE (A)-[:类型 {属性:值}]->(B) |
创建时添加属性 |
| 查找关系 | MATCH (A)-[r:类型]->(B) |
给关系起名 r |
| 查找关系属性 | MATCH ()-[r:类型]->() RETURN r.属性 |
返回属性值 |
| 修改关系 | MATCH ()-[r:类型]->() SET r.属性=值 |
修改属性 |
| 删除关系 | MATCH ()-[r:类型]->() DELETE r |
删除关系 |
| 查找路径 | MATCH path = ()-[:类型*]-() RETURN path |
查找连接路径 |
| 统计关系 | MATCH ()-[r:类型]->() RETURN count(r) |
统计数量 |
记住:关系就是节点之间的线,可以带属性、有方向、可以查询和修改!
图 = 节点(信息点) + 边(连接线)
让我用更直观的方式展示你的理解:
🌟 你的理解 vs 技术术语
| 你的说法 | 技术术语 | 简单比喻 |
|---|---|---|
| 节点信息 | 节点属性(Properties) | 人的身份证信息 |
| 边信息 | 关系属性(Relationship Properties) | 两人关系的详情 |
| 节点和边构成图 | 属性图模型 | 人际关系网 |
用现实例子验证你的理解:
📍 社交网络例子:
cypher
-- 节点(人)的信息
CREATE (:人 {
姓名: '张三', -- 节点信息
年龄: 28,
职业: '工程师'
})
-- 边(关系)的信息
CREATE (:人 {姓名: '张三'})
-[:认识 { -- 边信息开始
认识时间: '2020-01-01',
认识地点: '北京',
关系强度: 8
}]-> -- 边信息结束
(:人 {姓名: '李四'})
为什么这个理解很重要?
1. 灵活性极高
cypher
-- 同一种"人"节点,信息可以完全不同
CREATE (:人 {姓名: '张三', 年龄: 28}) -- 有年龄
CREATE (:人 {姓名: '李四', 城市: '北京'}) -- 没年龄,有城市
CREATE (:人 {姓名: '王五'}) -- 只有姓名
-- 同一种"认识"关系,信息也可以不同
CREATE ()-[:认识 {时间: '2020年'}]->() -- 有时间
CREATE ()-[:认识 {方式: '同事介绍'}]->() -- 有方式
CREATE ()-[:认识]->() -- 只有关系,没额外信息
2. 查询就像"看图说话"
cypher
-- "找到所有在北京认识的人"
MATCH (我:人)-[边:认识]->(别人:人)
WHERE 边.认识地点 = '北京'
RETURN 别人.姓名, 边.认识时间
-- 这就像:
-- 1. 找到"我"这个节点
-- 2. 找到从"我"出发的"认识"边
-- 3. 查看这条边的"认识地点"信息
-- 4. 找到边连接的"别人"节点
3. 修改就是更新"信息标签"
cypher
-- 更新节点信息
MATCH (节点:人 {姓名: '张三'})
SET 节点.年龄 = 29 -- 更新节点的身份证信息
SET 节点.已婚 = true
-- 更新边信息
MATCH (张三:人)-[边:认识]->(李四:人)
SET 边.最近联系 = date() -- 更新关系的记录本
SET 边.关系强度 = 边.关系强度 + 1
用这个理解解决实际问题:
场景:电商推荐系统
cypher
-- 1. 节点:用户和商品(都是信息点)
CREATE (:用户 {
用户ID: 'U001',
姓名: '张三',
偏好: ['数码', '运动']
})
CREATE (:商品 {
商品ID: 'P001',
名称: 'iPhone',
类别: '数码',
价格: 6999
})
-- 2. 边:购买关系(连接信息)
CREATE (:用户 {用户ID: 'U001'})
-[:购买 {
时间: '2023-10-01',
金额: 6999,
评分: 5,
评价: '很好用'
}]->
(:商品 {商品ID: 'P001'})
-- 3. 查询:基于图的推荐
-- "找买了数码产品的人还买了什么?"
MATCH (张三:用户 {用户ID: 'U001'})-[:购买]->(数码:商品 {类别: '数码'})
<-[:购买]-(其他用户:用户)
-[:购买]->(推荐商品:商品)
WHERE 推荐商品.类别 IN 张三.偏好
RETURN 推荐商品.名称, count(*) as 推荐度
ORDER BY 推荐度 DESC
几个关键洞察:
🔑 节点 = 实体
- 可以是:人、商品、地点、事件
- 每个节点有自己的"身份证信息"
🔑 边 = 关系
- 连接两个节点
- 有自己的"关系描述信息"
- 有方向:A → B 和 B → A 是不同的
🔑 图的力量
cypher
-- 传统数据库需要多次查询
-- 1. 查用户表
-- 2. 查订单表
-- 3. 查商品表
-- 4. 查评价表
-- Neo4j一次查询搞定
MATCH (用户)-[购买:购买]->(商品)
<-[浏览:浏览]-(用户)
-[搜索:搜索]->(相关)
RETURN 用户, 购买, 商品, 浏览, 搜索, 相关
-- 一次返回所有相关信息!
可视化你的理解:
节点信息 边信息 节点信息
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ 张三 │ │ 认识 │ │ 李四 │
│ 年龄:28 │─────────▶│ 时间:2020年 │─────────▶│ 年龄:25 │
│ 城市:北京 │ │ 地点:咖啡馆 │ │ 城市:上海 │
└─────────────┘ └──────────────────┘ └─────────────┘
↑ ↑ ↑
信息点 连接信息 信息点
最后,记住这个核心公式:
图 = ∑(节点 + 节点信息) + ∑(边 + 边信息)
Neo4j擅长处理:
- 社交网络(谁认识谁)
- 推荐系统(买了A的人也买了B)
- 欺诈检测(异常关系网络)
- 知识图谱(概念之间的关系)
核心特性
一、边的方向:可以是单向或双向
1. 单向边(有向边) - 大部分情况
cypher
-- A → B(A认识B,但B不一定认识A)
CREATE (:人 {名字:'张三'})-[:认识]->(:人 {名字:'李四'})
-- 这意味着:
-- 张三 认识 → 李四 ✓
-- 李四 认识 → 张三 ✗(除非另有创建)
-- 现实例子:
-- 微博关注:我关注你,你不一定关注我
-- 转账:我转钱给你
-- 点赞:我给帖子点赞
2. 双向边(无向边) - 需要明确创建
cypher
-- Neo4j没有真正的"双向边",需要创建两条相反方向的边
CREATE (张三:人 {名字:'张三'}),
(李四:人 {名字:'李四'}),
(张三)-[:朋友]->(李四),
(李四)-[:朋友]->(张三)
-- 或者用双向箭头(实际上是创建两条边)
CREATE (张三)-[:朋友]-(李四) -- 这会在内部创建两条方向相反的边
-- 现实例子:
-- 微信好友:需要双方同意
-- 婚姻关系:双方互为配偶
-- 同事关系:在同一公司工作
3. 方向查询的灵活性
cypher
-- 1. 查询时指定方向
MATCH (张三:人 {名字:'张三'})-->() -- 只找张三指向的
RETURN count(*)
MATCH (张三:人 {名字:'张三'})<--() -- 只找指向张三的
RETURN count(*)
-- 2. 查询时忽略方向
MATCH (张三:人 {名字:'张三'})--() -- 找到所有相连的(不分方向)
RETURN count(*)
-- 3. 查询双向关系(互相的)
MATCH (a:人)-[:朋友]->(b:人),
(b:人)-[:朋友]->(a:人)
RETURN a.名字, b.名字
二、环(Cycles):完全可以存在!
1. 什么是环?
A → B → C → A 形成一个循环
2. 简单环示例
cypher
-- 创建三角形环
CREATE (张三:人 {名字:'张三'}),
(李四:人 {名字:'李四'}),
(王五:人 {名字:'王五'}),
(张三)-[:认识]->(李四),
(李四)-[:认识]->(王五),
(王五)-[:认识]->(张三) -- 形成环!
-- 查询这个环
MATCH path = (a:人)-[:认识*3]->(a) -- 走3步回到自己
RETURN [node in nodes(path) | node.名字] as 环上的人
3. 自环(Self-loop) - 自己连接自己
cypher
-- 节点连接到自身
CREATE (张三:人 {名字:'张三'})
CREATE (张三)-[:自我提醒 {内容:'记得吃药'}]->(张三)
-- 现实例子:
-- 日程提醒:给自己设置提醒
-- 自我评价:对自己的评分
-- 自引用:比如"本文参考了本文"
-- 查询自环
MATCH (n)-[r]->(n) -- 起点和终点是同一个节点
RETURN n.名字, type(r), r.内容
4. 实际中的环
cypher
-- 资金循环(洗钱检测)
CREATE (公司A:公司)-[:转账 {金额:100万}]->(公司B),
(公司B)-[:转账 {金额:100万}]->(公司C),
(公司C)-[:转账 {金额:100万}]->(公司A) -- 钱转了一圈回来了!
-- 家族近亲结婚环
CREATE (爷爷)-[:父亲]->(爸爸),
(爸爸)-[:父亲]->(儿子),
(儿子)-[:婚姻]->(姑姑), -- 假设姑姑是爷爷的女儿
(姑姑)-[:父亲]->(爷爷) -- 形成环!
三、方向与环的组合示例
场景:微博关注网络
cypher
-- 创建用户和关注关系
CREATE (张三:用户 {名字:'张三'}),
(李四:用户 {名字:'李四'}),
(王五:用户 {名字:'王五'}),
(赵六:用户 {名字:'赵六'}),
-- 单向关注
(张三)-[:关注]->(李四), -- 张关注李
(张三)-[:关注]->(王五), -- 张关注王
(李四)-[:关注]->(王五), -- 李关注王
-- 双向关注(互相关注)
(王五)-[:关注]->(张三), -- 王也关注张
-- 环:关注链条回到起点
(王五)-[:关注]->(赵六), -- 王关注赵
(赵六)-[:关注]->(张三) -- 赵关注张,形成环:张→王→赵→张
-- 查询:谁关注我但我没关注TA(单向)
MATCH (我:用户 {名字:'张三'})<-[被关注:关注]-别人
WHERE NOT (我)-[:关注]->(别人)
RETURN 别人.名字 as 粉丝, '单向关注' as 关系类型
-- 查询:互相关注(双向)
MATCH (a:用户)-[:关注]->(b:用户)
WHERE (b)-[:关注]->(a)
RETURN a.名字 as 用户A, b.名字 as 用户B, '互相关注' as 关系类型
-- 查询:发现关注环
MATCH path = (a:用户)-[:关注*3]->(a) -- 3步回到自己
RETURN [node in nodes(path) | node.名字] as 关注环
四、方向的重要性
1. 方向影响查询结果
cypher
-- 准备数据
CREATE (北京:城市)-[:连接 {距离:100}]->(天津),
(天津)-[:连接 {距离:150}]->(上海)
-- 查询1:从北京能到哪?(考虑方向)
MATCH (北京:城市 {名字:'北京'})-[:连接*]->(目的地)
RETURN 目的地.名字 -- 结果:天津、上海
-- 查询2:能到北京的城市?(反向)
MATCH (出发地)-[:连接*]->(北京:城市 {名字:'北京'})
RETURN 出发地.名字 -- 结果:没有!因为路是单向的
2. 方向表示因果关系
cypher
-- 事件链:A导致B,B导致C
CREATE (事件A:事件)-[:导致]->(事件B),
(事件B)-[:导致]->(事件C)
-- 查找根本原因
MATCH (原因)-[:导致*]->(结果:事件 {名字:'事件C'})
RETURN 原因.名字 -- 可以找到事件A是根本原因
-- 如果边没有方向,就分不清因果了!
3. 环的特殊处理
cypher
-- 检测无限循环
MATCH path = (a)-[:引用*]->(a) -- 文档互相引用形成环
RETURN path LIMIT 1
-- 避免查询死循环
-- 设置最大深度
MATCH (a)-[:朋友*1..10]->(b) -- 最多10层,避免无限循环
-- 环在现实中的意义:
-- ✅ 好的环:推荐系统的"看了又看"
-- ❌ 坏的环:死锁、无限递归
五、实际应用场景
场景1:交通网络(单向很重要!)
cypher
-- 单行道系统
CREATE (路口A)-[:单行道 {方向:'东向西'}]->(路口B)
-- 不能从B直接到A,需要绕路
-- 环岛(环形路)
CREATE (入口)-[:进入]->(环岛),
(环岛)-[:出口 {到:'A路口'}]->(路口A),
(环岛)-[:出口 {到:'B路口'}]->(路口B),
(环岛)-[:继续]->(环岛) -- 可以在环岛里转圈!
场景2:工作流审批(有向无环图DAG)
cypher
-- 审批流程不能有环,否则会死循环
CREATE (申请)-[:提交给]->(经理审批),
(经理审批)-[:通过给]->(总监审批),
(总监审批)-[:通过给]->(财务审批),
(财务审批)-[:完成给]->(申请) -- 完成,不是新的审批
-- 检测是否有非法环(审批回到之前的人)
MATCH path = (a:审批)-[:提交给|通过给*]->(a)
RETURN path -- 如果有结果,说明流程设计有问题
场景3:社交网络的"六度空间"
cypher
-- 查找两个人之间的联系路径(可能包含环)
MATCH path = shortestPath(
(我:用户 {名字:'张三'})-[:认识|同事|同学*1..6]-(名人:用户 {名字:'马云'})
)
-- 可能路径:张→李→王→...→马云
-- 这个路径里可能有环(比如通过同一个圈子)
六、重要总结
✅ 边的方向性:
- 默认是单向的:A → B ≠ B → A
- 双向需要两条边:A → B 且 B → A
- 查询时可以忽略方向:A -- B(找所有连接)
- 现实意义:关注、转账、依赖等都有方向
✅ 环的存在性:
- 完全可以有环:A → B → C → A
- 自环也允许:A → A(自己连接自己)
- 环的用途:循环依赖、环形流程、社交圈子
- 需要注意:查询时要避免无限循环
⚠️ 使用建议:
cypher
-- 1. 明确边的方向意义
CREATE ()-[:转账 {from: A, to: B}]->() -- 明确谁转给谁
-- 2. 环检测查询
MATCH path = ()-[:依赖*]->()
WHERE length(path) > 10 -- 防止太长的环
RETURN path
-- 3. 双向关系的处理
-- 如果经常需要查询"互相"关系,考虑:
CREATE ()-[:好友 {双向: true}]->() -- 用属性标记
📊 可视化理解:
单向链: 双向关系: 环:
A → B → C A ↔ B A → B
↖ ↓
C ← D
自环: 复杂环:
↻ A → B → C
A ↑ ↓
D ← E ← F
记住:Neo4j的灵活性让你可以自由地:
- 创建单向或双向的关系
- 构建复杂的环状结构
- 根据业务需求设计图模式
这就是图数据库的强大之处!它更贴近真实世界的关系网络。🌐
Neo4j 索引详解 - 从入门到实战
一、索引的核心作用:加速查询
cypher
-- 没有索引:Neo4j要扫描所有节点
MATCH (p:Person) WHERE p.name = '张三' -- 慢!要查所有人
-- 有索引:Neo4j直接跳到目标位置
MATCH (p:Person) WHERE p.name = '张三' -- 快!用索引查找
二、索引类型速览
| 索引类型 | 用途 | 创建命令 |
|---|---|---|
| 单属性索引 | 加速单个属性查询 | CREATE INDEX FOR (n:Label) ON (n.property) |
| 复合索引 | 加速多属性组合查询 | CREATE INDEX FOR (n:Label) ON (n.p1, n.p2) |
| 全文索引 | 文本模糊搜索 | CREATE FULLTEXT INDEX ... |
| 文本索引 | 字符串前缀匹配 | CREATE TEXT INDEX ... |
三、实战:一步一步创建索引
1. 准备工作:创建测试数据
cypher
-- 先创建一些数据(没有索引)
CREATE (:Person {name: '张三', age: 25, city: '北京'}),
(:Person {name: '李四', age: 30, city: '上海'}),
(:Person {name: '王五', age: 28, city: '广州'}),
(:Person {name: '赵六', age: 35, city: '北京'}),
(:Person {name: '钱七', age: 40, city: '上海'})
-- 创建产品数据
CREATE (:Product {sku: 'P001', name: 'iPhone 15', price: 6999}),
(:Product {sku: 'P002', name: '华为Mate 60', price: 5999}),
(:Product {sku: 'P003', name: '小米13', price: 3999})
2. 第一步:创建单属性索引(最常用)
cypher
-- 为Person的name属性创建索引
CREATE INDEX person_name_index FOR (p:Person) ON (p.name)
-- 为Person的age属性创建索引
CREATE INDEX person_age_index FOR (p:Person) ON (p.age)
-- 为Product的sku创建索引
CREATE INDEX product_sku_index FOR (p:Product) ON (p.sku)
-- 查看创建进度
CALL db.awaitIndexes() -- 等待索引创建完成
3. 第二步:创建复合索引(多个属性)
cypher
-- 当经常同时按city和age查询时
CREATE INDEX person_city_age_index FOR (p:Person) ON (p.city, p.age)
-- 复合索引适用于这样的查询:
MATCH (p:Person)
WHERE p.city = '北京' AND p.age > 30 -- 两个条件都用上索引
RETURN p
-- 但不适用于:
MATCH (p:Person)
WHERE p.city = '北京' -- 只有city能用索引
RETURN p
MATCH (p:Person)
WHERE p.age > 30 -- 只有age不能用这个复合索引!
RETURN p
4. 第三步:创建文本索引(字符串搜索)
cypher
-- 创建文本索引(Neo4j 5.x+)
CREATE TEXT INDEX product_name_text_index FOR (p:Product) ON (p.name)
-- 支持前缀匹配查询(比普通索引快)
MATCH (p:Product)
WHERE p.name STARTS WITH 'iPh' -- 查找以'iPh'开头的
RETURN p
-- 普通索引不支持STARTS WITH,但文本索引支持!
5. 第四步:创建全文索引(模糊搜索)
cypher
-- 全文索引可以跨多个标签和属性
CREATE FULLTEXT INDEX product_titles_and_descriptions
FOR (n:Product|Book) -- 可以多个标签
ON EACH [n.name, n.description, n.title] -- 可以多个属性
-- 使用全文搜索
CALL db.index.fulltext.queryNodes(
'product_titles_and_descriptions',
'苹果手机'
) YIELD node, score
RETURN node.name, node.price, score
ORDER BY score DESC
-- 支持模糊匹配:'appel'也能找到'apple'
四、索引的最佳实践
1. 什么时候应该创建索引?
cypher
-- ✅ 情况1:经常用于WHERE条件的属性
-- 如果经常这样查:
MATCH (u:User) WHERE u.email = 'xxx@yyy.com' -- email应该建索引
-- ✅ 情况2:经常用于JOIN的属性
MATCH (u:User)-[:OWNS]->(o:Order)
WHERE u.user_id = '123' -- user_id应该建索引
-- ✅ 情况3:唯一性约束会自动创建索引
CREATE CONSTRAINT FOR (u:User) REQUIRE u.user_id IS UNIQUE
-- 自动为user_id创建索引!
-- ❌ 情况4:很少查询的属性不要建索引
-- MATCH (p:Person) WHERE p.hobby = '游泳' -- 如果不经常查,别建索引
-- ❌ 情况5:值种类太少的属性(如性别:男/女)
-- 建索引反而可能更慢
2. 索引的代价
cypher
-- 索引不是免费的!
-- 1. 占用磁盘空间
-- 2. 降低写入速度(每次增删改都要更新索引)
-- 3. 增加内存使用
-- 查看索引大小
CALL db.indexes() YIELD name, type, labelsOrTypes, properties, totalSize
RETURN name, type, labelsOrTypes, properties, totalSize
3. 索引命名规范
cypher
-- 好名字:一看就懂
CREATE INDEX idx_person_name FOR (p:Person) ON (p.name)
CREATE INDEX idx_user_email_for_login FOR (u:User) ON (u.email)
CREATE INDEX idx_product_sku_unique FOR (p:Product) ON (p.sku)
-- 按模式命名
CREATE INDEX idx_标签_属性_用途 FOR (n:Label) ON (n.property)
五、如何查看和管理索引
1. 查看所有索引
cypher
-- 查看已创建的索引
CALL db.indexes()
-- 查看更详细信息
SHOW INDEXES
-- 查看特定标签的索引
SHOW INDEXES FOR (n:Person)
-- 查看索引使用统计
CALL db.index.usageStats() -- 哪些索引被实际使用了
2. 测试索引效果
cypher
-- 在查询前加EXPLAIN查看执行计划
EXPLAIN
MATCH (p:Person) WHERE p.name = '张三'
RETURN p
-- 结果会显示是否使用了索引
-- 如果看到"NodeIndexSeek",说明用了索引
-- 如果看到"NodeByLabelScan",说明没索引,全表扫描
-- 用PROFILE查看实际执行情况
PROFILE
MATCH (p:Person) WHERE p.name = '张三'
RETURN p
3. 删除不需要的索引
cypher
-- 删除索引
DROP INDEX person_name_index
-- 安全删除(如果存在才删除)
DROP INDEX person_name_index IF EXISTS
-- 删除约束时,关联的索引也会自动删除
DROP CONSTRAINT constraint_name
六、实战案例:电商系统索引设计
cypher
-- 电商系统推荐索引配置
-- 1. 用户表:登录和主键索引
CREATE CONSTRAINT user_id_unique FOR (u:User) REQUIRE u.user_id IS UNIQUE
CREATE INDEX user_email_index FOR (u:User) ON (u.email) -- 登录用
CREATE INDEX user_phone_index FOR (u:User) ON (u.phone) -- 登录用
CREATE INDEX user_created_at_index FOR (u:User) ON (u.created_at) -- 按时间查询
-- 2. 商品表:搜索和分类索引
CREATE CONSTRAINT product_id_unique FOR (p:Product) REQUIRE p.product_id IS UNIQUE
CREATE TEXT INDEX product_name_index FOR (p:Product) ON (p.name) -- 名称搜索
CREATE INDEX product_category_index FOR (p:Product) ON (p.category_id)
CREATE INDEX product_price_index FOR (p:Product) ON (p.price) -- 价格范围查询
CREATE INDEX product_status_index FOR (p:Product) ON (p.status) -- 上架/下架
-- 3. 订单表:用户和时间索引
CREATE CONSTRAINT order_no_unique FOR (o:Order) REQUIRE o.order_no IS UNIQUE
CREATE INDEX order_user_id_index FOR (o:Order) ON (o.user_id) -- 查用户订单
CREATE INDEX order_status_index FOR (o:Order) ON (o.status) -- 按状态查询
CREATE INDEX order_created_at_index FOR (o:Order) ON (o.created_at) -- 时间范围
-- 4. 全文索引:商品搜索
CREATE FULLTEXT INDEX product_search_index
FOR (p:Product)
ON EACH [p.name, p.description, p.brand, p.tags]
-- 使用全文索引搜索
CALL db.index.fulltext.queryNodes('product_search_index', '苹果 手机 256GB')
YIELD node, score
WHERE node.price < 8000 AND node.stock > 0
RETURN node.name, node.price, score
ORDER BY score DESC
LIMIT 20
七、常见问题解答
Q1:索引创建后立即生效吗?
cypher
-- 索引创建是异步的,需要等待
CREATE INDEX idx_name FOR (p:Person) ON (p.name)
-- 等待索引创建完成
CALL db.awaitIndexes()
-- 或者查看状态
CALL db.indexes() YIELD name, state
WHERE name = 'idx_name'
RETURN name, state -- 状态应为'ONLINE'
Q2:如何知道应该给哪些属性建索引?
cypher
-- 方法1:分析查询日志
CALL dbms.queryJit() -- 查看慢查询
-- 方法2:使用性能监控
CALL db.stats.retrieve('QUERIES') -- 查询统计
-- 方法3:经验法则:
-- 1. WHERE条件中经常出现的属性
-- 2. JOIN操作中使用的属性
-- 3. ORDER BY中使用的属性
-- 4. 返回大量数据的过滤条件
Q3:索引会影响写入性能吗?
cypher
-- 会的!每次增删改都要更新索引
-- 写入速度:无索引 > 有少量索引 > 有很多索引
-- 解决方法:
-- 1. 批量写入时,可以先删除索引,写入完再重建
DROP INDEX idx_name
-- 批量导入数据
LOAD CSV FROM 'file:///data.csv' AS row
CREATE (:Person {name: row[0], age: toInteger(row[1])})
-- 重建索引
CREATE INDEX idx_name FOR (p:Person) ON (p.name)
Q4:可以为关系创建索引吗?
cypher
-- 可以直接为关系属性创建索引(Neo4j 4.0+)
CREATE INDEX rel_created_at_index FOR ()-[r:FOLLOWS]-() ON (r.created_at)
-- 查询时使用
MATCH ()-[r:FOLLOWS]->()
WHERE r.created_at > date('2023-01-01')
RETURN count(r)
八、索引检查清单
cypher
-- 创建索引前问自己:
-- 1. 这个属性经常出现在WHERE条件中吗? ✅
-- 2. 这个查询执行慢吗?(用PROFILE检查) ✅
-- 3. 数据量大吗?(小数据不需要索引) ✅
-- 4. 属性值的多样性高吗?(男/女这种不要建) ✅
-- 5. 写入频率高吗?(高写入要谨慎) ✅
-- 创建索引后:
-- 1. 等待索引构建完成:CALL db.awaitIndexes()
-- 2. 测试查询速度:对比前后的PROFILE结果
-- 3. 监控索引使用:CALL db.index.usageStats()
-- 4. 定期清理无用索引
九、快速参考命令
cypher
-- 1. 创建索引
CREATE INDEX 索引名 FOR (n:标签) ON (n.属性)
CREATE INDEX 索引名 FOR (n:标签) ON (n.属性1, n.属性2) -- 复合索引
-- 2. 查看索引
SHOW INDEXES
CALL db.indexes()
-- 3. 删除索引
DROP INDEX 索引名
DROP INDEX 索引名 IF EXISTS
-- 4. 检查索引使用
EXPLAIN MATCH ... -- 查看执行计划
PROFILE MATCH ... -- 查看性能
-- 5. 等待索引
CALL db.awaitIndexes()
记住:索引就像书的目录,没有目录找内容慢,但目录本身也占空间,而且书更新了目录也要更新!📚
Neo4j 核心概念全总结 🎯
一、最核心的 3 个概念(必须记住!)
Neo4j 图数据库 = 节点 + 关系 + 属性
1. 节点(Node) - 图的"点"
- 是什么:实体、对象、事物
- 比如:人、商品、地点、事件
- 可以有:标签(分类)、属性(信息)
2. 关系(Relationship) - 图的"边"
- 是什么:连接两个节点的线
- 特点:必须有方向、必须有类型、可以有属性
- 比如:认识、购买、位于、属于
3. 属性(Property) - 节点和关系的"详细信息"
- 是什么:键值对信息
- 存储位置:节点和关系都可以有属性
- 比如:姓名、年龄、时间、金额
二、5 大关键特性
1. 标签(Labels) - 节点的分类
cypher
-- 就像给节点贴标签
CREATE (:Person) -- "人"标签
CREATE (:Product) -- "产品"标签
CREATE (:Person:VIP) -- 可以有多个标签
- 作用:快速分类和查询
- 一个节点可以有多个标签
2. 关系类型(Relationship Type) - 关系的分类
cypher
CREATE ()-[:KNOWS]->() -- "认识"关系
CREATE ()-[:BOUGHT]->() -- "购买"关系
CREATE ()-[:LIVES_IN]->() -- "居住"关系
- 每个关系必须有一个类型
- 类型名通常用大写(约定)
3. 图遍历(Traversal) - 沿着关系查找
cypher
-- 找到朋友的朋友
MATCH (我)-[:FRIEND]->(朋友)-[:FRIEND]->(朋友的朋友)
RETURN 朋友的朋友
-- 多层关系查询
MATCH (我)-[:FRIEND*1..3]->(陌生人)
- 可以沿着关系"走"到其他节点
- 支持深度查询
4. 无固定模式(Schema-less)
cypher
-- 不需要预先定义结构!
CREATE (:Person {name: '张三'}) -- 只有名字
CREATE (:Person {age: 25, city: '北京'}) -- 不同属性
CREATE (:Person {height: 180}) -- 新增属性
- 随时添加新属性
- 同一标签的节点可以有不同属性
5. Cypher 查询语言 - 图的 SQL
cypher
-- 像说英语一样查询
MATCH (p:Person)-[:LIVES_IN]->(c:City)
WHERE p.age > 25
RETURN p.name, c.name
- 专门为图设计的查询语言
- 直观易读
三、与关系数据库对比
| 概念 | 关系数据库 (MySQL) | Neo4j | 比喻 |
|---|---|---|---|
| 数据结构 | 表 (Table) | 图 (Graph) | 表格 vs 网络 |
| 数据单元 | 行 (Row) | 节点 (Node) | 一行数据 vs 一个点 |
| 连接方式 | 外键 (Foreign Key) | 关系 (Relationship) | 数字引用 vs 直接连线 |
| 查询重点 | JOIN 操作 | 关系遍历 | 查表连接 vs 沿着线走 |
| 灵活度 | 固定表结构 | 动态属性 | 严格表格 vs 灵活标签 |
四、核心优势(为什么用 Neo4j?)
1. 关系查询极快
cypher
-- 传统SQL:需要多次JOIN
SELECT * FROM users u
JOIN friends f1 ON u.id = f1.user_id
JOIN friends f2 ON f1.friend_id = f2.user_id
-- 表越大越慢!
-- Neo4j:直接沿着关系走
MATCH (u:User)-[:FRIEND]->(f1)-[:FRIEND]->(f2)
RETURN f2
-- 速度几乎不受数据量影响
2. 最接近现实世界
现实世界:
张三 --认识--> 李四 --同事--> 王五
| |
购买 居住
↓ ↓
iPhone 北京
Neo4j完美映射:
(:Person {name:'张三'})-[:KNOWS]->(:Person {name:'李四'})
|
等等...
3. 适合的场景
- ✅ 社交网络:朋友关系、关注关系
- ✅ 推荐系统:买了A的人也买了B
- ✅ 知识图谱:概念之间的关系
- ✅ 欺诈检测:异常关系网络
- ✅ 供应链:产品流转路径
- ❌ 不适合:大量数值计算、简单CRUD
五、数据模型三层次
第1层:物理存储层
- 节点存储文件
- 关系存储文件
- 属性存储文件
- 用户看不见,但影响性能
第2层:逻辑模型层(你操作的部分)
节点 --关系--> 节点
↓ ↓
属性 属性
第3层:业务模型层(你的应用)
用户 --购买--> 商品
↓ ↓
地址 类别
六、必须掌握的 7 个 Cypher 操作
1. CREATE - 创建
cypher
CREATE (:Person {name: '张三', age: 25})
CREATE (a)-[:KNOWS {since: 2020}]->(b)
2. MATCH - 查找
cypher
MATCH (p:Person) RETURN p
MATCH (p:Person {name: '张三'}) RETURN p.age
3. WHERE - 过滤
cypher
MATCH (p:Person) WHERE p.age > 20 RETURN p
4. SET - 修改/添加属性
cypher
MATCH (p:Person {name: '张三'}) SET p.city = '北京'
5. DELETE - 删除
cypher
MATCH (p:Person {name: '张三'}) DELETE p
-- 注意:有关系的节点要先删关系!
6. REMOVE - 删除属性/标签
cypher
MATCH (p:Person {name: '张三'}) REMOVE p.age
7. RETURN - 返回结果
cypher
MATCH (p:Person) RETURN p.name, p.age ORDER BY p.age DESC
七、高级概念摘要
1. 索引和约束
cypher
-- 加速查询
CREATE INDEX FOR (p:Person) ON (p.name)
-- 保证数据唯一性
CREATE CONSTRAINT FOR (p:Person) REQUIRE p.id IS UNIQUE
2. 路径(Path)
cypher
-- 节点和关系的序列
MATCH path = (a)-[:KNOWS*]->(b)
RETURN path, length(path)
3. 模式(Pattern)
cypher
-- 描述图的结构
(a:Person)-[:WORKS_FOR]->(c:Company)<-[:WORKS_FOR]-(b:Person)
4. 变量(Variable)
cypher
-- 给节点、关系、路径起别名
MATCH (p:Person) -- p 是变量
WHERE p.age > 30
RETURN p
八、一句话记住 Neo4j
"用节点表示事物,用关系表示联系,两者都可以有详细信息,用 Cypher 语言像画画一样查询数据。"
九、学习路径建议
第1步:理解节点+关系+属性(✓ 已掌握)
第2步:学会 CREATE、MATCH、RETURN
第3步:掌握 WHERE、SET、DELETE
第4步:学习关系遍历和路径查询
第5步:了解索引和约束
第6步:实战项目练习
十、快速参考卡片
| 做什么 | Cypher 命令 | 例子 |
|---|---|---|
| 创建节点 | CREATE (n:Label {prop:value}) |
CREATE (:Person {name:'张三'}) |
| 查找节点 | MATCH (n:Label) RETURN n |
MATCH (p:Person) RETURN p |
| 条件查找 | MATCH (n:Label) WHERE ... |
MATCH (p:Person) WHERE p.age>20 |
| 创建关系 | CREATE (a)-[:TYPE]->(b) |
CREATE (a)-[:KNOWS]->(b) |
| 查找关系 | MATCH (a)-[r:TYPE]->(b) |
MATCH ()-[r:KNOWS]->() |
| 修改属性 | MATCH (n) SET n.prop=value |
SET p.age=30 |
| 删除节点 | MATCH (n) DELETE n |
DELETE p |
| 删除关系 | MATCH ()-[r]->() DELETE r |
DELETE r |