Cypher 基础教程
Cypher 基本概念
Cypher 是 Neo4j 数据库的查询语言,就如同 SQL 之于其他关系型数据库一样。Neo4j 作为一种图数据库,其数据均以节点、关系来存储。所以 Cypher 应该能够有某种语法来描述节点和关系,并能表征他们之间的关系。
比如下面 cypher 用来查找所有居住在北京的人。
(p:Person) -[:LIVES_IN]-> (:City {name: 'Beijing'}) return p
节点语法
() # 匿名的节点
(matrix) # 使用一个变量 matrix 与这个节点关联
(:Movie) # 类型为 Movie 的节点
(matrix:Movie)
(matrix:Movie {title: "The Matrix"}) # 指含有特定属性的某类节点
(matrix:Movie {title: "The Matrix", released: 1997})
关系语法
--> # 非直接相连的关系
-[role]-> # 使用变量关联此关系
-[:ACTED_IN]-> # 类型为 ACTED_IN 的关系
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ["Neo"]}]-> # 含有特定属性的关系
模式语法
将节点和关系组合起来,得出一个模式,而后使用此模式进行匹配:
(keanu:Person:Actor {name: "Keanu Reeves"} )
-[role:ACTED_IN {roles: ["Neo"] } ]->
(matrix:Movie {title: "The Matrix"} )
模式变量
模式由多个节点和关系组成,通常较长,可以将其保存为一个变量。在一条 cypher 中的其他位置,便可以使用此模式。
acted_in = (:Person)-[:ACTED_IN]->(:Movie)
子句
如同 SQL 中的 SELECT
、WHERE
等子句,在 cypher 中也有这类子句,用来进行查找、过滤、排序等操作。
创建
使用 CREATE
关键字能够创建节点、关系、模式,如下面语句,创建了一个类型为 Movie
的节点,且含有两个属性:
CREATE (:Movie { title:"The Matrix",released:1997 })
还可以同时使用多个 CREATE
创建更为复杂的模式:
CREATE (a:Person { name:"Tom Hanks",
born:1956 })-[r:ACTED_IN { roles: ["Forrest"]}]->(m:Movie { title:"Forrest Gump",released:1994 })
CREATE (d:Person { name:"Robert Zemeckis", born:1951 })-[:DIRECTED]->(m)
RETURN a,d,r,m
为现有的节点添加关系:
MATCH (p:Person { name:"Tom Hanks" })
CREATE (m:Movie { title:"Cloud Atlas",released:2012 })
CREATE (p)-[r:ACTED_IN { roles: ['Zachry']}]->(m)
RETURN p,r,m
匹配
MATCH (m:Movie)
RETURN m
MATCH (p:Person { name:"Keanu Reeves" })
RETURN p
MATCH (p:Person { name:"Tom Hanks" })-[r:ACTED_IN]->(m:Movie)
RETURN m.title, r.roles
添加 label
match (n {id:desired-id})
set n :newLabel
return n
Merge
有时候希望给某个节点添加属性,但又不能保证其存在于库中,此时可以使用 MERGE
。
首先查找某个模式,如果存在便得出这个模式,不存在则创建。在 ON CREATE
中指定的操作,会在创建的时候进行。
MERGE (m:Movie { title:"Cloud Atlas" })
ON CREATE SET m.released = 2012
RETURN m
如果不存在 p
和 m
之间的 ACTED_IN
关系,则创建,并在创建时添加属性。
MATCH (m:Movie { title:"Cloud Atlas" })
MATCH (p:Person { name:"Tom Hanks" })
MERGE (p)-[r:ACTED_IN]->(m)
ON CREATE SET r.roles =['Zachry']
RETURN p,r,m
得到正确的结果
过滤结果
可以在 WHERE
中对 MATCH
的结果进行过滤:
MATCH (m:Movie)
WHERE m.title = "The Matrix"
RETURN m
更好的方式是,在 MATCH
中指定更细致的条件:
MATCH (m:Movie { title: "The Matrix" })
RETURN m
WHERE
子句中可以使用正则表达式:
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name =~ "K.+" OR m.released > 2000 OR "Neo" IN r.roles
RETURN p,r,m
p.name =~ "K.+"
表示 name 以 K
开头。
在 WHERE
中还可以指定一个模式,可以过滤掉符合或者不符合这个模式的结果。
MATCH (p:Person)-[:ACTED_IN]->(m)
WHERE NOT (p)-[:DIRECTED]->()
RETURN p,m
返回结果
可以对结果整体来处理:
MATCH (:Person)
RETURN count(*) AS people
+# Cypher 基础教程-+
| people |
+# Cypher 基础教程-+
| 3 |
+# Cypher 基础教程-+
1 row
使用 DISTINCT
滤除重复: count(DISTINCT role)
count
会将其他列来进行分组,下面例子中会使用 actor,director
作为分组的键值:
MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(director:Person)
RETURN actor,director,count(*) AS collaborations
对结果排序
ORDER BY
可以基于任何可以访问到的变量、属性进行排序,默认是正序,如需倒序,使用关键词 DESC
:
MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
RETURN a,count(*) AS appearances
ORDER BY appearances DESC;
Collect
使用 collect
可以将多个匹配收集到一个数组中。
MATCH (m:Movie)<-[:ACTED_IN]-(a:Person)
RETURN m.title AS movie, collect(a.name) AS cast, count(*) AS actors
组合多条查询语句
UNION
UNION
可以将两个查询结果合并起来:
MATCH (actor:Person)-[r:ACTED_IN]->(movie:Movie)
RETURN actor.name AS name, type(r) AS acted_in, movie.title AS title
UNION
MATCH (director:Person)-[r:DIRECTED]->(movie:Movie)
RETURN director.name AS name, type(r) AS acted_in, movie.title AS title
+-------------------------------------------------+
| name | acted_in | title |
+-------------------------------------------------+
| "Tom Hanks" | "ACTED_IN" | "Cloud Atlas" |
| "Tom Hanks" | "ACTED_IN" | "Forrest Gump" |
| "Robert Zemeckis" | "DIRECTED" | "Forrest Gump" |
+-------------------------------------------------+
3 rows
WITH
WITH
能将多个语句连接起来,就像管道一样,前一个语句的输出作为下一个语句的输入:
MATCH (person:Person)-[:ACTED_IN]->(m:Movie)
WITH person, count(*) AS appearances, collect(m.title) AS movies
WHERE appearances > 1
RETURN person.name, appearances, movies
索引
对节点的某个属性建立索引,之后使用该属性来进行查询时,能够加快查询速度。
CREATE INDEX ON :Actor(name)
MATCH (actor:Actor { name: "Tom Hanks" })
RETURN actor;
当需要通过某个属性查询所有满足条件的节点时,分别在各不同 label 的节点上建立索引,就不起作用了。
MATCH (n:{ name:"xxx" }) RETURN n
上面这条语句会很慢,他需要遍历所有的节点。为此,可以给所有节点增加一个共有的 label,然后建立索引。
// 给所有节点增加一个 label 叫做 Node
match (n) set n :Node
// 在 Node 的 name 属性上建立索引
create index on :Node(name)