语法-运算符,注释

Neo
Neo
2022-03-12 / 0 评论 / 66 阅读

本节内容源自Cypher官方手册V4.4版,笔者对其进行学习、翻译、记录。

运算符总览

类型描述
聚合算子DISTINCT
属性运算符.用于静态属性访问,[]用于动态属性访问,=用于替换所有属性,+=用于改变特定属性
数学运算符+, -, *, /, %,^
比较运算符=, <>, <, >, <=, >=, IS NULL,IS NOT NULL
用于字符串的比较运算符STARTS WITH, ENDS WITH,CONTAINS
布尔运算符AND, OR, XOR,NOT
字符串运算符+用于连接,=~用于正则表达式匹配
时间运算符+以及-持续时间和时间瞬间/持续时间之间的操作,*以及/持续时间和数字之间的操作
Map运算符.用于按键的静态值访问,[]用于按键的动态值访问
List运算符+用于连接,IN检查列表中的元素是否存在,[]用于动态访问元素

聚合算子

聚合运算符包括:

  • 删除重复值:DISTINCT

使用DISTINCT运算符

Person从节点检索独特的眼睛颜色。

CREATE
  (a:Person {name: 'Anne', eyeColor: 'blue'}),
  (b:Person {name: 'Bill', eyeColor: 'brown'}),
  (c:Person {name: 'Carol', eyeColor: 'blue'})
WITH [a, b, c] AS ps
UNWIND ps AS p
RETURN DISTINCT p.eyeColor

尽管'Anne'和'Carol'都有蓝眼睛,但'blue'只返回一次。

"blue"
"brown"

DISTINCT通常与聚合函数结合使用。

属性运算符

属性运算符属于节点或关系,包括:

  • 使用点运算符静态访问节点或关系的属性:.

  • 使用下标运算符动态访问节点或关系的属性:[]

  • =用于替换节点或关系的所有属性的属性替换

  • 属性变异算子+=,用于设置节点或关系的特定属性

.使用运算符静态访问节点或关系的属性

CREATE
  (a:Person {name: 'Jane', livesIn: 'London'}),
  (b:Person {name: 'Tom', livesIn: 'Copenhagen'})
WITH a, b
MATCH (p:Person)
RETURN  p.name

结果

"Jane"
"Tom"

[]使用运算符过滤动态计算的属性键

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
"Hungry Jo"

[]操作员的行为在null详述。

使用运算符 = 替换节点或关系的所有属性

CREATE (a:Person {name: 'Jane', age: 20})
WITH a
MATCH (p:Person {name: 'Jane'})
SET p = {name: 'Ellen', livesIn: 'London'}
RETURN p.name, p.age, p.livesIn

节点上的所有现有属性都替换为Map中提供的属性;即name属性从更新Jane到Ellen,age属性被删除,livesIn属性被添加。

"Ellen"
<null>
"London"

使用运算符 += 改变节点或关系的特定属性

CREATE (a:Person {name: 'Jane', age: 20})
WITH a
MATCH (p:Person {name: 'Jane'})
SET p += {name: 'Ellen', livesIn: 'London'}
RETURN p.name, p.age, p.livesIn
"Ellen"
20
"London"

节点上的属性由Map中提供的属性更新如下:name属性从Jane更新到Ellen,age属性保持不变,添加属性livesIn。

数学运算符

数学运算符包括:

  • 加法:+

  • 减法:-

  • 乘法:*

  • 除法:/

  • 模除:%

  • 幂:^

使用幂运算符 ^

WITH 2 AS number, 3 AS exponent
RETURN number ^ exponent AS result
8.0

使用一元减号运算符 -

WITH -3 AS a, 4 AS b
RETURN b - a AS result
7

比较运算符

比较运算符包括:

  • 相等:=

  • 不等:<>

  • 小于:<

  • 大于:>

  • 小于或等于:<=

  • 大于或等于:>=

  • IS NULL

  • IS NOT NULL

字符串的比较运算符包括:

  • STARTS WITH: 对字符串执行区分大小写的前缀搜索

  • ENDS WITH: 对字符串执行区分大小写的后缀搜索

  • CONTAINS:在字符串中执行区分大小写的包含搜索

比较两个数字

WITH 4 AS one, 3 AS two
RETURN one > two AS result
true

用于STARTS WITH过滤名称

WITH ['John', 'Mark', 'Jonathan', 'Bill'] AS somenames
UNWIND somenames AS names
WITH names AS candidate
WHERE candidate STARTS WITH 'Jo'
RETURN candidate
"John"
"Jonathan"

值的相等和比较

平等

Cypher 支持使用 = 和 <> 运算符来比较值。

相同类型的值只有在它们是相同值时才相等(例如3 = 3和"x" <> "xy")。

Map只有在它们将完全相同的键映射到相等的值时才相等,而List只有在它们包含相同的相等值序列时才相等(例如[3, 4] = [1+2, 8/2])。

根据以下规则,不同类型的值被认为是相等的:

  • 路径被视为交替节点和关系的列表,并且等于包含相同节点和关系序列的所有列表。

  • 使用=和<>运算符对null值进行测试时,结果总是为null。这包括null = null和null <> null。可靠地测试一个值 v 是否 null 是的唯一方法是使用特殊v IS NULL的或v IS NOT NULL相等运算符。

所有其他类型的值的组合不能相互比较。特别是,节点、关系和字符映射是彼此无法比较的。

比较无法比较的值是错误的。

值的排序和比较

比较运算符 <=, <(用于升序)和 >=, >(用于降序)用于比较值以进行排序。以下几点提供了有关如何执行比较的一些详细信息。

  • 使用数字顺序比较数值以进行排序(例如3 < 4,为真)。

  • 特殊值java.lang.Double.NaN被认为大于所有其他数字。

  • 使用字典顺序(例如"x" < "xy")比较字符串值以进行排序。

  • 比较布尔值以进行排序,使得false < true.

  • 空间值比较:

    • Point值只能在同一坐标参考系 (CRS) 内进行比较。否则,结果将为null.

    • 对于两个点a和b在同一个 CRS 内,如果a.x > b.x 和 a.y > b.y(a.z > b.z 对于3D 点),a被认为大于b 。

    • 如果a.x < b.x 和 a.y < b.y(a.z < b.z对于3D 点),a被认为小于b。

    • 如果上述情况为真,则可以比较。如果没有,则这些点被认为是不可比较的,并且它们之间的任何比较运算符都将返回null。

  • 空间值的排序:

    • ORDER BY要求所有值都是可排序的。

    • Point在数组之后和时间类型之前排序。

    • 不同 CRS 的Point按 CRS 码(SRID 字段的值)排序。对于当前支持的坐标参考系统集,这意味着顺序:4326、4979、7302、9157

    • 同一个 CRS 的Point按每个坐标值依次排序,x先,后y,最后z。

    • 请注意,此顺序与空间索引返回的顺序不同,它将是空间填充曲线的顺序。

  • 时间值的比较:

    • 时间瞬时值在同一类型中具有可比性。如果一个瞬间发生在该瞬间之前,则认为它小于另一个瞬间,如果它发生在之后,则认为它大于另一个瞬间。

    • 在同一时间点出现的即时值(但具有不同时区)不被认为是相等的,因此必须以某种可预测的方式进行排序。Cypher 规定,在时间点的主要顺序之后,即时值按有效时区偏移量排序,从西(与 UTC 的负偏移)到东(与 UTC 的正偏移)。这具有表示相同时间点的时间将按照具有最早本地时间的时间排序的效果。如果两个即时值表示相同的时间点,并且具有相同的时区偏移量,但命名的时区不同(这仅适用于DateTime,因为Time只有一个偏移量),这些值不被认为是相等的,并且按时区标识符按字母顺序排序,作为其第三排序组件。如果类型、时间点、偏移量和时区名称都相等,则值相等,并且无法观察到任何顺序差异。

  • 无法比较持续时间值,因为不知道一天、一个月或一年的长度,不知道它是哪一天、哪一个月或哪一年。由于Duration值不可比较,因此在两个Duration值之间应用比较运算符的结果null。

  • 时间值的排序:

    • ORDER BY要求所有值都是可排序的。

    • 时间实例在空间实例之后和字符串之前排序。

    • 可比较值的排序应与它们的比较顺序所暗示的顺序相同。

    • 时间瞬时值首先按类型排序,然后按类型内的比较顺序。

    • 由于无法为Duration值定义完整的比较顺序,因此我们ORDER BY专门为Duration定义了一个顺序:

      • 持续时间值是通过标准化所有组件来排序的,就好像所有年份都是365.2425天长 ( PT8765H49M12S),所有月份都是30.436875(1/12年) 天长 ( PT730H29M06S),所有天都是24小时长[ 1 ]。
  • 当一个参数是null(例如null < 3 is null )。

  • 不同类型的值排序:

    • 排序按升序,根据以下列表定义:

      • Map

      • Node

      • Relationship

      • List

      • Path

      • DateTime

      • LocalDateTime

      • Date

      • Time

      • LocalTime

      • Duration

      • String

      • Boolean

      • Number

    • 值null被认为大于任何值。

  • 复合类型值的排序:

    • 对于复合类型(例如Map和List),容器的元素会成对比较以进行排序,从而确定两种容器类型的排序。例如,[1, 'foo', 3]在[1, 2, 'bar']之前排序,因为'foo'在2之前。

链式比较操作

比较可以任意链接,例如,x < y <= z 等价于 x < y AND y <= z.

形式上,如果a, b, c, ..., y, z是表达式并且op1, op2, ..., opN是比较运算符,则a op1 b op2 c ... y opN z等价于a op1 b and b op2 c and ... y opN z。

请注意,a op1 b op2 c这并不意味着 a 和 c 之间的任何比较,因此例如x < y > z是完全合法的(尽管可能不优雅)。

MATCH (n) WHERE 21 < n.age <= 30 RETURN n
MATCH (n) WHERE 21 < n.age AND n.age <= 30 RETURN n

此语法扩展到所有相等=和不等<>比较,以及超过三个的链。

在 Cypher 中以特殊方式处理 = 和 <> 的链。
这意味着 that 1=1=true等价于 1=1 AND 1=true 而不是 (1=1)=true 或者 1=(1=true)。

a < b = c <= d <> e
a < b AND b = c AND c <= d AND d <> e

布尔运算符

布尔运算符(也称为逻辑运算符)包括:

  • 与:AND

  • 或:OR,

  • 非:XOR

  • 否:NOT

使用布尔运算符过滤数字

WITH [2, 4, 7, 9, 12] AS numberlist
UNWIND numberlist AS number
WITH number
WHERE number = 4 OR (number > 6 AND number < 10)
RETURN number
4
7
9

字符串运算符

字符串运算符包括:

  • 连接字符串:+

  • 匹配正则表达式:=~

使用正则表达式 with=~过滤单词

WITH ['mouse', 'chair', 'door', 'house'] AS wordlist
UNWIND wordlist AS word
WITH word
WHERE word =~ '.*ous.*'
RETURN word
"mouse"
"house"

时间算子

时间运算符包括:

  • 将Duration添加到时间瞬间或另一个Duration:+

  • 从时间瞬间或另一个Duration中减去Duration:-

  • 将Duration与数字相乘:*

  • 将Duration除以一个数字:/

下表显示了 - 对于每个操作和操作数类型的组合 - 每个时间运算符的应用程序返回的值的类型:

OperatorLeft-hand operandRight-hand operandType of result
+Temporal instantDurationTemporal instant
+DurationTemporal instantTemporal instant
-Temporal instantDurationTemporal instant
+DurationDurationDuration
-DurationDurationDuration
*DurationNumberDuration
*NumberDurationDuration
/DurationNumberDuration

在时间瞬间添加和减去持续时间

WITH
  localdatetime({year:1984, month:10, day:11, hour:12, minute:31, second:14}) AS aDateTime,
  duration({years: 12, nanoseconds: 2}) AS aDuration
RETURN aDateTime + aDuration, aDateTime - aDuration
1996-10-11T12:31:14.000000002
1972-10-11T12:31:13.999999998

不适用于时间瞬间的Duration组件将被忽略。例如,当将Duration添加到Date时,忽略Duration的小时、分钟、秒和纳秒(Time的行为方式类似):

WITH
  date({year:1984, month:10, day:11}) AS aDate,
  duration({years: 12, nanoseconds: 2}) AS aDuration
RETURN aDate + aDuration, aDate - aDuration
1996-10-11
1972-10-11

将两个持续时间添加到时间瞬间不是关联操作。这是因为不存在的日期被截断为最近的现有日期:

RETURN
  (date("2011-01-31") + duration("P1M")) + duration("P12M") AS date1,
  date("2011-01-31") + (duration("P1M") + duration("P12M")) AS date2
2012-02-28,2012-02-29

在另一个 Duration 中添加和减去Duration

WITH
  duration({years: 12, months: 5, days: 14, hours: 16, minutes: 12, seconds: 70, nanoseconds: 1}) as duration1,
  duration({months:1, days: -14, hours: 16, minutes: -12, seconds: 70}) AS duration2
RETURN duration1, duration2, duration1 + duration2, duration1 - duration2
P12Y5M14DT16H13M10.000000001S,P1M-14DT15H49M10S,P12Y6MT32H2M20.000000001S,P12Y4M28DT24M0.000000001S

将Duration乘以或除以数字

这些操作被简单地解释为在除法(和与分数相乘)的情况下基于单元的平均长度溢出到更小的单元的组件操作。

WITH duration({days: 14, minutes: 12, seconds: 70, nanoseconds: 1}) AS aDuration
RETURN aDuration, aDuration * 2, aDuration / 3
P14DT13M10.000000001S,P28DT26M20.000000002S,P4DT16H4M23.333333333S

Map运算符

Map运算符包括:

  • 使用点运算符通过键静态访问映射的值:.

  • 使用下标运算符通过键动态访问映射的值:[]

使用运算符通过键静态访问嵌套映射的值

WITH {person: {name: 'Anne', age: 25}} AS p
RETURN  p.person.name
"Anne"

[]使用运算符和参数通过键动态访问映射的值

可以使用参数来指定要访问的值的键:

{
  "myKey" : "name"
}
WITH {name: 'Anne', age: 25} AS a
RETURN a[$myKey] AS result
"Anne"

列表运算符

列表运算符包括:

  • 连接列表l1和l2:[l1] + [l2]

  • 检查列表中是否存在元素e l:e IN [l]

  • 使用下标运算符动态访问列表中的元素:[]

使用 + 连接两个列表

RETURN [1,2,3,4,5] + [6,7] AS myList
[1,2,3,4,5,6,7]

用于IN检查一个数字是否在列表中

WITH [2, 3, 4, 5] AS numberlist
UNWIND numberlist AS number
WITH number
WHERE number IN [2, 3, 8]
RETURN number
2
3

用于IN更复杂的列表成员操作

一般规则是,如果作为右操作数给出的列表包含与左操作数具有相同类型和内容(或值)的元素,则IN运算符的计算结果将为true。列表只能与其他列表进行比较,并且列表innerList中的元素按照从innerList中的第一个元素到innerList中的最后一个元素的升序成对进行比较。

以下查询检查列表是否是列表[2, 1]的元素[1, [2, 1], 3]:

RETURN [2, 1] IN [1, [2, 1], 3] AS inList
true

乍一看,左侧操作数和右侧操作数的内容在以下查询中似乎相同:

RETURN [1, 2] IN [1, 2] AS inList
false

以下查询可用于确定列表是否 — 例如,从labels()函数获得 — 至少包含一个元素,该元素也存在于另一个列表中:

MATCH (n)
WHERE size([label IN labels(n) WHERE label IN ['Person', 'Employee'] | 1]) > 0
RETURN count(n)

只要labels(n)返回一个Person或Employee(或两者),查询就会返回一个大于零的值。

[]使用运算符访问列表中的元素

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

[]使用运算符和参数动态访问列表中的元素

可以使用参数来指定要访问的元素的索引:

{
  "myIndex" : 1
}
WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names
RETURN names[$myIndex] AS result
"John"

在嵌套列表中使用IN和WITH

IN 可以与 [] 结合使用来测试一个元素是否存在于嵌套列表中:

{
  "myIndex" : 1
}
WITH [[1, 2, 3]] AS l
RETURN 3 IN l[0] AS result
true

注释

注释以双斜杠 // 开头并一直到行尾。评论不会执行,它们是供人类阅读的。