Neo4j之Cypher概述

第 3 章 Cypher 入门

这章的内容有些多,部分小节又会分为很多小片段,本章需要大家认真学习,重点掌握

3.1 Cypher 概述

3.1.1 Cypher是什么

Cypher 是一种声明式图数据库查询语言,它具有丰富的表现力,能高效地查询和更新图数据。对于初学者 Cypher 使用相对简单,但其功能还是非常强大,即便是非常复杂的数据库查询也能用 Cypher 简要地表达出来。这使得用户可以将精力集中在自己所从事的领域,而不用在数据库访问上花太多时间。

Cypher 查询语言设计很人性化,既适合开发人员,也适合专业的运营人员(这点尤为重要)。作为一个声明式查询语言, Cypher 专注于清晰地表达从图中检索什么,而不是怎么去检索。在这点上,与命令式的 Java 语言和脚本式的 Gremlin 语言完全不同。

Cypher 博采众长,同时也继承了已有的惯用做法。像 WHERE 和 ORDER BY 等大多数关键词均来自于 SQL 语言。而像模式匹配表达方法借鉴于 SPARQL 语言,部分聚合(Collection)语法来源于像 Haskell 和 Python 语言。

Cypher 借鉴了 SQL 语言的结构——查询可由各种各样的语句组合。语句被链接在一起,相互之间传递中间结果集。

查询语言由多种不同的语句构成,这里是一些获取图的常用语句:

  • MATCH:匹配图模式。这是从图中获取数据最常见的方法。
  • WHERE:不是独立的语句,而是 MATCH , OPTINAL MATCH 和 WITH 的一部分。用于给模式添加约束或者过滤传递给 WITH 的中间结果。
  • RETURN:定义返回的结果。

下面是一些用于更新图常用的语句:

  • CREATE(和DELETE):创建(和删除)节点和关系。
  • SET(和REMOVE):使用 SET 设置属性值和给节点添加标签,使用 REMOVE 移除它们。
  • MERGE:匹配已经存 在的或者创建新节点和模式,这对于有唯一性约束的时候非常有用。
3.1.2 模式

Neo4j 图由节点和关系构成。节点可能还有标签和属性,关系可能还有类型和属性。节点表达的是实体,关系连接一对节点。节点可以看作类似关系数据库中的表,但又不完全一样。节点的标签可以理解为不同的表名,属性类似关系数据库中表的列。一个节点的数据类似关系数据库中表的一行数据。拥有相同标签的节点通常具有类似的属性,但不必完全一样,这点与关系数据库中一张表中的行数据拥有相同的列是不一样的。

然而,节点和关系都是简单的低层次的构建块。单个节点或者关系只能编码很少的信息,但模式可以将很多节点和关系编码为任意复杂的想法。

Cypher 查询语言很依赖于模式。只包含一个关系的简单模式连接了一对节点。例如,一个人 LIVES_IN 在某个城市或者某个城市 PART_ OF 一个国家。使用了多个关系的复杂模式能够表达任意复杂的概念,可以支持各种有趣的使用场景。例如,下面的 Cypher 代码将两个简单的模式连接在一起。

(:Person) -[:LIVES_IN]-> (:City) -[:PART_OF]-> (:Country)

像关系数据库中的 SQL 一样, Cypher 是一种文本的声明式查询语言。它使用 ASCII art 的形式来表达基于图的模式。采用类似 SQL 的语句,如 MATCH 、 WHERE 和 DELETE ,来组合这些模式以表达所预期的操作。

3.1.2.1 节点语法

Cypher 采用一对圆括号来表示节点,如: ()、(foo)。下面是一 些常见的节点表示法:

()
(matrix)
(:Movie)
(matrix:Movie)
(matrix:Movie {title: "The Matrix"})
(matrix:Movie {title: "The Matrix", released: 1997})

简单的()表达了一个匿名节点。如果想在其他地方引用这个节点,可以添加一个变量,如(matrix)。此变量的可见范围局限于单个语句。

Movie 标签声明了节点的类型。 Neo4j 节点索引也会使用到标签,每个索引都是建立在一个标签和属性的组合上。节点的属性以 key/value 列表的形式存在,并外加一对大括号。属性可以存储信息和(或者)限制模式。

3.1.2.2 关系语法

Cypher 使用一对短横线(即–) 表示- -个无方向关系。有方向的关系在其中一段加上一个箭头(即<–或-->) 。方括号表达式[…]可用于添加详情。里面可以包含变量、属性和(或者)类型信息。关系的常见表达方式如下:

-->
-[role]->
-[:ACTED_IN]->
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ["Neo"]}]->

关系的方括号内的语法和语义与节点类似,定义了可以在别处引用的变量,关系的类型类似于节点的标签,关系的属性等同于节点的属性。注意,属性的值可以是数组。

3.1.2.3 模式语法

将节点和关系的语法组合在一起可以表达模式。下面是一个简单的模式:

(keanu:Person:Actor {name: "Keanu Reeves"})-[role:ACTED_IN {role: ["Neo"]}]->(matrix:Movie {title: "The Matrix"})
3.1.2.4 模式变量

为了增强模块性和减少重复, Cypher 允许将模式赋给一个变量。 这使得匹配到的路径可以用于其他表达式。如:

acted_in = (:Person)-[:ACTED_IN]->(:Movie)
3.1.3 查询和更新图

Cypher 语句既可用于查询,又可用于更新图数据。

3.1.3.1 更新语句结构

一个 Cypher 查询部分不能同时匹配和更新图数据。每个部分要么读取和匹配图,要么更新它。

如果需要从图中读取,然后更新图,那么该查询隐含地包含两个部分一第一 部分 是读取,第二部分是写入。如果查询只是读取, Cypher 将采用惰性加载(Lazy Load),事实上并没匹配模式,直到需要返回结果时才实际地去匹配。在更新查询语句中,所有的读取操作必须在任何的写操作发生之前完成。

当希望使用聚合数据进行过滤时,必须使用 WITH 将两个读语句部分连接在一起。第一部分做聚合,第二部分过滤来自第一部分的结果。 如下所示:

MATCH (n {name: 'Jokn'})-[:FRIEND]-(friend)
WITH n, count(friend) AS friendsCount
WHERE friendsCount > 3
RETURN n, friendssCount

下面是一个将聚合数据更新到图中的例子:

MATCH (n {name: 'Jokn'})-[:FRIEND]-(friend)
WITH n, count(friend) AS friendsCount
WHERE n.friendsCount = friendsCount
RETURN n.friendssCount

在内存运行的情况下,可以尽可能多地将查询部分链接在一起。

3.1.3.2 返回数据

任何查询都可以返回数据。 RETURN 语句有三个子语句,分别为 SKIP 、 LIMIT 和 ORDER BY 。
如果返回的图元素是刚刚删除的数据,需要注意的是这时数据的指针不再有效,针对它们的任何操作都是未定义的。

3.1.4 事务

任何更新图的查询都运行在一个事务中。一个更新查询要么全部成功,要么全部失败。 Cypher 或者创建一个新的事务, 或者运行在一个已有的事务中:

  • 如果运行上下文中没有事务, Cypher 将创建一个,一旦查询完成就提交该事务。
  • 如果运行上下文中已有事务, 查询就会运行在该事务中。直到该事务成功地提交之后,数据才会持久化到磁盘中去。

可以将多个查询作为单个事务来提交:

  1. 开始一个事务。
  2. 运行多个Cypher更新查询。
  3. 次提交这些查询。

**tips:**查询将这些变化放在内存中,直到整个查询执行完成。一个巨大的查询会导致 JVM 使用大量的堆空间。

3.1.5 唯一性

当进行模式匹配时, 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

查询结果如下所示:

在这里插入图片描述

在这个查询中, Cypher 确保不会包含关系 r1 和 r2 指向的同一个图关系。

然后,有时也未必一直希望这样。如果查询应当返回该用户,可以通过多个 MATCH 语句延伸匹配关系来实现,如下:

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

这里的 MATCH 语句包含一个有两条路径的单个模式,而前一个查询有两个不同的模式。

在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我真的不是cjc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值