Neo4j Cypher语法(一)

目录

Cypher手册详解

1 背景

2 唯一性

3 语法

3.1 命名规则

3.2 表达式

3.3 变量与保留关键字

3.4 参数

3.5 操作符

3.6 模式

3.7 列表


Cypher手册详解

最近在研究知识图谱,避免不了的涉及到了图数据库和图算法,我们用的图数据库是neo4j,对其CQL语法做一个记录。整篇文章是对官网Cypher手册的翻译(正常访问超级慢,也许要翻墙),同时做了一些删减,例如地理函数和时间函数,和我的项目关系不大,就没有学习,对于官网的一些示例加上了结果的截图和自己的理解,本博文基于Neo4j3.5.3,其余版本可能会报错。如有错误,还麻烦各位大佬指正,非常感谢。

1 背景

什么是neo4j?

Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中--但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。

neo4j的呈现形式:Neo4j中不存在表的概念,只有两类:节点(Node)和关系(Relation),可以简单理解为图里面的点和边。

在数据查询中,节点一般用小括号(),关系用中括号[]。

当然也隐含路径的概念,是用节点和关联表示的,如:(a)-[r]->(b),表示一条从节点a经关联r到节点b的路径。

关系:neo4j中是单向关系,严格的来说不具备双向或者无向的关系。但是merge (a)-[r]-(b)这样的语句创建的关系可以理解为是双向的,但是neo4j中比较尴尬的一点是这样可以理解为无向关系的关系,在web呈现时是带着单向箭头的。

属性:节点和关系都可以具备属性。

标签:代表节点的类型,一个节点可以有0个、1个或者多个标签。

类型:代表关系的类型,一条关系可以有0个或者1个,一条边不能具有多个type。

2 唯一性

在模式匹配时,neo4j确保不会在单个模式中多次找到相同图形关系的匹配。举例,在寻找朋友的朋友时,不会返回所述用户自身。

CREATE (adam:User { name: 'Adam' }),(pernilla:User { name: 'Pernilla' }),(david:User { name: 'David'}),(adam)-[:FRIEND]->(pernilla),(pernilla)-[:FRIEND]->(david) 

寻找Adam朋友的朋友

MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-()-[r2:FRIEND]-(friend_of_a_friend)

RETURN friend_of_a_friend.name AS fofName

返回David

因为r1和r2在同一个模式中,又是不同的变量名,所以不会返回同一条关系,即图形中的有向边。检验:在两个子句中用不同的变量名就不管用

MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend)

MATCH (friend)-[r2:FRIEND]-(friend_of_a_friend)

RETURN friend_of_a_friend.name AS fofName

但是只要在一个模式中,即使拆分了多个子模式也不会匹配到同一关系,如下所示。

MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend),(friend)-[r2:FRIEND]-(friend_of_a_friend)

RETURN friend_of_a_friend.name AS fofName

3 语法

3.1 命名规则

必须以字母开头,不能以数字开头。

节点标签:驼峰式命名,关系类型:全大写命名。

3.2 表达式

十进制、十六进制:0x13ff,0xFCA39

八进制整数文字:01372、02127

字符串、bool类型

属性:n.prop、x.prop、rel.thisProperty

动态属性:n["prop"], rel[n.city + n.zip], map[coll[0]]

参数:$param, $0

表达式列表:['a', 'b'], [1, 2, 3], ['a', 2, n.property, $param], [ ].

函数调用:length(p) nodes(p)

聚合函数,路径模式

正则表达式:a.name =~ 'Tim.*'

字符串匹配:

surname STARTS WITH 'Sven',

surname ENDS WITH 'son' or a.surname CONTAINS 'son'

CASE表达式

3.2.1 字符串常用的转义序列

Tab键  后退键 新起一行 回车符 f 制表符 ’ 单引号 ’’双引号

\ 反斜杠的转义

3.2.2 CASE表达式

计算表达式,并按顺序与WHEN子句进行比较,直到找到匹配项。 如果未找到匹配项,则返回ELSE子句中的表达式。 但是,如果没有ELSE情况且未找到匹配项,则返回null。

CASE test

 WHEN value THEN result

  [WHEN ...]

  [ELSE default]

END

 

建表语句:

create (A:Person {name:'Alice', eyes:"brown",age:38}),

(B:Person {name:"Bob", eyes:"blue", age:25}),

(C:Person {name:"Charlie", eyes:'green',age:53}),

(D:Person {name:"Daniel", eyes:'brown'}),

(E:Person {name:'Eskil',eyes:"blue",age:41,array:['one','two','three']}),

(A)-[:KNOWS]->(B),

(A)-[:KNOWS]->(C),

(B)-[:KNOWS]->(D),

(C)-[:KNOWS]->(D),

(B)-[:MARRIED]->(E)

测试语句1:

MATCH (n:Person)
RETURN n.name,
CASE n.eyes
WHEN 'blue'
THEN 1
WHEN 'brown'
THEN 2
ELSE 3 END AS result

测试语句2:

MATCH (n:Person)
RETURN n.name,
CASE
WHEN n.eyes = 'blue'
THEN 1
WHEN n.age < 40
THEN 2
ELSE 3 END AS result

测试语句3:

我们看到建表语句中,存在一些节点时没有age属性的,我们希望返回一个age_10_years_ago的值,假设不存在age属性,将该值返回-1。我们按照如下的方式来试写查询语句,期望对于Daniel返回-1,因为他不具备age属性。但是并不如意:

MATCH (n:Person)
RETURN n.name,
CASE n.age
WHEN n.age IS NULL THEN -1
ELSE n.age - 10 END AS age_10_years_ago

原因:n.age是一个整型,而n.age IS NULL是一个bool值,所以不会走到WHEN n.age IS NULL THEN -1这个对应的分支,需要换成如下的写法:

MATCH (n:Person)
RETURN n.name,
CASE
WHEN n.age IS NULL THEN -1
ELSE n.age - 10 END AS age_10_years_ago

换一种方式理解,就是常用的switch(n.age), 不会等于 n.age is null这个case ,想要返回-1直接写成如下方式即可。

MATCH (n:Person)
RETURN n.name,
CASE n.age
WHEN NULL THEN -1
ELSE n.age - 10 END AS age_10_years_ago

3.3 变量与保留关键字

变量仅在同一查询部分中可见

变量不会转移到后续查询中。 如果使用WITH将多个查询部分链接在一起,则必须在WITH子句中列出变量以将其转移到下一部分。

保留关键字不能用于变量名、函数名、参数。

3.4 参数

Cypher支持使用参数查询。这意味着开发人员不必使用字符串构建来创建查询。此外,参数使得Cypher的执行计划缓存更加容易,从而缩短了查询执行时间。

参数可用于:文字和表达式

节点和关系id

仅用于显式索引:索引值和查询

参数不能用于以下构造,因为它们构成了编译到查询计划中的查询结构的一部分:

属性键;所以,MATCH(n)WHERE n.$ param ='something'无效

关系类型

标签

参数可以包含字母和数字,以及这些参数的任意组合,但不能以数字或货币符号开头。

3.4.1 参数定义

参数仅仅对当前会话有效,网页刷新变量消失。变量为一个kv的键值对。

:param a:1, b:2或者:param {a: 1, b: 2}以这样的形式来定义参数,注意前面是有冒号的。

MATCH (n:Person)

WHERE n.name = $name

RETURN n

MATCH (n:Person { name: $name })

RETURN n

查看当前的所有参数:

:params

3.4.2 可以使用参数的各种场景

正则表达式:

:param {"regex":".*VM.*"}

match (n:VM) where n.name=~ $regex return n.name

大小写敏感的字符串匹配

:params { "name" : "Michael"}

MATCH (n:Person)

WHERE n.name STARTS WITH $name

RETURN n.name

创建多个带属性带标签的节点

:param {"props" : [ {

    "awesome" : true,

    "name" : "Andy",

    "position" : "Developer"

  }, {

    "children" : 3,

    "name" : "Michael",

    "position" : "Developer"

  } ]}

 

UNWIND $props AS properties

CREATE (n:Person)

SET n = properties

RETURN n

判断某个变量在或者不在变量列表中

:param "ids" : [ 0, 1, 2 ]

//判断变量在列表中,如何判断变量不在对应的列表中?not in会报错,<>达不到想要的结果

MATCH (n)

WHERE id(n) IN $ids

RETURN n.name

//判断变量不存在于列表中

match(n:VM) where size([l in [id(n)] where l in $ids ])=0 return n

调用函数

:param "value" : "Michaela"

START n=node:people(name = $value)

RETURN n

3.5 操作符

3.5.1 使用[]

来访问动态计算的属性键 对多个属性键来进行共同筛选

CREATE (a:Restaurant { name: 'Hungry Jo', rating_hygiene: 10, rating_food: 7 }),(b:Restaurant { name: 'Buttercup Tea Rooms', rating_hygiene: 5, rating_food: 6 }),(c1:Category { name: 'hygiene' }),(c2:Category { name: 'food' })

WITH a, b, c1, c2

MATCH (restaurant:Restaurant),(category:Category)

WHERE restaurant["rating_" + category.name]> 6

RETURN DISTINCT restaurant.name

3.5.2 ^完成指数运算

3.5.3字符串判断

STARTS WITH       ENDS WITH  CONTAINS

3.5.4 使用in进行更加复杂的列表成员操作

RETURN [2, 1] IN [1,[2, 1], 3] AS inList 会return true。

RETURN [1, 2] IN [1, 2] AS inList  会return false 这里的in不是判断认为两个是整体,而是将左边作为一个整体元素,判断左边是否为右边的子元素

如下查询可以用于判断llhs是否至少包含一个也存在于lrhs中的元素

MATCH (n)//判断当前库中的所有节点,有哪些的标签是Person或者Employee

WHERE size([l IN labels(n) WHERE l IN ['Person', 'Employee'] | 1]) > 0

RETURN count(n)

3.5.5 用[]获取列表元素

WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names
RETURN names[1..3] AS result

这里的方括号是左闭右开的,

所以会返回[‘John’,‘Bill’]

和C语言一样//表示对应的注释

3.6 模式

模式和模式匹配时Cypher的核心,有效使用Cypher需要对模式有一个正确的理解。

最为简单的模式就是一个双括号括上一个变量名,例如(a) a就是一个变量名

(a)-->(b)

(a)-->(b)<--(c)这样的一系列的节点和关系称之为路径

可以在模式中描述的最简单的属性称之为标签(a:User)-->(b)   同时可以描述具备多个标签的节点(a:User:Admin)-->(b)

3.6.1 指定属性

对于MERGE子句,属性将用作任何现有数据必须具有的形状的附加约束(指定的属性必须与图中的任何现有数据完全匹配)。 如果未找到匹配的数据,则MERGE的行为类似于CREATE,并且将在新创建的节点和关系中设置属性。

3.6.2 关系的模式

类似于节点的标签,对于关系来说叫做类型,但是和节点标签不同的是,关系的类型仅仅只有一种。如果我们想要描述一些数据,使得这种关系可以有一组类型中的任何一种,那么它们都可以在模式中列出,用管道符号将它们分开。像这样(但是仅仅适用于match,不适用于Create和merge):

(a)-[r:TYPE1|TYPE2]->(b)

关系名称通常也可以省略

3.6.3 变量长度的模式匹配

在模式的关系描述中指定长度来进行对应的描述

(a)-[*2]->(b)  等价于  (a)-->()-->(b)

(a)-[*3..5]->(b)这一关系是左闭右闭,即包含3个关系、4个关系、5个关系

(a)-[*3..]->(b)    (a)-[*..5]->(b)

需要特别注意的一点是,即使关系是单向的,在如下的语句中,--表示不考虑关系的方向,仍然会反向查找找出走一个关系或者两个关系的节点。

MATCH (me)-[:KNOWS*1..2]-(remote_friend)

WHERE me.name = 'Filipa'

RETURN remote_friend.name

3.7 列表

RETURN range(0, 10) as list ,range(0, 10)[3] as result//将列表中下标索引为3的元素也就是第4个元素返回

与Python不同的是 这里的range是左闭右闭的,即一个列表中有11个元素

range(0, 10)[-3]//倒数第三个元素

RETURN range(0, 10)[0..3]//左闭右开

RETURN range(0, 10)[-5..]或者[..4]//只有在list中的a..b是左闭右开的,路径长度的匹配与range范围中的a..b都左闭右闭的。

//也可以理解为返回倒数5个元素的列表和正数4个元素的列表

RETURN size(range(0, 10)[0..3])//size函数的返回结果是3

3.7.1 列表推导

RETURN [x IN range(0,10) WHERE x % 2 = 0 | x^3] AS result//这里的竖线不是或,而是管道

MATCH (a:Person { name: 'Charlie Sheen' })

RETURN [(a)-->(b) WHERE b:Movie | b.year] AS years

3.8 映射

Cypher坚定地支持映射,对map的处理不太理解。

3.9 使用null

Cypher中的null表示缺失或未定义的值,null并不等于null,不知道的两个值并不意味着它们相等 ,所以null=null会抛出null而不是true

null IN [1, 2, 3]  

null IN [1, null, 3] 

null in [] 

如果使用null来做列表切片的首尾索引值,那么返回值也是null。

原文地址:https://blog.csdn.net/weixin_42348333/article/details/89758617
原文地址:https://www.cnblogs.com/jpfss/p/11738650.html