Neo4j - Ep2丨学习记录
前言:
Abstract:本文的主要内容是图数据库的入门以及Cypher语言的基础知识。
笔者近日在学习有关知识图谱Knowledge Graph的相关内容。
Neo4j是项目所需的一款功能强大的应用,特此来学习之,并记录于本文。
笔者是AI领域的小白,作为初学者,文章中难免会有出错或者不恰当的部分,烦请读者朋友们指出(在以下任意平台)。
注意:本文不是教程,只是个人学习的记录和心得,可能会对你有帮助,建议配合官方文档一起学习!
官方文档链接:graphacademy.neo4j.com/courses/cyp…
再注:原文是英文,若有较好的英文阅读能力可以直接读,本文是对原文中重要的内容进行了翻译,以及加上了笔者自己的理解。
从Neo4j读取数据:
Cypher语言可以帮助在图中检索数据,包括节点,关系(也就是边),还可以过滤查询Filter queries。
Cypher简介:
Cypher是一种为图而设计的查询语言。
一个很重要的概念是:Cypher的模式pattern:
- 节点由圆括号表示
()
. - 使用冒号来表示标签
(:Person)
. - 节点之间的关系用两个破折号表示,
(:Person)--(:Movie)
. - 使用大于或小于符号
<
或>
表示关系的方向,(:Person)->(:Movie)
. - 关系的类型是用两个破折号之间的方括号写的
[
and]
,[:ACTED_IN]
- 在语音气泡中绘制的属性类似
JSON
的语法指定;- Neo4j中的属性是
key-value对
,{name: 'Tom Hanks'}
.
- Neo4j中的属性是
Example:
(m:Movie {title: 'Cloud Atlas'})<-[:ACTED_IN]-(p:Person)
此模式中的两个节点类型是Movie和Person。
Person节点与Movie节点有直接的ACTED_IN关系。
这个模式中的特定Movie节点由值为Cloud Atlas的title属性过滤。
这个图形代表了所有在电影 Cloud Atlas 中扮演角色的人。
检索 - MATCH:
那么,Cypher是怎么工作的呢?
Cypher的工作原理是匹配数据中的模式;
我们使用MATCH
关键字从图中检索数据;
可以认为MATCH
类似于SQL
语句中的FROM
。
例如,如果我们想要在图中找到一个Person,我们将MATCH
一个带有标签的单个节点的模式:Person
-前缀为冒号。
假设我们想从图中检索所有Person节点;
我们可以通过在冒号前放置一个值来赋值一个变量;
使用变量p
表示从图中检索到的所有Person节点,并使用RETURN
返回它们。
就像这样:
(注意,SHIFT + ENTER
可以换行输入,这个界面在右下角可以点开)

这太酷了,简直符合我对CybercCypher的想象!
我们还可以看到返回的Text,具体来说,该查询返回图中带有Person标签的所有节点。可以使用图视图或表视图查看返回的结果。在选择表视图时,还可以看到返回的节点的属性。

如果我们要具体指定地查询某一个人,应该如何操作呢?
事实上,就像这样:

更进一步地,如果我只想知道他的出生年份,如何查询呢?
很简单,只需要RETURN p.born
就可以了,这里就不再演示了。
检索 - WHERE:
筛选查询的另一种方法是使用WHERE
子句,而不是用大括号内联指定属性值。
Example:

一般来说,WHERE
在今后会更常用,因为其功能更强大。
Example:

使用与编写习惯:
在Cypher中,标签、属性键和变量是区分大小写的。Cypher关键字不区分大小写。
一言以蔽之,就是自定义的东西区分大小写。
推荐方式:
- 标签:
CamelCase
- 属性键和变量:
camelCase
- 关键字:
UPPERCASE
随后,你可以在网站中的课后习题中进行练习,那都是一些比较简单和基础但是不可谓不重要的题目。
寻找关系:
扩展MATCH
子句中的模式,以遍历具有ACTED_IN
类型的所有关系到任何节点。
Domain Model显示ACTED_IN
关系从Person
节点向外延伸,因此我们可以在模式中添加方向,通常将此称为遍历traversal。
MATCH (p:Person {name: 'Tom Hanks'})-[:ACTED_IN]->(m)
RETURN m.title
当然,我们也可以进行一些指定:
MATCH (p:Person {name: 'Tom Hanks'})-[:ACTED_IN]->(m:Movie)
RETURN m.title
过滤查询:
Example:
此查询检索Person节点和Movie节点,该人员在2008或2009年发布的电影中扮演角色。
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE m.released = 2008 OR m.released = 2009
RETURN p, m

按节点标签进行过滤:
Solution1:
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE m.title='The Matrix'
RETURN p.name
Solution2:
MATCH (p)-[:ACTED_IN]->(m)
WHERE p:Person AND m:Movie AND m.title='The Matrix'
RETURN p.name
使用范围进行过滤:
a <= XX <= b
Example:
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE 2000 <= m.released <= 2003
RETURN p.name, m.title, m.released
根据属性的存在进行筛选:
IS NOT NULL
Example:
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name='Jack Nicholson' AND m.tagline IS NOT NULL
RETURN m.title, m.tagline
按部分字符串筛选:
START WITH
END WITH
CONTAINS
MATCH (p:Person)-[:ACTED_IN]->()
WHERE p.name STARTS WITH 'Michael'
RETURN p.name
大小写转换:
toLower(p.name)
toUpper(p.name)
根据图中的模式进行过滤:
假设你想找出所有的,写过一部电影但没有导演这部电影的人。
MATCH (p:Person)-[:WROTE]->(m:Movie)
WHERE NOT exists( (p)-[:DIRECTED]->(m) )
RETURN p.name, m.title
使用列表过滤:
如果你有一组想要测试的值,你可以将它们放在列表中,或者可以使用图中的现有列表进行测试。
Cypher列表是方括号内以逗号分隔的值集。
可以在WHERE
子句中定义列表。在查询期间,图形引擎将每个属性与列表中的值进行比较。您可以在列表中放置数字值或字符串值,但通常情况下,列表的元素是相同类型的数据。如果您正在测试字符串类型的属性,那么列表中的所有元素都将是字符串。
在这个例子中,我们只想检索出生在1965、1970或1975年的人的Person
节点:
MATCH (p:Person)
WHERE p.born IN [1965, 1970, 1975]
RETURN p.name, p.born
同样的,我们也可以添加一些条件:
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE 'Neo' IN r.roles AND m.title='The Matrix'
RETURN p.name, r.roles
节点或关系具有哪些属性:
使用key()进行查询
MATCH (p:Person)
RETURN p.name, keys(p)

图中存在什么性质:
CALL db.propertyKeys()

同样地,你可以在网站中的课后习题中进行练习,那都是一些比较简单和基础但是不可谓不重要的题目。
向Neo4j写入数据:
因为这主要是语法的部分,并没有什么特别难理解的东西需要进一步的解释,所以,这一部分更推荐动手实践,
还是挑重点来说,主要内容包括:
使用
MERGE
在图中创建节点;使用
MERGE
在图中创建关系;创建、更新和删除图中节点和关系的属性;
根据图中的内容执行有条件的
MERGE
处理;从图中删除节点和关系。
创建节点:
MERGE (p:Person {name: 'Michael Caine'})
另外,可以使用CREATE
而不是MERGE
创建节点。
使用CREATE
的好处是,它在添加节点之前不会查找主键。
如果您确定数据是干净的,并且希望在导入过程中提高速度,则可以使用CREATE。
创建关系:
如果Person和Movie节点都已经存在,我们可以在创建它们之间的关系之前使用MATCH
子句找到它们。
MATCH (p:Person {name: 'Michael Caine'})
MATCH (m:Movie {title: 'The Dark Knight'})
MERGE (p)-[:ACTED_IN]->(m)
MERGE
的作用是创建图中不存在的节点或关系。
MERGE (p:Person {name: 'Emily Blunt'})-[:ACTED_IN]->(m:Movie {title: 'A Quiet Place'})
RETURN p, m
设置属性:
有两种办法可以进行属性的设置:
- 作为
MERGE
子句的一部分; - 使用
SET
关键字来引用节点或关系。
具体来说,我们给出两个样例:
MERGE (p:Person {name: 'Michael Caine'})
MERGE (m:Movie {title: 'Batman Begins'})
MERGE (p)-[:ACTED_IN {roles: ['Alfred Penny']}]->(m)
RETURN p,m
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'Michael Caine' AND m.title = 'The Dark Knight'
SET r.roles = ['Alfred Penny']
RETURN p, r, m
注意:SET
中的[]
有时不是必要的。
如果需要设置多个属性,请使用逗号分隔。
SET r.roles = ['Alfred Penny'], r.year = 2008
更新属性:
除此之外,SET
还可以用于更新属性:
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'Michael Caine' AND m.title = 'The Dark Knight'
SET r.roles = ['Mr. Alfred Penny']
RETURN p, r, m
像这样直接覆盖就可以了
删除属性:
至于删除属性,我们可以用REMOVE
:
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'Michael Caine' AND m.title = 'The Dark Knight'
REMOVE r.roles
RETURN p, r, m
还可以用SET xxx = null
MATCH (p:Person)
WHERE p.name = 'Gene Hackman'
SET p.born = null
RETURN p
神奇的自定义MERGE:
// 查找或创建一个具有此名称的人
MERGE (p:Person {name: 'McKenna Grace'})
// 如果节点是在此查询期间创建的,则只设置'createdAt'属性
ON CREATE SET p.createdAt = datetime()
// 如果之前创建了节点,则只设置'updatedAt'属性
ON MATCH SET p.updatedAt = datetime()
// 设置'born'属性
SET p.born = 2006
RETURN p
类似地,可以用逗号分割多个属性。
MERGE处理:
使用MERGE
来创建节点或关系:
// 查找或创建一个具有此名称的人
MERGE (p:Person {name: 'Michael Caine'})
// 用这个标题找到或创建一个电影
MERGE (m:Movie {title: 'The Cider House Rules'})
// 查找或创建两个节点之间的关系
MERGE (p)-[:ACTED_IN]->(m)
下面是在查询处理器中发生的事情:
Neo4j将尝试查找名称为Michael Caine的Person节点。
如果不存在,则创建节点。
然后,它将尝试在图中展开该节点的ACTED_IN关系。
如果这个节点中有任何ACTED_IN关系,它将查找标题为“the Cider House Rules”的电影。
如果Movie没有节点,则创建该节点。
如果两个节点之间没有关系,则在它们之间创建ACTED_IN关系。
删除数据:
前文提到的"删除属性"是删除数据的一个子集。
还可以包括:节点、关系、属性、标签。
要删除数据库中的任何数据,必须先检索它,再删除它。
MATCH (p:Person)
WHERE p.name = 'Jane Doe'
DETACH DELETE p
这里仅给出一个例子,其他的类似。
转载自:https://juejin.cn/post/7217346593501757497