第4章 Cypher 查询语言:节点、关系、属性、模式匹配基础
Cypher 是 Neo4j 的图查询语言,说实话,我第一次接触时觉得它像 SQL 和 ASCII 艺术的结合体。后来在做一个药物靶点关联项目时,我才真正体会到它的直观——用方括号和箭头就能画出图里的关系,这比写一堆 JOIN 爽多了。
4.1 认识 Cypher
Cypher 不是声明式语言里最年轻的,但绝对是最适合图数据的。它的核心理念很简单:你在屏幕上怎么画图,就怎么写查询。节点用圆括号 (),关系用方括号 [] 加箭头 -->,属性写成键值对。
我记得刚带团队时,有个同事问我:「Cypher 是不是只能查单个节点?」我笑了笑,给他看了下面这段代码,他能在一行里匹配出药物、靶点和疾病的三元组。
MATCH (d:药物)-[r:作用于]->(t:靶点)-[:关联]->(dis:疾病)
RETURN d.name, t.name, dis.name
LIMIT 10
你看,箭头方向就把关系语义表达清楚了。嗯,这里要注意:箭头方向必须和数据插入时一致,否则查不到东西。
4.2 节点(Node)
节点是图里的实体。在 Cypher 里创建节点,就像写一个标签化的括号。
CREATE (:药物 {name: '阿司匹林', 机制: 'COX抑制剂'})
RETURN 节点
我个人习惯先定义标签(Label),再加属性。标签相当于关系数据库里的表名,但一个节点可以有多个标签,比如 :药物:NSAID。
匹配节点用 MATCH,和 WHERE 配合过滤。
MATCH (d:药物)
WHERE d.机制 CONTAINS '抑制'
RETURN d.name, d.机制
4.3 关系(Relationship)
关系是图的核心。Cypher 用 -[r:关系类型]-> 或 <-[r:关系类型]- 表示有向边。关系也可以有属性,比如记录某个相互作用的置信度。
我曾经遇到一个坑:两个节点之间可以存在多条不同方向或类型的关系,查的时候如果不指定类型,会返回所有关系。比如下面的例子,只查 :作用于 关系。
MATCH (d:药物)-[r:作用于]->(t:靶点)
RETURN d.name, t.name, r.置信度
关系类型必须用冒号开头,习惯上用大写字母加下划线。方向可以用 --(无方向)或 ->/<-(有方向)。我建议在药物图谱里统一用有向关系,因为「药物作用于靶点」就是有向的。
4.4 属性(Property)
属性就是键值对,写在节点或关系的大括号里。支持字符串、数值、布尔、列表等类型。
CREATE (:药物 {
name: '布洛芬',
分子量: 206.28,
获批: true,
别名: ['Ibuprofen', 'Advil']
})
Cypher 的查询可以基于属性过滤:
MATCH (d:药物)
WHERE d.分子量 < 300 AND d.获批 = true
RETURN d.name
1stName,结果查询报错。建议用驼峰或下划线命名,比如 first_name。
4.5 模式匹配基础
模式匹配是 Cypher 的灵魂。你写一个路径模式,Cypher 会从图里找出所有匹配的子图。
最简单的模式是两个节点一条关系:
MATCH (a:药物)-[:作用于]->(b:靶点)
RETURN a, b
三个节点两条关系形成一条链:
MATCH (d:药物)-[:作用于]->(t:靶点)-[:关联]->(dis:疾病)
RETURN d.name, t.name, dis.name
你想想看,如果用 SQL 查这个「药物→靶点→疾病」路径,至少要写两个 JOIN。Cypher 一行搞定,而且可读性高得多。
模式还可以用变长路径。比如查「药物通过任意步数作用于靶点」:
MATCH (d:药物)-[:作用于*1..3]->(t:靶点)
RETURN d, t
这里的 *1..3 表示关系步数从 1 到 3。我在做药物重定位项目时,经常用变长路径找间接关联。
(节点)-[关系]->(节点),机器就在图里做同构子图搜索。这个思想理解透了,后面学高级查询就轻松了。
下面这张图总结了我们刚才讲的节点、关系、属性和模式匹配的关系。
再来看一个实际的药物图谱例子。假设我们要查「阿司匹林直接作用的靶点,以及这些靶点关联的疾病」:
MATCH (d:药物 {name: '阿司匹林'})-[:作用于]->(t:靶点)-[:关联]->(dis:疾病)
RETURN d.name AS 药物, t.name AS 靶点, dis.name AS 疾病
ORDER BY 疾病
这个查询返回一张表,每一行是一条路径。我个人习惯在返回时用 AS 起别名,方便后续处理。
节点、关系、属性对比
| 元素 | Cypher 写法 | 示例 | 是否可有属性 |
|---|---|---|---|
| 节点 | (变量:标签) | (d:药物 {name:'阿司匹林'}) | 是 |
| 关系 | -[变量:类型]-> | -[r:作用于 {置信度:0.9}]-> | 是 |
| 属性 | {键: 值} | {name: '布洛芬', 获批: true} | — |
MATCH + RETURN 这个组合。模式匹配就像搭积木,一个括号一个箭头,积木搭对了,查询就对了。多写几遍,手感就上来了。