在 Cypher 中,深度查询的核心是「可变长度关系语法」,用于匹配节点间多步(多深度)的关联关系。它的核心格式、用法场景、常见问题及最佳实践如下,结合之前的示例系统化梳理:
匹配 n 到 m 步的关系,语法格式为:
()-[:关系类型*最小深度..最大深度]->()
- 深度边界:
*1..2:匹配 1 到 2 度关系(直接关联 + 间接关联 1 次)
*2:等价于 *2..2,仅匹配 2 度关系(精确深度)
*1..:匹配 1 度及以上(无最大深度,谨慎使用)
*:等价于 *0..∞(0 度 = 节点本身,无上限,极易性能爆炸)
- 关系方向:
->:仅匹配「从左到右」的单向关系
<-:仅匹配「从右到左」的单向关系
- 无箭头
()-[]-():匹配双向关系(如朋友、同事等无明确方向的关联)
- 关系类型:
- 单一类型:
[:FRIENDS_WITH*1..2](仅朋友关系)
- 多类型:
[:FRIENDS_WITH|COLLEAGUE*1..2](朋友或同事关系,用 | 分隔)
基于你之前的用户 - 商品图模型,结合实际需求举例:
查询「张三的 2 度朋友」(朋友的朋友,不包含直接朋友):
MATCH (zhangsan:User {name:"张三"})-[:FRIENDS_WITH*2]-(friend:User)
WHERE friend <> zhangsan // 排除自己
RETURN DISTINCT friend.name AS 2度朋友;
查询「张三的 1-3 度朋友」(直接朋友 + 朋友的朋友 + 朋友的朋友的朋友):
MATCH (zhangsan:User {name:"张三"})-[:FRIENDS_WITH*1..3]-(friend:User)
WHERE friend <> zhangsan
WITH friend, shortestPath((zhangsan)-[:FRIENDS_WITH*]-(friend)) AS sp
RETURN friend.name AS 朋友, length(sp) AS 关系度数
ORDER BY 关系度数;
查询「张三的 1-2 度关联(朋友或购买过同商品的人)」:
// 逻辑:张三 → 朋友(1度),或 张三→购买商品→其他人(2度)
MATCH (zhangsan:User {name:"张三"})-[:FRIENDS_WITH|PURCHASED*1..2]-(related:User)
WHERE related <> zhangsan
RETURN DISTINCT related.name AS 关联用户;
查询「张三 2020 年后添加的 1-2 度朋友」(过滤关系属性 since):
MATCH (zhangsan:User {name:"张三"})-[r:FRIENDS_WITH*1..2]-(friend:User)
WHERE friend <> zhangsan
AND all(rel IN r WHERE rel.since >= 2020) // 所有路径中的关系都满足2020年后
RETURN friend.name AS 朋友, [rel.since IN r] AS 路径中关系的添加时间;
- 用
length(路径):获取单条路径的长度(即度数)
- 用
shortestPath():避免多路径导致的度数计算错误(之前报错的核心修复)
MATCH (a:User {name:"张三"}), (b:User)
MATCH p = shortestPath((a)-[:FRIENDS_WITH*1..3]-(b)) // 最短路径确保度数准确
WHERE a <> b
RETURN b.name AS 朋友, length(p) AS 度数;
多深度查询可能通过多条路径匹配到同一节点,用 DISTINCT 去重:
MATCH (zhangsan:User {name:"张三"})-[:FRIENDS_WITH*1..2]-(friend:User)
WHERE friend <> zhangsan
RETURN DISTINCT friend.id, friend.name; // 去重同一朋友
无最大深度的查询(如 *1..)可能遍历全图,用 LIMIT 限制结果:
MATCH (zhangsan:User {name:"张三"})-[:FRIENDS_WITH*1..]-(friend:User)
WHERE friend <> zhangsan
RETURN DISTINCT friend.name LIMIT 10; // 最多返回10个朋友
用 all()/any() 过滤路径中所有 / 任意节点 / 关系是否满足条件:
// 查询张三的1-2度朋友,且路径中所有朋友年龄≥25
MATCH (zhangsan:User {name:"张三"})-[r:FRIENDS_WITH*1..2]-(friend:User)
WHERE friend <> zhangsan
AND all(node IN nodes(r) WHERE node.age >= 25) // nodes(r) 获取路径中所有节点
RETURN friend.name;
- 错误写法:
length((a)-[:FRIENDS_WITH*]-(b))
原因:* 无边界,返回多条路径(List<Path>),length() 仅接收单条 Path
- 修复:用
shortestPath() 取单条路径,或用 WITH 处理路径列表
- 错误写法:
MATCH (a)-[:FRIENDS_WITH*]-(b)
风险:遍历全图所有路径,数据量大时直接超时
- 避坑:必须指定最大深度(如
*1..3),根据业务场景限制深度(一般不超过 5)
- 错误:
MATCH (a)-[:FRIENDS_WITH*0..2]-(b)
问题:*0 会匹配 a 本身(0 度关系)
- 避坑:要么深度从 1 开始(
*1..2),要么用 WHERE a <> b 排除自身
- 明确深度边界:始终指定最大深度(如
*1..3),避免无上限遍历
- 关系方向按需选择:双向关系用无箭头(
()-[]-()),单向关系用箭头(->)
- 计算度数用最短路径:
shortestPath() 确保度数准确,避免多路径干扰
- 必去重 + 排重:用
DISTINCT 去重重复节点,ORDER BY 优化结果展示
- 过滤路径属性:用
all()/any() 筛选符合条件的路径,减少无效结果
通过以上语法和技巧,可灵活实现 1 度、多度关联查询,适配社交关系、推荐系统、知识图谱等场景的深度遍历需求。