一 MATCH语法
WHERE中条件可以看作是模式的一部分,WHERE子句可视为MATCH子句的一部分。
MATCH的进阶用法有以下三种:
1.多模式:
MATCH p1..., p2=... [WHERE...]
2.多MATCH语句
MATCH ... [WHERE...]
MATCH ... [WHERE...]
3.MATCH…WITH:这个最终是为了以聚合函数作为判断条件
MATCH ... [WHERE...]
WITH ... [WHERE...]
二 MATCH作用
MATCH以模式匹配的方式对整个graph进行查找,并返回结果集。
查找过程:
- MATCH在整个graph中进行一次模式匹配,将得到的结果打包成一个结果元组,放入结果集;
- MATCH重复以上步骤,直到不再有新的结果。
查找结果:
- 结果不一定是单个值(结点/关系/路径),可以是多个值打包成的元组,如:(p1,p2);
【注意:当查询中有不相连的pattern时,会有Warning,并提示将建立笛卡尔结果;所谓笛卡尔结果就是MySQL中JOIN】 - 结果元组中包含多个路径值时,各路径不能包含相同的边,可以包含相同的点,如:p1为A–>B–>C,p2不能为A–>B,但是p2可为B–>D。
注意:
- MATCH操作的是模式pattern,结点的pattern是小括号;WITH、RETURN中操作的是变量,不需要小括号。
- MATCH返回的是一个结果集,结果集的元素为MATCH中pattern所包含的变量形成的元组;
- MATCH搜索的范围总是整个graph;多个MATCH子句串联时,每个都是重新从graph中查找。
- RETURN、WITH的搜索范围是中间结果表。
三 MATCH用法详解
3.1 MATCH…WHERE…RETURN…
路径模式也是一种约束条件,既可以放在MATCH子句中,也可以放在WHERE子句中。仅从语法上看,两种方式能实现相同的功能。那么到底放在哪里更好?可从执行效率上比较。
以下三条语句执行结果相同,但耗时相差巨大:
代码一:执行耗时:250 ms
MATCH (a:Blog{mid:'IbjCn93Bs'})-[*5]->(b:Blog) return b;
代码二:执行耗时:254 ms.
MATCH (a:Blog)-[*5]->(b:Blog) where a.mid='IbjCn93Bs' return b
代码三:执行耗时:165088 ms.
MATCH (a:Blog{mid:'IbjCn93Bs'}),(b:Blog) where (a)-[*5]->(b) return b;
分析/结论:
1.由代码一和代码二可知:模式放在MATCH中时,属性值约束放在MATCH或WHERE中执行时间基本相同。
2.由代码一和代码三可知:模式放在MATCH中执行效率远高于放在WHERE中。
可见,应该将模式相关的约束条件放到MATCH中,属性值相关的约束条件放哪都可以。
补充:
为什么会想到代码三这样的写法?
个人认为代码三这样的写法语义上更加清晰,在MATCH指明想要查找的目标是结点而不是路径,将与目标结点相关的所有约束(模式、属性值)都放到WHERE中,最后RETURN返回目标结点。
但既然效率上相差巨大,那自然不做此考虑了。
为什么代码三执行的这么慢?
个人猜想是:MATCH和WHERE是先后执行的,MATCH找到并保存所有符合模式的中间结果后,再由WHERE进一步判断。这样的话,MATCH中约束越宽松找到的中间结果越多,之后WHERE判断的次数也越多。
假设:代码一中访问整个图找到中间结果10个,之后进行10次WHERE判断即可;代码三中访问整个图找到中间结果1000个,之后再进行1000次WHERE判断。
另外,注意到,代码三中是不相连的模式,变量b模式找到的是所有结点,再与a形成笛卡尔积,数量就很大了。
3.2 MATCH p1=… , p2=…
https://neo4j.com/docs/cypher-manual/current/introduction/uniqueness/
MATCH p1=(a)-->(b),p2=(c)-->(d)
参照2.X中对MATCH匹配过程的理解,进行循环多次匹配后,MATCH返回的结果集如下:
[(p1_1,p2_1),(p1_2,p2_2)...]
对应表格形式:
p1 | p2 |
---|---|
p1_1 | p2_1 |
p1_1 | p2_2 |
p1_1 | p2_3 |
匹配多个模式时,Neo4j自动约束返回的一个结果(如:(p1_1,p2_1))中不能存在重复的边。验证如下:
graph:整个数据库
3.2.1 测试一:
match p1=(a:Test)-->(b)-->(c),p2=(a)-->()
return p1,p2
结果: no records
分析:
- 第一次匹配,找到p1=(717069)–>(717068)–>(717650),再找p2,由于(717069)只有一条出去的边(717069)–>(717068),而该边已存在于p1中,所以p2不存在,所以结果(p1,p2)不存在。
- 第二次匹配,找到p1=(717070)–>(717028)–>(717649),同理p2不存在,(p1,p2)不存在。
- 第三次匹配,找到p1=(717070)–>(717028)–>(717648),同理p2不存在,(p1,p2)不存在。
综上,结果集为空。
3.2.2 测试二:
match p1=(a:Test)-->(b)-->(c),p2=(b)-->()
return p1,p2
结果:
分析:
- 第一次匹配,找到p1=(717069)–>(717068)–>(717650),再找p2,p2不存在,(p1,p2)不存在。
- 第二次匹配,找到p1=(717070)–>(717028)–>(717649),p2=(717028)–>(717648),得(p1_1,p2_1)。
- 第三次匹配,找到p1=(717070)–>(717028)–>(717648),p2=(717028)–>(717649),得(p1_2,p2_2)。
综上,结果集为[(p1_1,p2_1),(p1_2,p2_2)]。
3.3 MATCH…MATCH…
graph:整个数据库
MATCH、RETURN的功能通过以下测试详细说明:
3.3.1 测试一:
MATCH (a:Test)-->()-->()
WHERE id(a) in [717069,717070]
MATCH p=(a)-->()
RETURN p
结果: