图数据库基础
什么是图数据库
图数据库是图数据库管理系统的简称,使用图形化的模型进行查询的数据库,通过节点、边和属性等方式来表示和存储数据,支持增删改查(CRUD)等操作。图数据库一般用于OLTP系统中,提供在线事务处理能力。与图数据库对应的是图计算引擎,一般用于OLAP系统中,提供基于图的大数据分析能力。
图数据库是NoSQL的一种,除此之外还有键值数据库,内存数据库,文档数据库,搜索数据库。
历史
从数据科技(DT)、数据处理技术发展的趋势来看,过去的40年间,我们经历了从Data到Big Data 到Fast Data到Deep Data的四个阶段。
1980-2010年间的关系型数据库主导的阶段;
2010-2020年间的大数据与快数据主导的云计算&大数据时代;
而未来的10年(2020-2030)则可以预见的被认为是图计算、图数据库的时代。
这是由商业驱动的本质来决定的,当企业IT信息化已经基本完成后,再向前就是企业的全面智能化,而智能化时代的核心技术就是可以处理高维数据关联关系的图数据库或图计算与存储引擎,低维的SQL类型的数据库注定会逐步消亡。
知名信息咨询公司Gartner在2019年11月和2020年6月的两份关于数据与分析科技(Data & Analytics Technology Trends)的报告中,明确的提出了图分析(Graph Analytics,如下图所示)作为10大核心科技发展趋势之一,且其所代表的细分市场以年复合增长率100%的速度持续增长,预计到2023年,30%的BI(商务智能、商业决策)会通过图分析与计算(既图数据库系统)来完成。
图数据库的特点
图数据库的的所有特点都是相对于传统数据库而言的,尤其是关系型数据库。简单而言,图数据库的最大特点有3个:
1.高维
2.高性能
3.高效率
相比于传统的关系型数据库中的关系表(二维表),图数据库采用的是可描述复杂关联关系的高维拓扑结构,既图论的理念,这也是图数据库(Graph Database)名字的源头。高维的数据关联关系并不意味着性能降低、效率降低,恰恰相反,图数据库中的高维关系的构建只依赖两大类最基础的数据类型:顶点与边,我们也通常称作实体与关系。用图数据库可以简单、高效、自由,并且非常自然的表达真实世界中的关联关系。这种100%还原世界的能力,让图数据库比关系型数据库或其它类型的数据库或大数据处理框架可以更加快速、深度、准确的挖掘事物间的关联关系,很多时候这种效率与性能的提升是指数级的,成千上万倍或者更多(随着搜索深度的增加,相对的性能与效率的提升会呈现指数级的差异增大)。
图数据库术语
GQL
Graph Query Language,即图数据库的查询与管理语言。在SQL标准已经发展40年后才迎来了数据库领域的第二个标准,这就是GQL,预计GQL的第一版国际标准在2022年中发布。
点(node)
称之为顶点(Vertex)或点(node),也可以称作实体(Entity)。
边(edge)
连接两个点(node)的边,分为无方向和有方向(见下面"方向"的解释)。在知识图谱范畴内也常被称作关系(relation、relationship)。
路径(path)
多个相连的边(包括边连接的点)构成的一个序列称为一条路径,例如a–b–c,单独的一条边也是一个路径。
子图(subgraph)
子图相对于全图(完整图数据集合)而言,是由全图的部分顶点和边组成,例如每一次查询结果可以作为一张子图。
属性(property)
图系统中的数据属性,主要分为点属性(node property)和边属性( edge property)。
实例(instance)
实例通常指在图数据库的底层系统架构中的一个相对独立且完整的功能集合的实体,例如计算实例、存储实例、管理实例等。例如一个集群化部署的图数据库系统可能由3台实例构成,每台实例可以有各自的角色分配(管理、计算、存储、同步等等)。
GraphQL语法
GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。
一个 GraphQL 服务是通过定义类型和类型上的字段来创建的,然后给每个类型上的每个字段提供解析函数。例如,一个 GraphQL 服务告诉我们当前登录用户是 me,这个用户的名称可能像这样:
type Query {
me: User
}
type User {
id: ID
name: String
}
一并的还有每个类型上字段的解析函数:
function Query_me(request) {
return request.auth.user;
}
function User_name(user) {
return user.getName();
}
一旦一个 GraphQL 服务运行起来(通常在 web 服务的一个 URL 上),它就能接收 GraphQL 查询,并验证和执行。接收到的查询首先会被检查确保它只引用了已定义的类型和字段,然后运行指定的解析函数来生成结果。
查询和变更
简单而言,GraphQL 是关于请求对象上的特定字段。我们以一个非常简单的查询以及其结果为例:
{
hero {
name
}
}
{
"data": {
"hero": {
"name": "R2-D2"
}
}
}
你立即就能发现,查询和其结果拥有几乎一样的结构。这是 GraphQL 最重要的特性,因为这样一来,你就总是能得到你想要的数据,而服务器也准确地知道客户端请求的字段。
对了,还有一点 —— 上述查询是可交互的。也就是你可以按你喜欢来改变查询,然后看看新的结果。尝试给查询中的 hero 对象添加一个appearsIn 字段,看看新的结果吧。
在前一例子中,我们请求了我们主角的名字,返回了一个字符串类型(String),但是字段也能指代对象类型(Object)。这个时候,你可以对这个对象的字段进行次级选择(sub-selection)。GraphQL 查询能够遍历相关对象及其字段,使得客户端可以一次请求查询大量相关数据,而不像传统 REST 架构中那样需要多次往返查询。
{
hero {
name
# 查询可以有备注!
friends {
name
}
}
}
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
参数
即使我们能做的仅仅是遍历对象及其字段,GraphQL 就已经是一个非常有用的数据查询语言了。但是当你加入给字段传递参数的能力时,事情会变得更加有趣。
{
human(id: "1000") {
name
height
}
}
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}
在类似 REST 的系统中,你只能传递一组简单参数 —— 请求中的 query 参数和 URL 段。但是在 GraphQL 中,每一个字段和嵌套对象都能有自己的一组参数,从而使得 GraphQL 可以完美替代多次 API 获取请求。甚至你也可以给 标量(scalar)字段传递参数,用于实现服务端的一次转换,而不用每个客户端分别转换。