还是写在前面?
按照原计划系列的第二篇博文来介绍一下Neo4j独特的查询语言——Cypher。这个在网上资料还是挺全的,鸟哥也没法把所有内容都覆盖,就挑选比较重要的内容介绍了,建议大家去官网查阅比较齐全的文档。
Cypher简介
Neo4j的查询语言称作Cypher,Cypher是对图形的声明查询语言,使用图形模式匹配作为主要的机制作图形数据选择(包括只读和变更操作)。
简单的查询语句
假如我们想要查询一个Job相邻的依赖Job,我们可以使用如下的查询语句
MATCH (n:Job) WHERE n.name="EXM" WITH n MATCH (:Job) - [:DEPEND] -> (b:Job) RETURN b
首先我们要指定起始节点,我们通过查找Job中name为"EXM"的节点来指定
下一步,设置需要输出结果的匹配模式。模式就是对需要检查数据库中的子图形的描述,它是由关系相互连接的一些节点构成。一个关系连接的两个节点是典型的图形模式,它是用
( )-[]-( )描述的。节点用圆括号( )指定,关系使用方括号[]指定。节点和关系使用连字符连接。(注意连字符可以包含方向!)
最后,要返回查询的结果,这里我们使用一个关键字RETURN来返回查询结果 b
Cypher的基本语法
Cypher句法由四个不同的部分组成, 每一部分都有一个特殊的规则:
- start——查找图形中的起始节点。
- match——匹配图形模式, 可以定位感兴趣数据的子图形。
- where——基于某些标准过滤数据。
- return——返回感兴趣的结果。
Cypher的模式匹配性质使得图形模式成为任何查询的重点问题,因此我们重点介绍它。
MATCH模式匹配
① 使用节点和关系标识
在Cypher查询中,节点和关系都可以与标识关联,这种关联使得以后可以在同样的查询中引用同一个图形实体。
前面的例子中我们就给Job分别定义了别名n、b,当然关系也可以加上别名
MATCH (j:Job) - [d:DEPEND] -> (b:Job) RETURN b
如果没有给出别名,那么就是匿名节点/关系,后续如果不需要用到该节点/关系建议匿名,比如上面的例子的(:Job)和[:DEPEND]
② 复杂模式匹配
了解了简单的用法之后,我们来一个比较复杂一点的查询
MATCH (n:Job) WHERE n.name="EXM" WITH n
MATCH p = (n) - [*] -> (m:Job) WHERE NOT m.description="EX"
RETURN m
这个查询会返回指定名字为"EXM"的下游所有节点,然后过滤掉描述description值为"EX"的节点
看到这里,相信大家已经大概了解匹配模式的三大部分内容了,下面将对这三大部分进行更加详细地介绍。
- 查找起始节点
① 通过单个编号查找
使用关键字start可以指定编号查找起始节点
start job = node(1)
RERUEN job
② 通过多个节点编号加载多个节点
在start语句中使用多个编号,需要列出以逗号隔开的编号参数值,如下所示:
start job = node(1,3)
MATCH job - [:DEPAND] -> (b:job)
RETURN b
③ 使用索引查找
start job = node:job(name = "EXM")
RETURN job
④ 使用基于模式的索引查找
MATCH (job:job)
WHERE job.name = "EXM"
RETURN job
- 过滤数据
在一些情况下,需要对节点和关系再做一些过滤以决定返回哪些结果。与在关系数据库中的SQL查询相同,Cypher查询过滤使用where语句实现。
可以通过属性值、正则表达式以及函数(has(property))过滤
MATCH (n:Job) WHERE n.name="EXM" WITH n
MATCH (:Job) - [:DEPEND] -> (b:Job)
WHERE b.email =~ /.*@gmail.com/
RETURN b
- 获得结果
Cypher查询的结果用return语句返回,return语句不仅仅能返回节点——也可以返回关系、节点和关系的属性,甚至子图形的整个路径。
① 返回属性
上面的例子基本都是返回节点信息,我们也可以返回节点的属性信息
MATCH (n:Job) WHERE n.name="EXM" WITH n
MATCH (:Job) - [:DEPEND] -> (b:Job)
WHERE b.email =~ /.*@gmail.com/
RETURN b.name
② 返回关系
同样,我们也可以返回感兴趣的关系或者是关系的属性值
MATCH (n:Job) WHERE n.name="EXM" WITH n
MATCH (:Job) - [d:DEPEND] -> (b:Job)
WHERE b.email =~ /.*@gmail.com/
RETURN d
③ 返回路径
除节点和属性外,还可以从Cypher查询返回整个路径。要返回路径作为查询的结果,将需要给它一个标识符并能对它做出引用。那么,在return语句中通过指定标识符就可以返回引用的路径。
MATCH (n:Job) WHERE n.name="EXM" WITH n
MATCH recPath = (:Job) - [d:DEPEND] -> (b:Job)
WHERE b.email =~ /.*@gmail.com/
RETURN d,recPath
④ 分页结果
结果中包含很多实体,可能需要将结果分成几页以显示在网页上。要对Cypher查询结果进行分页,Neo4j有三个简单明了的语句。
order —— 在分页之前,对结果进行排序,因此分页返回的结果是一致的,无论是往前还是往后分页。
skip —— 划分结果集以便跳到指定的页。
limit —— 以页面尺寸限制返回结果的数量。
MATCH (job:job)
WHERE job.name = "EXM"
RETURN job
ORDER BY job.name
SKIP 3
LIMIT 25
高级Cypher
聚合
就像在SQL中的GROUP BY一样,Cypher支持查询中的聚合函数。不是使用一个专用GROUP BY语句,Cypher中的分组关键词被定义为所有的查询非聚合结果。
Cypher支持SQL的所有常用的聚合函数:SUM的数值求和、AVG计算平均值到MAX和MIN寻找数值属性中的最大值和最小值。
函数
TYPE函数
查找一个关系的类型。下面的例子演示了“每一类型有多少个关系开始于或结束于job名为EXM的节点?”
start n = node:job(name = "EXM")
MATCH n - [rel] - ()
WITH TYPE(rel), count(*)
常用的函数如下:
HAS(graphEntity.propertyName) —— 如果一个节点或关系具有给定名字的属性存在,则返回true。
NODES(path) —— 把一个路径转换成一个可迭代的节点集。
ALL(x in collection where predicate(x)) —— 如果collection中的每一个单个元素匹配了给定的predicate,则返回true。
NONE(x in collection where predicate(x)) —— 如果提供的集合中没有元素匹配谓词表述,返回true;否则,返回false。
ANY(x in collection where predicate(x)) —— 如果至少有一个元素匹配谓词表述,返回true;如果没有匹配的,返回false。
SINGLE(x in collection where predicate(x)) —— 如果正好有一个元素匹配谓词表述,返回true;如果没有或多于一个匹配的,这个函数返回false。
with语句的管道功能
在Cypher中,可以将一个查询的输出链接到另一个查询中,从而创建功能强大的图形结构。Cypher中的链(或管道)语句是with。
如果问题涉及在聚合函数上的过滤。在SQL中,在聚合函数上过滤是由HAVING语句完成的,但是Cypher并不支持这个。而在Cypher中可以使用with,就像下面的程序演示的一样。
start n = node(1)
MATCH n - [rel] - ()
WITH TYPE(rel) as type, count(*) as count
WHERE count > 1
RETURN type,count;
注意:在被用作链接查询之前命名with语句中的输出字段是强制性的!
总结
本文把常用的Cypher语言用法结合实际查询例子简要的介绍了一下,了解了Cypher之后,其实我们就可以使用Spring Data Neo4j(SDN)进行简单的开发了。下一篇文章将会介绍SDN的内容。