大数跨境

关于图数据库(Neo4j)你应该知道的一切

关于图数据库(Neo4j)你应该知道的一切 国科慧安
2023-11-17
3
导读:图数据库(Graph Database)是一种非关系型数据库,它使用图结构来存储和查询数据。开源图数据库的代

图数据库(Graph Database)是一种 非关系型数据库,它使用 图结构来存储和查询数据。开源图数据库的代表产品是 Neo4j,今天就以 Neo4j 为例,介绍一下图数据库的基本概念、设计模式、查询方法以及部分最佳实践。

首先 Neo4j 是一个图数据库管理系统,应该是知名度最广的开源图数据库,由「Neo4j, Inc.」公司开发。

图数据库和 Neo4j 由于图数据库应用没有关系数据库广泛,造成同类产品比较少, Neo4j 又占据了开源和先发的优势, 2010 年 2 月就发布了 1.0 版本,导致很长一段 时间内,说起图数据库,大家只知道 Neo4j。

从我们之前维护的数据库知识图谱中可以看到,图数据库分类下还是有很多产品的:

图数据库(排名不分先后)

名字由来

Google Group 上有一个帖子问『Neo4j 这个名字是是什么意思』, 4j 肯定是 『for Java』的意思, Neo 有人说可能是参考黑客帝国的角色 Neo。

I think "Neo" is a reference to the Matrix character.

也有人说是「物之新生」或者「物联引擎」:

"Neo" has also been transcribed to "New Energy for Objects" and "Network Engine for Objects" :)

我也只是好奇八卦一下,名字怎么来的并不影响咱们后面的使用。

Neo4j vs AuraDB vs Cypher

「Neo4j Inc」 公司的数据库产品叫 《Neo4j Graph Database[1]》也就是我们常说的 Neo4j 数据库, 也叫 Neo4j DBMS

Neo4j DBMS

除了 Neo4j 数据库,Neo4j 公司还开发了新的产品 《Neo4j AuraDB[2]》。这是一个完全托管的云服务,相当于 Neo4j DBMS 的 SaaS 版本。

Neo4j AuraDB

Neo4j 公司另外一个最重要的产品就是 《Cypher[3]》, 这是 Neo4j 数据库的查询语言,他的作用就相当于 SQL 之于关系数据库。

Cypher

下载安装

如果大家想在本地开发测试使用 Neo4j 那就不要在官网点击「免费试用」, 直接打开Neo4j 下载中心[4], 点击下载即可:

Neo4j 下载中心

不过注意, Neo4j Desktop 虽然把所有的工具都包含进去了,非常方便,但是它并不适合生产环境使用

Neo4j Desktop is not suited for production environments.

安装过程我就不说了,选择合适的版本一路点下去就行。安装之后就有 Neo4j 程序的启动图标。

生产环境 生产环境安装 Neo4j 我建议使用容器安装,把数据文件挂载出来,这样的话安装和运维都比较简单,而且稳定性也高。可以参考 Neo4j 容器安装文档 [5]来进行操作。

软件使用

打开 Desktop 就可以看到应用程序界面:

左上角的三个图标分别是「项目」、「数据库」和「应用」。

第一个功能是「项目」,Neo4j Desktop 安装好之后会自带一个默认的样例项目,里面有一个电影数据库。

Desktop 样例项目

点击启动按钮可以启动这个数据库,启动之后我们看到数据库的状态是 Active

启动电影样例数据库

点击右上角的 『Open』 按钮,会默认新窗口打开 Neo4pj Browser,这是一个 GUI 的客户端工具,你可以通过它查看数据库链接信息、服务状态,还可以执行命令。

我们先从左侧收藏里面执行下 Hello World,然后返回数据:

命令如下,你也可以拷贝或者手输命令在执行框里面点击执行。具体 Cypher 代码语法含义我们等到后面讲 Cypher 语言的时候再讲。

// Hello World!
CREATE (database:Database {name:"Neo4j"})-[r:SAYS]->(message:Message {name:"Hello World!"}) RETURN database, message, r

上述代码创建了一个具有 Database 标签的节点,一个 Message 标签的节点,以及一个 SAYS 类型的边,并返回。

语法解释 () 表示一个节点, ()-[]->() 表示一个边

: 冒号前面表示 变量,冒号后面来表示  节点标签 或者  边类型

图数据库

为什么用图数据库

现实中的很多场景天然就是以图的概念存储的,比如人和人之间的关系,每个人有自己的定义和属性,人与人之间会有各种可能的关系。

任何人之间的关系

这样的场景用传统的关系型数据库存储的话,无论是从数据结构设计,还是最终的查询性能上都有很多的损耗,此时图数据库就能很好的满足这些场景。

图数据库的优点 图数据库可以在大图中深度和广度的 恒定时间遍历,在  浏览深层结构 时架构的优越性表现尤其明显。图数据库还可以 灵活动态的增加新的关系和属性,并且没有太多的维护和性能损耗。

图数据库的组成

像我们之前《构建个人知识图谱》文章里提到的一样,图数据库有三个概念来表示数据:节点关系属性。节点和关系又组成了经典的三元组关系:节点-关系-节点,节点和关系上都可以有自己的属性。

图数据库的基本构成(图片来自 Neo4j 网站)

节点

节点可以用 labels 标记, 比如动物软件公司网站书籍 等都可以作为 「标签」,在《构建个人知识图谱》系列中我们称之为「类型」。。

不同的标签在 Neo4j 的工具会被显示成不同的颜色。

节点可以保存任意数量的属性,当然也可以没有属性。比如张三这个节点,可能有 姓名性别名族年龄等众多属性。

作为数据库节点还可以有一些约束性质的属性。比如 姓名不能为空身份证号不能重复等。

关系

Neo4j 的关系是有方向的,用于连接两个节点。关系也可以有自己的类型属性

每个节点的关系数量也是不受限制的,而且我们还可以通过正向或者逆向的方向来查找节点。

数据建模

我们动手开始所有项目和数据库之前,第一件事情肯定是建模。所谓建模就是描述清楚你要做事情的结构, 有哪些数据、数据之间的结构是什么。对这些模型胸有成竹,后面做事情才可以游刃有余。

白板数据建模法

Neo4j 官方推荐白板建模法,白板建模法:就是直接在白板(黑板当然也行)上绘制想要的模型和关系,然后照搬的图数据库中即可。

比如我们想围绕李小龙先生进行一个图谱数据建设,第一步就可以列出实体:

我后面直接用绘图软件画图来模拟白板。

绘制实体节点

然后绘制好连线,可能是这样子:

绘制节点之间的关系

一般来说,主要的连线在白板上绘制实体的时候已经绘制好了。

下一步,添加标签和节点属性,我们用不同颜色表示不同类型的节点(标签),一个节点可能有多种类型标签, 同时完善节点和关系的属性,当然别忘了关系也有自己的关系类型哦。

标记节点属性

最后一步就是把我们刚刚梳理的关系原样录入图数据库了。

建模步骤

我们再画一个例子,一步步看下怎么样从零开始图数据库的建模。

场景描述

首先我们描述下我们的需求,这次我们换个需求,关注下西游记:

金角大王和银角大王两个妖怪是兄弟俩,他们都想吃唐僧这个和尚的肉。

提取节点

比如可以从上面的场景描述中提取如下节点:

  • • 金角大王

  • • 银角大王

  • • 唐僧

如何识别节点 场景中的 每一个实体都是一个节点,比如 金角大王银角大王这两个 妖怪唐僧 是个  和尚妖怪以及 和尚这个 职业,在我们的场景中更偏向是一种类型,这类节点、和类型(/属性)定位不清楚的 名词否作为节点我们后面单独讨论。

提取节点标签

前面提到,一个节点可能有多个标签,这些标签可以为节点进行分类或分组。比如按照对按照职业或者身份进行分组,可能有「教师」、 「学生」、「演员」、「工程师」、「历史学家」等等很多标签,同时一个人也可以兼顾不同的身份。

金角大王和银角大王两个妖怪是兄弟俩,他们都想吃唐僧这个和尚的肉。

这样的话,上面场景我们可以提取出如下标签:

  • • 妖怪

  • • 和尚

为什么使用标签 在图数据库中,标签就相当于一个 集合,我们在查询的时候可以快速使用标签类划分查询范围,让查询更容易编写以及更加高效。通常情况下,我们的查询也都是在集合内,而不是整个图。

定义关系

现在我们有了数据主体,但是这些主体目前还是孤零零的个体,因为还缺少了图数据库中的一个重要部分:『关系』。

关系允许我们链接两个节点,它有一个源节点、带箭头的方向以及一个目标节点,同时关系也有自己的名字(动作),以及他们自己的属性。

金角大王和银角大王两个妖怪是兄弟俩,他们都想吃唐僧这个和尚的肉。

在上面这个场景中我们可以找到关系:

  • • 金角大王和银角大王是兄弟

  • • 他们想吃唐僧

「师兄弟」和「想吃唐僧」这两个动作就是我们说的关系了。

定义属性

简单来说,我们已经完成了图数据库的定义,因为画出来的图已经有模有样了。但是有时候为了存储更多的信息,更准确的描述实体,我们往往还需要定义属性。

属性是可以存储在节点或关系上的数据的名称/值对。常见的数据类型都可以作为属性值:

  • • 字符

  • • 整数、小数

  • • 布尔

  • • 日期和时间

我们对于节点本身的任何疑问都可以变成属性来设计:

  • • 金角大王几岁了

  • • 银角大王身高多少

  • • 金角大王的真身是什么

  • • 唐僧是男是女

  • • 唐僧多少斤

  • • 唐僧生日是哪天

  • • 唐僧什么时候当和尚的

  • • ...

只要你有问有答,他就可以作为一个属性。

创建模型

创建模型需要使用 Cypher 语句,刚刚的西游记三人组我们使用 MERGE 字据来创建数据模型。在 Neo4j Browser 中运行以下代码:

MERGE (j:Monster {name: '金角大王'})
    ON CREATE set j.age = 3100
MERGE (y:Monster {name: '银角大王'})
  ON CREATE set y.age = 2800
MERGE (t:Monk {title: '唐僧'})
  ON CREATE set t.height = 182
MERGE (j)-[rel1:IS_BROTHER]->(y)
  ON CREATE SET rel1.since = '-2023'
MERGE (j)-[rel2:WANT_EAT]->(t)
  ON CREATE SET rel2.desire = 4, rel2.possibility = 0
MERGE (y)-[rel3:WANT_EAT]->(t)
  ON CREATE SET rel3.desire = 3, rel3.possibility = 0

语法解释 MERGE ... ON CREATE ... 表示查找节点,如果不存在则创建并设置属性

可以看到提示创建成功:

节点和关系创建成功

接着我们执行查询验证下:

// Get some data
MATCH (n1)-[r]->(n2) RETURN r, n1, n2 LIMIT 25

语法解释 MATCH ()-[]->() RETURN ... 表示查找所有关系,并返回关系中的节点和边

可以看到查询结果:

查询结果

点击「金角大王」节点,可以看到节点标签和属性(其他节点以同样):金角大王是一个 Monster,年龄是 3100 岁,名字叫金角大王

节点标签和属性

图数据的删除 因为 Neo4j  不允许出现损坏的边,也就是不能允许边只有一个端点。所以我们再删除数据的时候必须 先删除边,再删除节点

我们先删除妖怪想吃唐僧 这些边:

MATCH (n:Monster)-[r:WANT_EAT]->() 
DELETE r

提示成功删除两条边:

然后删除唐僧这个和尚,执行下面语句:

MATCH (n:Monk {title: '唐僧'})
DELETE n
唐僧删除成功

以及兄弟这条边:

MATCH (n:Monster)-[r:IS_BROTHER]->() 
DELETE r

删除所有妖怪:

MATCH (n:Monster)
DELETE n

中文标签

我们刚才用 Monk Moster WANT_EAT IS_BROWSER 这些英文单词来表示节点和边,有人可能耗时是不是标签只能用英文?

当然不是,中文标签 Neo4j 也是支持的。

用英文标签纯粹是为了在写查询和程序的时候可以不切换输入法,并且大小写可以区分边和、节点。

我们改一下建模语句,先创建节点河边:

MERGE (j:妖怪 {姓名: '金角大王'})
  ON CREATE set j.年龄 = 3100
MERGE (y:妖怪 {姓名: '银角大王'})
  ON CREATE set y.年龄 = 2800
MERGE (t:和尚 {姓名: '唐僧'})
  ON CREATE set t.身高 = 182
MERGE (j)-[rel1:是兄弟]->(y)
  ON CREATE SET rel1.自从 = '-2023'
MERGE (j)-[rel2:想吃]->(t)
  ON CREATE SET rel2.程度 = 4, rel2.可能性 = 0
MERGE (y)-[rel3:想吃]->(t)
  ON CREATE SET rel3.程度 = 3, rel3.可能性 = 0

然后查询返回:

// Query
MATCH (n1)-[r]->(n2) RETURN r, n1, n2 LIMIT 25
完全中文的节点

但是这样有一个问题,Neo4j 不知道哪个节点是节点名称,所以建议 title 和 name 属性使用英文,其他的属性可以根据需要使用中文或者英文。当然你也可以在 Neo4j Browser 里面进行设置节点名称使用哪个属性。

模型设计

我们熟悉了基本的建模流程之后,再回来考虑刚刚抛出的问题:节点上的内容应该怎么建模?

我们前面有一个例子是说「妖怪」和「和尚」这两个身份,当时我们是使用标签来表示的。其实还有两种表示方法:使用属性节点

使用属性表示的时候,他么都有一个统一的属性名字在区分,我们再扩展一下身份,唐僧不仅是谁和尚还是人,看看怎么表示:

使用属性表示身份

当然也可以用节点来表示:

使用节点表示身份

这三种方式没有优劣,最终还是看你对这些数据的使用和组织方式,怎么维护和查询方便就怎么定义。

复杂的数据结构

看到这里,你可能觉得你已经掌握了 Neo4j 图数据库的建模,足矣应对你的使用需求。

大多数时候是这样的,但是我还是有几个小技巧来教给你。

超边和中间点

还是拿西游记中金角大王和唐僧的故事来举例,如果我们要查询下他们什么时候初次见面的怎么办?

这个时候我们就可以用「超边」或者说是「中间节点」这个技术来进行建模。

使用中间节点进行建模

日期事件

我们扩展一下,这个中间节点不只有一次,或者是周期性发生的,比如学生每个学期的开学、打工人每天的打卡, 西游记里面唐僧的十次转世投胎,而对于「开学」、「打开」、「转世」这些事情有公共的属性,但是每次发生又有独立的属性。

此时我们可以把这个事件本身作为一个节点,每次事件发生也作为一个节点,就既能满足通用型查询、又能满足个性事件查询。

索引

图数据库和关系数据库一样也有索引的概念。合理的运用索引能很好的提升搜索性能。Neo4j 可以为节点和边创建索引,支持下面索引类型:

  • • 范围索引

  • • Lookup 索引

  • • 文本索引

  • • 点索引

  • • 全文索引。

对索引有兴趣的可以查看官方的 索引和搜索性能[6]文档。

结语

图数据库很强大,我们做设计的时候对其基本概念有一个完整的了解很有必要,了解了这些之后再我们应用的时候一些更高级的概念时, 结合我们之前的工程知识就变得信手拈来了, 比如 Cypher 查询、子查询、条件匹配、函数的使用、查询调优等等。

最后希望大家都能在图数据库的世界里尽情遨游。

引用链接

[1] Neo4j Graph Database: https://neo4j.com/product/neo4j-graph-database/
[2] Neo4j AuraDB: https://neo4j.com/cloud/platform/aura-graph-database/
[3] Cypher: https://neo4j.com/product/cypher-graph-query-language/
[4] Neo4j 下载中心: https://neo4j.com/download/
[5] Neo4j 容器安装文档: https://neo4j.com/docs/operations-manual/current/docker/introduction/
[6] 索引和搜索性能: https://neo4j.com/docs/cypher-manual/current/indexes-for-search-performance/


【声明】内容源于网络
0
0
国科慧安
关注安全与可靠性行业动态,提升国内安全与可靠性设计评价水平,打造尖端安全与可靠性软件,提供优质安全与可靠性设计评价服务。
内容 38
粉丝 0
国科慧安 关注安全与可靠性行业动态,提升国内安全与可靠性设计评价水平,打造尖端安全与可靠性软件,提供优质安全与可靠性设计评价服务。
总阅读15
粉丝0
内容38