1. 什么是模式匹配 #
1.1 基础概念 #
模式匹配是 Cypher 的核心功能。它让你能够用类似"画图"的方式来描述你想要查找的数据结构,然后数据库会自动找到所有匹配的数据。
1.2 什么是模式? #
模式(Pattern)就像是一个"模板"或"模具",用来描述图的结构。想象一下:
- 如果你想要找"朋友",模式就是:
(人)-[:朋友]->(朋友) - 如果你想要找"朋友的朋友",模式就是:
(人)-[:朋友]->(朋友)-[:朋友]->(朋友的朋友)
模式的作用:
- 描述你想要查找的图结构
- 让数据库知道"什么样的数据是你想要的"
- 可以很简单,也可以很复杂
1.3 为什么需要模式匹配? #
在传统数据库中,查找数据需要写复杂的 SQL 查询。但在图数据库中,模式匹配让你能够:
- 直观描述:用接近自然语言的方式描述关系
- 高效查询:数据库自动优化查询路径
- 灵活匹配:可以匹配任意复杂的图结构
1.4 模式的组成 #
一个模式由以下部分组成:
- 节点:用圆括号
()表示 - 关系:用方括号和箭头
-[]->表示 - 变量:用来引用节点和关系
- 标签和属性:用来过滤和匹配
简单示例:
(人)-[:朋友]->(朋友)这个模式表示"一个人通过朋友关系连接到另一个朋友"。
2. 节点语法详解 #
2.1 节点语法的组成部分 #
一个完整的节点语法包含三个可选部分:
- 变量名:用来引用这个节点
- 标签:节点的类型
- 属性:节点的数据
基本格式:
(变量名:标签 {属性})2.2 节点语法示例 #
2.2.1 匿名节点:() #
最简单的节点,没有变量、标签或属性。
使用场景:
- 不关心节点的具体信息
- 只关心关系或模式结构
- 在查询中作为占位符
示例:
MATCH ()-[r:ACTED_IN]->(m:Movie)
RETURN m这个查询表示"查找任意节点通过 ACTED_IN 关系连接到电影",不关心起始节点是什么。
2.2.2 带变量的节点:(kungfu) #
给节点一个变量名,可以在查询的其他地方引用它。
特点:
- 变量名通常使用小写字母
- 可以是单个字母(如
m)或单词(如movie) - 变量只在当前查询中有效
示例:
MATCH (kungfu)
RETURN kungfu2.2.3 带标签的节点:(:Movie) #
标签用来分类节点,类似于数据库中的"表"。
示例:
(:Person) // Person 类型的节点
(:Movie) // Movie 类型的节点
(:Company) // Company 类型的节点2.2.4 带属性和标签的节点:(kungfu:Movie {title: '功夫'}) #
完整的节点语法,包含变量、标签和属性。
示例:
(kungfu:Movie {title: '功夫', released: 2004})2.3 节点语法实践 #
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建一个空节点
CREATE ()
// 创建一个带有标签 Actor 的节点
CREATE (:Actor)
// 创建一个带变量 a 且有标签 Actor 的节点
CREATE (a:Actor)
// 创建一个 Actor 类型的节点,并带有 name 和 born 属性
CREATE (:Actor {name: '吴孟达', born: 1952})
// 创建一个带变量 kungfu、有标签 Movie、有 title 和 released 属性的节点
CREATE (kungfu:Movie {title: '功夫', released: 2004})
// 创建一个带变量 xingye,有 Person 和 Actor 标签,并带有 name 和 born 属性的节点
CREATE (xingye:Person:Actor {name: '周星驰', born: 1962})
// 查询所有 Actor 类型的节点并返回
MATCH (a:Actor) RETURN a
// 查询名字为"吴孟达"的 Actor 类型节点
MATCH (a:Actor {name: '吴孟达'}) RETURN a
// 查询即为 Person 又为 Actor 的节点,返回其 name 和 born 属性
MATCH (a:Person:Actor) RETURN a.name AS name, a.born AS born2.4 数据 #
2.4.1 功夫 (2004) #
| 演员 | 饰演角色 | 备注 |
|---|---|---|
| 周星驰 | 阿星 | 主角,想加入斧头帮的小混混 |
| 元华 | 包租公 | 猪笼城寨房东,隐藏高手 |
| 元秋 | 包租婆 | 猪笼城寨房东娘子,狮吼功传人 |
| 黄圣依 | 芳 | 哑女,阿星的童年初恋 |
2.4.2 大话西游 (1995) #
| 演员 | 饰演角色 | 备注 |
|---|---|---|
| 周星驰 | 至尊宝 | 主角,孙悟空转世 |
| 朱茵 | 紫霞仙子 | 女主角,至尊宝的挚爱 |
| 吴孟达 | 猪八戒 | 至尊宝的好兄弟 |
| 莫文蔚 | 白晶晶 | 白骨精,至尊宝的前任 |
2.4.3 少林足球 (2001) #
| 演员 | 饰演角色 | 备注 |
|---|---|---|
| 周星驰 | 五师兄/星 | 主角,少林弟子 |
| 吴孟达 | 黄金右脚 | 落魄球探,组建球队 |
| 赵薇 | 阿梅 | 太极拳传人,馒头店老板 |
3. 关系语法详解 #
3.1 关系语法的组成部分 #
一个完整的关系语法包含:
- 变量名(可选):用来引用关系
- 关系类型(可选):关系的种类
- 属性(可选):关系的附加数据
- 方向(必需):
->或<-或-(无向)
基本格式:
-[变量名:关系类型 {属性}]->3.2 关系语法示例 #
3.2.1 最简单的关系:-[]-> #
只有方向,没有变量、类型或属性。
使用场景:
- 不关心关系的具体信息
- 只关心两个节点之间是否有关系
示例:
MATCH (p:Person)-[]->(m:Movie)
RETURN p, m3.2.2 带类型的关系:-[:ACTED_IN]-> #
指定关系类型,但不使用变量。
使用场景:
- 只关心特定类型的关系
- 不需要访问关系的属性
示例:
// 匹配所有标签为 Person 的节点与标签为 Movie 的节点,
// 且它们之间存在类型为 ACTED_IN 的关系(p 演过 m)
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
// 返回匹配到的 Person 节点和 Movie 节点
RETURN p, m3.2.3 带变量的关系:-[r:ACTED_IN]-> #
给关系一个变量名,可以在查询中使用。
使用场景:
- 需要访问关系的属性
- 需要在 WHERE 子句中过滤关系
- 需要在 RETURN 中返回关系信息
示例:
// 匹配标签为 Person 的节点 p 与标签为 Movie 的节点 m,二者之间有 ACTED_IN 类型的关系 r
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
// 返回演员姓名、电影标题和出演角色信息
RETURN p.name, m.title, r.roles3.2.4 完整的关系语法:-[r:ACTED_IN {roles: ['至尊宝']}]-> #
包含变量、类型和属性。
示例:
// 匹配标签为 Actor 的节点 a 与标签为 Movie 的节点 m,二者之间有 ACTED_IN 类型的关系 r,且 r 的属性 roles 包含 '至尊宝'
MATCH (a:Actor)-[r:ACTED_IN {roles: ['至尊宝']}]->(m:Movie)
// 返回匹配到的 Actor 节点 a、关系 r 和 Movie 节点 m
RETURN a, r, m3.3 关系语法实践 #
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建演员和电影节点
CREATE (zxc:Actor {name: '周星驰', born: 1962}),
(wmd:Actor {name: '吴孟达', born: 1952}),
(kungfu:Movie {title: '功夫', released: 2004}),
(erta:Movie {title: '大话西游', released: 1995})
// 创建带有类型和属性的完整关系
MATCH (a:Actor {name: '周星驰'}),
(m:Movie {title: '功夫'})
CREATE (a)-[:ACTED_IN {roles: ['阿星']}]->(m)
// 创建 ACTED_IN 类型的关系,表示周星驰出演大话西游
MATCH (a:Actor {name: '周星驰'}),
(m:Movie {title: '大话西游'})
CREATE (a)-[:ACTED_IN]->(m)
// 创建带变量的 ACTED_IN 关系,变量名为 r
MATCH (a:Actor {name: '吴孟达'}),
(m:Movie {title: '大话西游'})
CREATE (a)-[r:ACTED_IN]->(m)
// 创建带属性的 ACTED_IN 关系(角色为"猪八戒"、年份为1995),变量名为 r
MATCH (a:Actor {name: '吴孟达'}),
(m:Movie {title: '大话西游'})
CREATE (a)-[r:ACTED_IN {roles: ['猪八戒'], year: 1995}]->(m)
// 匹配所有 Actor 节点与所有 Movie 节点间的任意关系,返回对应的演员名和电影名
MATCH (a:Actor)-[]->(m:Movie)
RETURN a.name AS actor, m.title AS movie
// 匹配所有 Actor 节点与 Movie 节点之间的 ACTED_IN 关系,返回演员名与电影名
MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
RETURN a.name AS actor, m.title AS movie4. 模式语法详解 #
4.1 什么是模式语法? #
模式语法是节点和关系语法的组合,用来描述完整的图结构。模式是 Cypher 的核心,让你能够描述"想要查找什么样的图"。
4.2 简单模式示例 #
最简单的模式包含一个关系,连接两个节点:
CREATE (xingye:Person:Actor {name: '周星驰', born: 1962})-[role:ACTED_IN {roles: ['至尊宝']}]->(erta:Movie {title: '大话西游', released: 1995});这个模式表示:
- 一个名为周星驰的 Person/Actor 节点
- 通过 ACTED_IN 关系(角色是至尊宝)
- 连接到一个名为《大话西游》的 Movie 节点
4.3 复杂模式示例 #
4.3.1 多跳关系模式 #
// 匹配一个Person节点p1,通过IS_FRIENDS_WITH关系,连接到Person节点p2,再通过IS_FRIENDS_WITH关系连接到Person节点p3
MATCH (p1:Person)-[:IS_FRIENDS_WITH]->(p2:Person)-[:IS_FRIENDS_WITH]->(p3:Person)
RETURN p1,p2,p3这个模式表示"朋友的朋友"(2跳关系)。
4.3.2 多关系模式 #
// 匹配一个 Person 节点 p,通过 ACTED_IN 关系指向 Movie 节点 m
// 同时,该 Movie 节点 m 被另一个 Person 节点 d 通过 DIRECTED 关系指向
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(d:Person)
RETURN p,m,d这个模式表示"演员出演电影,且该电影被某个导演执导"。
4.3.3 可变长度模式 #
// 匹配一个 Person 节点,经过 1 到 3 跳的任意关系,连接到任意节点 connected
MATCH (p:Person)-[*1..3]-(connected)
RETURN p这个模式表示"1到3跳的任意关系"。
4.4 模式语法实践 #
// 清空数据库
MATCH (n) DETACH DELETE n;
// 创建演员和电影节点(周星驰电影宇宙)
CREATE (zxc:Person:Actor:Director {name: '周星驰', born: 1962}),
(wmd:Person:Actor {name: '吴孟达', born: 1952}),
(zy:Person:Actor {name: '朱茵', born: 1971}),
(kungfu:Movie {title: '功夫', released: 2004}),
(erta:Movie {title: '大话西游', released: 1995}),
(shaolin:Movie {title: '少林足球', released: 2001});
// 创建 周星驰 和 功夫 之间的出演关系
MATCH (zxc:Person {name: '周星驰'}),
(kungfu:Movie {title: '功夫'})
CREATE (zxc)-[:ACTED_IN {roles: ['阿星']}]->(kungfu);
// 创建 周星驰 和 大话西游 之间的出演关系
MATCH (zxc:Person {name: '周星驰'}),
(erta:Movie {title: '大话西游'})
CREATE (zxc)-[:ACTED_IN {roles: ['至尊宝']}]->(erta);
// 创建 朱茵 和 大话西游 之间的出演关系
MATCH (zy:Person {name: '朱茵'}),
(erta:Movie {title: '大话西游'})
CREATE (zy)-[:ACTED_IN {roles: ['紫霞仙子']}]->(erta);
// 演示:创建带年份属性的 ACTED_IN 关系
// 这里为吴孟达与少林足球添加更详细的关系属性
MATCH (wmd:Person {name: '吴孟达'}),
(shaolin:Movie {title: '少林足球'})
CREATE (wmd)-[:ACTED_IN {roles: ['黄金右脚'], year: 2001}]->(shaolin);
// 创建导演关系(周星驰自导自演)
MATCH (zxc:Person {name: '周星驰'}),
(kungfu:Movie {title: '功夫'})
CREATE (zxc)-[:DIRECTED]->(kungfu);
MATCH (zxc:Person {name: '周星驰'}),
(shaolin:Movie {title: '少林足球'})
CREATE (zxc)-[:DIRECTED]->(shaolin);
// 查询示例
MATCH (a:Actor) RETURN a.name AS name LIMIT 3;
// 更全面的查询:所有演员和他们的电影
MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
RETURN a.name AS actor, m.title AS movie, m.released AS year
ORDER BY a.name, m.released;
// 查询导演和演员的合作(周星驰自导自演)
MATCH (actor:Person)-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(director:Person)
RETURN actor.name AS actor, director.name AS director, m.title AS movie
ORDER BY director.name, actor.name;5. CREATE 和 MATCH 的使用 #
5.1 CREATE:创建数据 #
CREATE 用于创建新的节点和关系。它总是创建新数据,即使数据已存在也会创建重复的。
5.1.1 创建单个节点 #
// 创建一个 Movie 节点,属性为 title='功夫', released=2004
CREATE (:Movie {title: '功夫', released: 2004})这个语句创建一个 Movie 节点,没有变量名,所以无法在后续查询中引用它。
5.1.2 创建节点并返回 #
如果想返回创建的数据,需要给节点一个变量名:
// 创建一个 Actor 节点,属性为 name='周星驰', born=1962
CREATE (a:Actor {name: '周星驰', born: 1962})
// 返回刚刚创建的节点 a
RETURN a5.1.3 创建复杂结构 #
可以一次性创建节点和关系:
// 创建一个Actor节点,名字为"周星驰"
// 创建一个ACTED_IN关系,属性roles为列表['阿星'],连接到Movie节点
// 创建一个Movie节点,标题为"功夫",上映时间为2004年
CREATE (a:Actor {name: '周星驰'})
-[r:ACTED_IN {roles: ['阿星']}]->
(m:Movie {title: '功夫', released: 2004})
// 返回刚刚创建的三个对象:a(演员)、r(关系)、m(电影)
RETURN a, r, m5.2 MATCH:匹配数据 #
MATCH 用于查找匹配模式的节点和关系。它不会创建新数据,只查找已存在的数据。
5.2.1 匹配所有节点 #
MATCH (m:Movie)
RETURN m5.2.2 匹配特定节点 #
MATCH (a:Actor {name: '周星驰'})
RETURN a5.2.3 匹配关系模式 #
MATCH (a:Actor {name: '周星驰'})-[r:ACTED_IN]->(m:Movie)
RETURN m.title, r.roles5.3 CREATE 和 MATCH 实践 #
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建一个电影节点,标题为"功夫",上映年份为2004
CREATE (:Movie {title: '功夫', released: 2004})
// 创建一个演员节点,名字为"周星驰",出生年份为1962,并返回该节点
CREATE (a:Actor {name: '周星驰', born: 1962})
RETURN a
// 创建一个演员节点"吴孟达",出生年份1952
// 创建一个"ACTED_IN"关系,属性roles为['猪八戒']
// 关系连接到电影节点"大话西游"(1995年)
CREATE (a:Actor {name: '吴孟达', born: 1952})
-[r:ACTED_IN {roles: ['猪八戒']}]->
(m:Movie {title: '大话西游', released: 1995})
// 匹配所有电影节点,并返回其标题和上映年份
MATCH (m:Movie) RETURN m.title AS title, m.released AS released
// 匹配名字为"周星驰"的演员节点,返回其姓名和出生年份
MATCH (a:Actor {name: '周星驰'}) RETURN a.name AS name, a.born AS born
// 匹配"吴孟达"出演的所有电影,并返回电影标题和角色列表
MATCH (a:Actor {name: '吴孟达'})-[r:ACTED_IN]->(m:Movie)
RETURN m.title AS title, r.roles AS roles6. MERGE 的使用 #
6.1 什么是 MERGE? #
MERGE 是 CREATE 和 MATCH 的组合。它会先检查数据是否存在,如果不存在则创建,如果存在则匹配。
6.2 前置知识:为什么需要 MERGE? #
问题: 使用 CREATE 可能会创建重复数据
// 第一次执行:创建节点
CREATE (a:Actor {name: '周星驰'})
// 第二次执行:又创建一个同名节点(重复!)
CREATE (a:Actor {name: '周星驰'})解决方案: 使用 MERGE 避免重复
// 第一次执行:创建节点
MERGE (a:Actor {name: '周星驰'})
// 第二次执行:匹配已存在的节点(不重复)
MERGE (a:Actor {name: '周星驰'})6.3 MERGE 的基本用法 #
6.3.1 基本 MERGE #
MERGE (m:Movie {title: '功夫'})
RETURN m行为:
- 如果节点不存在:创建它
- 如果节点已存在:匹配它
6.3.2 使用 ON CREATE SET #
// 如果不存在标题为"功夫"的电影节点,则创建该节点
MERGE (m:Movie {title: '功夫'})
// 如果是新创建的节点,则设置 released 属性为 2004
ON CREATE SET m.released = 2004
// 返回节点 m
RETURN m行为:
- 如果节点不存在:创建它,并设置
released = 2004 - 如果节点已存在:匹配它,不执行
ON CREATE SET
6.3.3 使用 ON MATCH SET #
// 合并(匹配或创建)一个 Movie 节点,标题为"功夫"
MERGE (m:Movie {title: '功夫'})
// 如果节点已存在,则设置 lastSeen 属性为当前时间戳
ON MATCH SET m.lastSeen = timestamp()
// 返回节点 m
RETURN m行为:
- 如果节点不存在:创建它,不执行
ON MATCH SET - 如果节点已存在:匹配它,并更新
lastSeen
6.3.4 组合使用 #
// 合并(匹配或创建)一个标题为"功夫"的 Movie 节点
MERGE (m:Movie {title: '功夫'})
// 如果是新创建的节点,则设置 released 属性为 2004,created 属性为当前时间戳
ON CREATE SET m.released = 2004, m.created = timestamp()
// 如果节点已存在,则设置 lastSeen 属性为当前时间戳
ON MATCH SET m.lastSeen = timestamp()
// 返回节点 m
RETURN m6.4 MERGE 实践 #
// 清空数据库
MATCH (n) DETACH DELETE n
// 合并(匹配或创建)一个标题为"功夫"的电影节点,如果不存在则创建并返回该节点
MERGE (m:Movie {title: '功夫'}) RETURN m
// 合并(匹配或创建)一个标题为"喜剧之王"的电影节点
// 如果该节点是新创建的,则设置 released 属性为 1999
MERGE (m:Movie {title: '喜剧之王'})
ON CREATE SET m.released = 1999
// 返回节点的 title 属性作为"标题",released 属性作为"上映年份"
RETURN m.title AS 标题, m.released AS 上映年份
// 合并(匹配或创建)一个标题为"功夫"的电影节点
// 如果该节点已存在,则设置 lastSeen 属性为 '2024-01-01'
MERGE (m:Movie {title: '功夫'})
ON MATCH SET m.lastSeen = '2024-01-01'
// 返回节点的 title 属性作为"标题",lastSeen 属性作为"最近查看时间"
RETURN m.title AS 标题, m.lastSeen AS 最近查看时间
// 合并(匹配或创建)一个标题为"少林足球"的电影节点
// 如果是新创建的节点,则设置 released 为 2001,created 为 '2024-01-01'
// 如果节点已存在,则设置 lastSeen 为 '2024-01-01'
MERGE (m:Movie {title: '少林足球'})
ON CREATE SET m.released = 2001, m.created = '2024-01-01'
ON MATCH SET m.lastSeen = '2024-01-01'
// 返回节点的各属性
RETURN m.title AS 标题, m.released AS 上映年份, m.created AS 创建时间, m.lastSeen AS 最近查看时间7. 使用别名优化查询结果 #
7.1 什么是别名? #
别名(Alias)是给查询结果中的字段起一个更易读的名字。使用 AS 关键字创建别名。
7.2 为什么需要别名? #
有些属性名可能不够直观,或者你想让结果更易读。使用别名可以让查询结果更清晰。
7.3 使用别名的示例 #
7.3.1 不使用别名 #
// 匹配名字为"周星驰"的演员,与其出演过的所有电影节点及关系
MATCH (a:Actor {name:'周星驰'})-[rel:ACTED_IN]-(movie:Movie)
// 返回"周星驰"的姓名、出生年份,以及对应的电影标题和上映年份
RETURN a.name, a.born, movie.title, movie.released结果:
a.name | a.born | movie.title | movie.released7.3.2 使用别名 #
MATCH (a:Actor {name:'周星驰'})
-[rel:ACTED_IN]-(movie:Movie)
RETURN a.name AS 姓名,
a.born AS `出生年份`,
movie.title AS 电影标题,
movie.released AS `上映年份`结果:
姓名 | 出生年份 | 电影标题 | 上映年份7.4 使用别名实践 #
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建演员和电影节点
CREATE (zxc:Actor {name: '周星驰', born: 1962}),
(erta:Movie {title: '大话西游', released: 1995})
// 匹配已创建的演员和电影节点
MATCH (zxc:Actor {name: '周星驰'}),
(erta:Movie {title: '大话西游'})
// 创建 "周星驰" 与 "大话西游" 之间的 ACTED_IN 关系,角色为"至尊宝"
CREATE (zxc)-[:ACTED_IN {roles: ['至尊宝']}]->(erta)
// 匹配"周星驰"及其出演的电影,并返回详细属性(未使用别名)
MATCH (zxc:Actor {name:'周星驰'})-[rel:ACTED_IN]-(movie:Movie)
RETURN zxc.name, zxc.born, movie.title, movie.released
// 匹配"周星驰"及其出演的电影,并使用别名返回结果字段
MATCH (zxc:Actor {name:'周星驰'})
-[rel:ACTED_IN]-(movie:Movie)
RETURN zxc.name AS 姓名,
zxc.born AS `出生年份`,
movie.title AS 电影标题,
movie.released AS `上映年份`8. 小结 #
8.1 核心概念 #
- 模式匹配:用模式描述想要查找的图结构
- 节点语法:
(变量名:标签 {属性}) - 关系语法:
-[变量名:类型 {属性}]-> - 模式语法:节点和关系的组合
- CREATE:创建新数据(可能重复)
- MATCH:查找已存在的数据
- MERGE:创建或匹配数据(避免重复)
8.2 语法要点总结 #
8.2.1 节点语法 #
(变量名:标签1:标签2 {属性1: 值1, 属性2: 值2})8.2.2 关系语法 #
-[变量名:关系类型 {属性1: 值1}]-> // 从左到右
<-[变量名:关系类型 {属性1: 值1}]- // 从右到左
-[变量名:关系类型 {属性1: 值1}]- // 无向8.2.3 模式语法 #
(节点1)-[关系]->(节点2) // 简单模式
(节点1)-[关系1]->(节点2)-[关系2]->(节点3) // 多跳模式
(节点1)-[*1..3]-(节点2) // 可变长度模式8.3 最佳实践 #
- 创建节点时使用变量名,方便后续引用
- 使用标签分类节点,提高查询效率
- 使用 MERGE 避免重复数据
- 使用别名提高结果可读性
- 使用 LIMIT 限制大型查询结果