Cypher Query Language (CQL)Neo4j 所使用的开放图形查询语言。Cypher 的语法提供了一种方式(类SQL)来匹配图中的节点和关系,也就是模式。如果具备 SQL 的基础,那么学习起 Cypher 就能变得更加容易。这是这篇指引推崇的做法 —— 先掌握SQL基础,再学习 Cypher。除此之外,还需要具备图形数据库和属性图模型的基本概念,以便更好的理解 Cypher 查询。

节点 Nodes

Cypher 使用 ASCII-Art 来表示模式。就像一个⚪一样,用双括弧来围绕节点,例如(节点A)。在之后如果我们想要引用这个节点,只需要使用一个变量例如(node_a) ,如果关注的问题与节点无关,还可以使用空括弧()。一般情况下,节点还会使用标签来区分实体,同时在Neo4j中,使用标签是一种执行优化的方案。以节点A为例,为其添加标签,如(节点A:标签1)

match (节点A:标签1) return 节点A.某属性

在进行节点查询时,有时还会用到(emp:Employee)-->(dep:Department)这样的模式,用以查看例如emp.name,dep.no等属性,可以看一个例子:

match (emp:Employee)-->(dep:Department)
where emp.name = {value}
return dep.no,dep.name

关系 Relationships

节点与节点之间可以用比直接查询更复杂的模式。关系是用-->来连接两个节点,若要描述关系的类型,则在箭头中增加一对方括号,例如-[]->,在方括号内写明关系类型。

  • 关系类型-[:friend]->
  • 声明关系类型的变量,例如 f-[f:friend]->
  • 附加属性-[{date:20180906}]->
  • 可变长度的路径结构信息-[:friend*..3]->

其中声明关系的变量是为了方便之后对有关关系的信息进行调用。例如friend中有一个until的信息,声明了变量之后就可以用 变量名.until 来调用。

match (emp:Employee)-[info:information]->(dep:Department)
where info.join_time > {value}
return info.join_time, type(info)

模式 Patterns

节点和关系的表达式是更为复杂模式的基础,模式是可以连续编写的,也可以用逗号进行分隔,同时还可以引用先前声明的变量或引入新的变量。

  • 找到朋友的朋友(me)-[:KNOWS]-(friend)-[:KNOWS]-(she)
  • 最短路径path = shortestPath( (me)-[:KNOWS*..5]-(other_peopel) )
  • 协同过滤(someone)-[:PURCHASED]->(product)<-[:PURCHASED]-()-[:PURCHASED]->(other_product)
  • 树导航(root)(root)<-[:PARENT*]-(leaf:Category)-[:ITEM]->(data:Product)

Cypher 的实践

首先通过create来创建一个节点,这里就拿我自己为例子:

create (me:Person {name:'林羽双珏'})
return me

create能够使用标签和属性创建一个节点。除此之外,我想给自己添加一个新的关系,现在想想自己喜欢做什么——比如我喜欢玩《Warframe》这款TPS网游。首先找到自己,并添加一个新的关系到新节点上:

match (me:Person {name:'林羽双珏'})
create (me)-[play:PLAY]->(warframe:PC_Game {name:'Warframe'})
return me,play,warframe

通过上面这两个例子,我们不难发现create不仅能够创建单个节点,同时也可以创建出更复杂的结构。接下来继续创建几个节点,但是每次创建节点都要编写这么长的代码未免太过麻烦,所以这一次除了create,还会用到foreach,循环遍历创建出节点:

match (me:Person {name:'林羽双珏'})
foreach(n in ['魏小彬','陈奕霖','刘懿辉','王祎','陈文辉','钟滨','唐建新'] |
create (me)-[:FRIEND]->(:Person {name:n})
)

在循环创建出多个节点之后,把我与朋友们的图给查询出来:

match (me:Person {name:'林羽双珏'})-[:FRIEND]->(myFriend)
return me,myFriend

iCEnot.png

根据查询出来的图可以看出与我关系为FRIEND的人(节点)一共有7个。假设此时,忽然想起了其中某一个人的老师是Warframe这款游戏的设计师,我们把这个二层关系也创建出来。

match (warframe:PC_GAME {name:'Warframe'})
match (wangyi:Person {name:'王祎'})
create (wangyi)-[:STUDENT]->(teacher:Person:GameDesigner {name:'Sean Bigham'})-[:DESIGNED]->(warframe)
return wangyi,teacher,warframe

我现在并不知道我的哪一个朋友的老师,是Warframe的设计师,我非常迫切的想要认识那位设计者,这时就可以通过这个社交网络找到谁可以帮助我。

match (me {name:'林羽双珏'})
match (designer)-[:DESIGNED]->(warframe:PC_GAME {name:'Warframe'})
match path = shortestPath( (you)-[*..5]-(designer) )
return db,designer,path

iCEmdI.png

CREATE 和 MATCH

这一个小节中对CREATE以及MATCH做一个简单的描述和总结,如若在完成了上述章节中的内容还对所使用的语句不是特别理解的话,建议在这一章节中进行巩固。相反,若经过实践已经对Cypher的使用找到了一些感觉,并理解你写下的每一个字符所代表的含义,那么这一章节你大可以跳过。

CREATE

create (me:Person {name:'林羽双珏'})
  • CREATE 子句用以创建数据(节点,关系都属于数据)
  • ( )双括弧表示节点
  • me 变量命,:Person 为这个节点施以指定的标签(也可以没有标签)
  • { } 花括号用以向节点添加属性,属性值以键值表达

MATCH

match (me:Person) where me.name ='林羽双珏' return me
//或
match (me:Person {name:'林羽双珏'}) return me // 本文所使用的模式
  • MATCH 子句用以指定节点和关系的模式

  • (me:Person) me 为变量名,:Person 用以指定匹配带标签“Person”节点

  • where 子句用以约束结果

  • me.name = '林羽双珏' 将值与name属性的值进行比较

  • return 子句用于请求特定的结果

模式匹配

match (me:Person)-[:FRIEND]-(friends)
where me.name = '林羽双珏'
return me , friends
//或
match (me:Person {name:'林羽双珏'})-[:FRIEND]-(friends)
return me , friends
  • MATCH 子句用以描述从已知节点找到节点的模式

  • -[:FRIEND]- 匹配“FRIEND”这一关系,如果不带有箭头><则表示任何一个方向都可以

  • (friends)将匹配到指定 meFRIEND