主要学习资源有:

语法简介

Cypher 语法视频介绍

介绍 Cypher 语法有一个视频,很不错。

image-20220528003855660

image-20220528004501791

image-20220528004546321

image-20220528005741817

image-20220528005717895

image-20220528005951486

Cypher 基于 Pattern

模式(Pattern)由节点和边组成,并且可以表达简单或复杂的遍历或路径。

模式的识别是基础,而人们是擅长识别这些模式的,因此 Cypher 也基于模式来简化查询。

模式也是 AsciiArt,很直观。

注释

双斜线://

节点表示 Node

用圆括号包围一个节点:(node)

为什么是圆括号?因为看起来像一个圆圆的节点啊。

举例:

()               // 匿名节点,可指代任意节点
(p:Person)       // 变量p与标签Person
(:Technology)    // 无变量,标签Technology
(work:Company)   // 变量work与标签Company

节点变量

如果之后想引用这个节点,那么我们可以对节点分配一个变量,命名就类似编程语言的变量命名。

如果节点与返回的结果并不相关,那么可以指定匿名节点即空括号(),这意味着之后不能返回这个节点。

节点标签

节点标签可以把相似的节点聚集起来。

就像 SQL 中选择特定的某张表。

如果不指定标签,就会查询所有节点,这真的很笨重。

边表示Relationship

边在Cypher中使用箭头表示--><--

边的属性可以用箭头中的方括号表示-[:LIKES]->

无向图的边没有方向--,这就表示任一方向的关系都可以被遍历到。这对忽略方向时的查询非常有用。

如果数据是有向边,那么当查询指定了错误的方向时返回的结果为空。在这种情况下,使用无向边来查询是合适的。

边类型

边类型对边增加了语义,展示了节点之间是为何相连的。

边类型最好是有语义的,如使用动词或动作。

边变量

就像节点变量一样,当我们想引用某个边时,可以设置变量,如[r]

匿名边:----><--

有变量的边:-[rel]->-[rel:LIKES]->

注意如果没有冒号的话就不是边类型了,而成了边变量。

属性 Property

属性就是键值对,对节点和边的细节进行描述。

这些属性使用花括号表示,很像Python的字典格式,可以放在节点中,也可以放在边中。

例如:

(p:Persion {name: 'Jack'})-[rel:IS_FRIENDS_WITH {since: 2018}]->()

模式 Pattern

模式可由节点和关系组成的构建块来表示。

这些构建块可以表达简单或复杂的模式。

模式可以写作连续的路径或由逗号分隔的离散的小模式串。

例如:

(p:Person {name: "Jennifer"})-[rel:LIKES]->(g:Technology {type: "Graphs"})

关键字

要想在 Neo4j 中增删改查,有几个关键字需要整明白。

  • MATCH1:类似SELECT,查询存在的节点、边、标签、属性、模式等。
  • RETURN2:指定从查询语句中返回的结果,可以返回节点、边、属性、模式等。要想返回,你需要在 MATCH 子句中使用变量。
  • AS:对返回的变量赋予别名。
  • CREATE3:类似INSERT,插入节点、边、模式。盲插,无论存不存在,可能造成重复插入。
  • SET4:修改节点或边的属性,可增、删、改。可添加日期时间类型5的数据。第一次设置则为添加,第二/n次设置则为修改,设置为 null 则是删除属性(也可以用 REMOVE 6删除特定属性)。
  • DELETE7:删除节点、边。删除边需要先找到这条边。删除没有边连接的节点需要先找到这个节点。删除有边连接的节点,你可以分成两个步骤先删除边然后删除节点,也可以使用 DETACH DELETE 删除所有与节点相连的边之后删除节点。
  • MERGE8:先查找再操作,如果没有则添加。如果此次操作是新建ON CREATE9,如果此次操作是匹配 ON MATCH

// 添加一个类型为 Person 的节点,并用 friend 引用,然后返回结果
CREATE (friend:Person {name: 'Mark'})
RETURN friend

// 找到两个节点,并为它俩添加一条边
MATCH (jennifer:Person {name: 'Jennifer'})
MATCH (mark:Person {name: 'Mark'})
CREATE (jennifer)-[rel:IS_FRIENDS_WITH]->(mark)

// 创建两个节点,并为这两个节点连接一条边。这会重复添加!
CREATE (j:Person {name: 'Jennifer'})-[rel:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})

// 找到一个节点,并添加一条属性,使用变量 p 引用这个节点,然后返回结果。重复使用该语句会更新属性,而不是重复添加。
MATCH (p:Person {name: 'Jennifer'})
SET p.birthdate = date('1980-01-01')  // 这里使用了 date 函数
RETURN p

// 找到一条边,并删除这条边
MATCH (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})
DELETE r

// 删除一个节点,这个节点没有任何边与之相联
MATCH (m:Person {name: 'Mark'})
DELETE m

// 找到一个节点,并删除这个节点及其所有边
MATCH (m:Person {name: 'Mark'})
DETACH DELETE m

//delete property using REMOVE keyword
MATCH (n:Person {name: 'Jennifer'})
REMOVE n.birthdate

//delete property with SET to null value
MATCH (n:Person {name: 'Jennifer'})
SET n.birthdate = null

图数据库的属性的删除中,有一种方法是 SET n.birthdate = null,为什么这么做行?我们知道关系型数据库中这样做是把该字段的值置为 null ,而图数据库呢?图数据库只存储对数据有意义的属性和值,这意味着节点和边可有不同类型和不同数量的属性10

// 找到一条边,并用变量 rel 引用,然后修改 rel 边的属性,最后返回这条边(只会显示属性),如果要显示节点,则需要返回 p,rel,c
MATCH (:Person {name: 'Jennifer'})-[rel:WORKS_FOR]-(:Company {name: 'Neo4j'})
SET rel.startYear = date({year: 2018})
RETURN rel

// 返回一个 Person 节点
MATCH (p:Person)
RETURN p
LIMIT 1

// 返回所有的具有 name为'Tom Hanks' 属性的 Persion 节点
MATCH (tom:Person {name: 'Tom Hanks'})
RETURN tom
                    
// 返回所有的 Tom Hanks 执导的电影名称
MATCH (:Person {name: 'Tom Hanks'})-[:DIRECTED]->(movie:Movie)
RETURN movie.tilte

// cleaner printed results with aliasing
MATCH (tom:Person {name:'Tom Hanks'})-[rel:DIRECTED]-(movie:Movie)
RETURN tom.name AS name, tom.born AS `Year Born`, movie.title AS title, movie.released AS `Year Released`

避免重复数据

之前用 CREATE 的时候可能产生重复数据,解决的办法之一是使用 MERGE

MERGE 做的是 select or insert 的事,它首先检索数据存在与否,如果存在则直接返回(或直接做修改),否则先创建数据。

// 查找一个节点,如果不存在则插入
MERGE (mark:Person {name: 'Mark'})
RETURN mark

// 查找一条边,如果不存在则插入
MATCH (j:Person {name: 'Jennifer'})
MATCH (m:Person {name: 'Mark'})
MERGE (j)-[r:IS_FRIENDS_WITH]->(m)  // 为什么只在这里使用 MERGE ?
RETURN j, r, m

// 以下语句,会创建重复的两个节点!
MERGE (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})
RETURN j, r, m

// 如果新建模式则设置 since 属性,如果匹配模式则修改 updated 属性
MERGE (m:Person {name: 'Mark'})-[r:IS_FRIENDS_WITH]-(j:Person {name:'Jennifer'})
  ON CREATE SET r.since = date('2018-03-01')
  ON MATCH SET r.updated = date()
RETURN m, r, j

MERGE 会查找整个 Pattern 模式存不存在,如果模式不存在(包括节点、边、属性),就会新建10。 所以,你需要先查找已经存在的数据,然后使用 MERGE 来创建你可能会创建的数据。 也许,你想在新建模式的时候初始化一些属性,或者想匹配模式的时候修改一些属性,那么在这种情况下,可使用 ON CREATEON MATECH 结合 SET。【如果创建了模式,您想初始化某些属性,如果仅匹配,则更新其他属性】