人之初,性本鸽。

大家好,我叫储惠龙(实名上网),你可以叫我小龙人,00 后一枚。目前从事后端开发工作。

今天给大家带来一个简单的为 NebulaGraph 提供 GraphQL 查询支持的 DEMO,为什么是简单的,因为本来想完成更多工作再给大家介绍的,但是上个月太忙加上下个月更忙,但是我又很想白嫖一下 Nebula 官方的奖品,所以就赶紧端上来了。

体验 NebulaGraphQL

先上项目地址:https://github.com/Dragonchu/NebulaGraphQL

GraphQL 是什么

先简单介绍一下 GraphQL,https://graphql.cn/ 详细的信息官方介绍得都很清晰。说一下我的理解,GraphQL 并不是对标 Cypher 这种查询语言,而是对标 REST 的一种 API 设计风格

所以,严格意义上,不是说使用 GraphQL 查询图数据库,而是使用一种 GraphQL 风格的 API 查询图数据库,或者说是将 Cypher 封装了一样。这个本质工作和大家做应用开发时,基于 NebulaGraph 写一些通过的 REST 接口是一样的。

API 查询示例

本文的测试数据集使用的 NebulaGraph 官方的 basketballplayer 数据集https://docs.nebula-graph.io/2.0/basketballplayer-2.X.ngql

举个例子,如果我想“根据科比的名字得到科比的全部信息”,可能会使用下面这样的 nGQL 语句:

LOOKUP ON player WHERE player.name == "Kobe Bryant" YIELD id(vertex) as vertexId | FETCH PROP ON player $-.vertexId YIELD properties(vertex);

虽然说 nGQL 已经很方便阅读了,但是如果让一个完全 0 基础的萌新来看也是看不懂的,并且这个语句的返回值是不明确的,至少没有办法从查询看到结果。而返回值的解析一直也是很多人的痛苦

那么,来看看使用 GraphQL 查询同一场景会是什么情况。

查询语句会是:

{
players(name:"Kobe Bryant"){
name
age
}
}

返回结果是:

{
players=[{name=Kobe Bryant, age=40}]
}

看看这优雅的查询和返回结果,想必我不多说,大家也都看得懂。这真的是

其实上面说了那么多,就是官方对 GraphQL 的总结:描述你的数据、请求你所要的数据、得到可预测的结果

上述的查询在 NebulaGraphQL 中已经实现了,同时还支持通过 VertexID 查询数据(好吧,我也就实现了这两种)。

NebulaGraphQL 简单入门

NebulaGraphQL 是一个 Java 库,旨在应用层提供使用 GraphQL 语法查询 NebulaGraph 图数据库中数据的能力。

在项目中使用 NebulaGraphQL 非常简单,因为 NebulaGraphQL 本身只想做一个简单的工具库,未来如果想直接集成到 MVC 框架可能会再起一个 NebulaGraphQL-Spring 之类的项目(画大饼中……)。所以 NebulaGraphQL 的使用和 nebula-java 是几乎完全一致的。

使用示例:

//创建一个config
GraphqlSessionPoolConfig graphqlSessionPoolConfig = new GraphqlSessionPoolConfig(
Lists.newArrayList(graphdAddress),
Lists.newArrayList(metadAddress),
spaceName, username, password);
//创建一个连接池
GraphqlSessionPool pool = new GraphqlSessionPool(graphqlSessionPoolConfig);
//执行语句
ExecutionResult executionResult = pool.execute("{players(age:32){name\nage}}");
//获取结果
System.out.println(executionResult.getData().toString());

其实 GraphSessionPool 内部就是使用的 nebula-java 的 SessionPool,所有配置都和使用官方提供的连接池一致,唯一的区别是需要额外提供 metad 的连接地址。这是因为 NebulaGraphQL 是通过 metad 来自动构建 Schema 的,NebulaGraphQL 会在创建连接池时自动创建 Schema。

NebulaGraphQL 的实现

NebulaGraphQL 主要是基于 graphql-java实现的。而使用 graphql-java,大家可以根据自己的项目定义自己的 GraphQL 的 Schema。不过,NebulaGraphQL 想尽可能地提供一些通用功能,并且一定是根据 NebulaGraph 的 Schema 自动构建的。

在创建 GraphqlSessionPool 时,NebulaGraphQL 通过连接 NebulaGraphQL 的 metad 将 NebulaGraph 中的元数据信息构造成 GraphQL 的 Schema 信息。这一部分是关键难题。目前,我仅仅做了如下的变换:

  1. 对于 NebulaGraph 中所有的 Tag,都会构造一个对应的 GraphQL 的可查询对象。
  2. 每一个 Tag 都会有一个同名的根据 ID 获取信息的查询。举例来说,对于 player 这个 tag,会生成一个查询 player,这个查询的参数是 vertexID,会根据 vertexID 获取到信息。
  3. 每一个 Tag 都会有一个在名称后加 -s 的查询。举例来说,对于 player 这个 tag,会生成一个查询 players,这个查询的参数是任意的属性。如果 player 上有 age,name,country 这些属性,在查询参数中可以传入这三种属性的任意组合,NebulaGraphQL 查询时会将这些参数进行“与” AND 语义的构造,再获取相关顶点。对于用户没有指定的参数,默认为 null(这是一个已知的问题,如果目的就是查 null 会有问题)。

测试数据集上自动生成的 GraphQL 的 Schema 示例:

type Query {
player(
"Vertex ID"
ID: ID
): player
players(age: Int = null, name: String = null): [player]!
team(
"Vertex ID"
ID: ID
): team
teams(name: String = null): [team]!
}
type player {
age: Int
name: String
}
type team {
name: String
}

简单讲解一下,Query 是 GraphQL 的查询入口,其中的 player, players, team, teams 都是自动生成的查询,可以当作查询语句。

player 是根据 VertexID 查询并返回一个 player,player 后面没有 ! 标识符,说明可能查询结果为空。players 查询有两个参数,对应着 player 这个 tag 的两个属性 age 和 name,这两个参数的类型都从 NebulaGraph 中的数据类型映射到了 GraphQL 的数据类型,默认值都为 null,返回值是一个列表。列表后的 !,说明一定返回一个列表,但是其中的 player 后没有 ! 标识符,指的是可能返回一个空列表。

使用 players 查询,参数可以指定 age 或者 name,或者 age 和 name 一起指定。

下面的 player 和 team 两个 type 就表示了这两个对象有什么属性,可以在查询时指定返回的属性,NebulaGraphQL 在返回结果时就只会提供查询需要的属性。

每一个 GraphQL 的查询会有一个绑定的 DataFetcher 对象,该对象中实现的就是如何将 GraphQL 语法映射成 nGQL 语句,并执行插叙返回结果。而返回结果会映射到自定义对象上,这里使用了我另一个小工具NebulaResultBoot 将执行结果映射到自定的对象上后,我们就可以在未来实现应用层的缓存,当然这里也有一个潜在的问题:每一次查询都要求获取到每一个点边的所有属性,这部分未来需要考虑优化。

当然,NebulaGraphQL 的目标不只是简单将 nGQL 映射到 GraphQL 这么简单,因为 GraphQL 除了查询简单这个很明朗的特点,还可以更轻松的支持权限管理,以及通过 DataLoader 机制在应用层实现一层缓存。不过,我这边目前也没有研究的很透彻,如果有大佬愿意加入一起实现那就最好不过了。

为了方便大家贡献(主要是我懒),NebulaGraphQL 的开发测试已经完成了一部分的容器化了,将代码库克隆到本地后,本地只需要有 Docker,然后在仓库根目录下运行

docker-compose -f docker-compose.dev.yml up --build

就可以看到在自动跑测试了,会在本地启动 NebulaGraph 集群并自动插入测试的数据,后续会继续优化这方面的流程。

小结

NebulaGraphQL 提供了更简单的查询语句,这个查询语句的构造应该是让前端直接提供的,GraphQL 的优势之一就是可以让前端选择自己需要的数据从而避免“接口地狱”,可能会有人认为这相当于让前端直接访问数据库了。是的,我觉得这个理解也确实没问题,这也是有人反对 GraphQL 的理由,不过这里就不继续讨论了。

但是使用 GraphQL 有一个潜在优势,也就是可以更轻松的将图数据库和关系型数据库整合在一起。当然如果只是使用图数据库的话,那使用 NebulaGraphQL 至少也能方便做一些简单的数据查询与测试。

对于 NebulaGraphQL 在实际生产中的价值目前我也没有体验过,因为纯属兴趣写着玩儿,如果大家有想法,欢迎在评论区交流。

当 GraphQL 遇上图数据库,便有了更方便查询数据的方式的更多相关文章

  1. Android数据库专家秘籍(七)经验LitePal查询艺术

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/40153833 经过了多篇文章的学习,我们已经把LitePal中的绝大部分内容都掌握 ...

  2. iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】

                   在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运 ...

  3. SQL点滴17—使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识

    原文:SQL点滴17-使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识 在开发过程中会遇到需要弄清楚这个数据库什么时候建的,这个数据库中有多少表,这个存储过程长的什么样子等等信息 ...

  4. 国产多维数据库 NeuralCube!中国人自己的大数据底层核心技术!

    商业转载请联系作者获得授权,非商业转载请注明出处. 提到‘数据库’,首先被想到的肯定是Oracle.DB2.SQL Server.MySql这些传统的关系型数据库.数据库的概念是非常宽泛的,除了上述的 ...

  5. 完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询

    相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能 完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制 自APIJSON发布 ...

  6. mysql(数据库,sql语句,普通查询)

    第1章 数据库 1.1 数据库概述 l 什么是数据库 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作. l 什 ...

  7. 关系型数据库与HBase的数据储存方式差别

    现在Bigtable型(列族)数据库应用越来越广,功能也非常强大. 可是非常多人还是把它当做关系型数据库在使用,用原来关系型数据库的思维建表.存储.查询. 本文以hbase举例讲述数据模式的变化. 传 ...

  8. MySQL数据库:7、SQL常用查询语句

    Python基础之MySQL数据库 目录 Python基础之MySQL数据库 一.SQL语句常用查询方法 前期数据准备 1.基本查询 2.编写SQL语句的小技巧 3.查询之where筛选 3.1.功能 ...

  9. 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。

    最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...

  10. [原]php远程odbc连接sqlsvr数据库,自定义端口,命名实例的连接方式

    远程odbc连接sqlsvr数据库,自定义端口,命名实例的连接方式,默认如果不修改的话sqlsvr的端口号是1433,默认实例名就是机器名,,如果既用了命名实例,又改了默认端口,改怎么连接数据库呢? ...

随机推荐

  1. HBase深度历险 | 京东物流技术团队

    简介 HBase 的全称是 Hadoop Database,是一个分布式的,可扩展,面向列簇的数据库,是一个通过大量廉价的机器解决海量数据的高速存储和读取的分布式数据库解决方案.本文会像剥洋葱一样,层 ...

  2. echarts显示地图

    <template> <div class="managingPatientSize"> <div id="china-map"& ...

  3. es6默认传参 es5的默认传参

    在默认传参在实际中座中还是用的比较多的. 它可以用来解决,用户没有给定值的时候,默认给一个指定的值. es6默认传参 es5的默认传参 //es6 function say(a = 4) { cons ...

  4. KubeSphere2.1踩坑记

    至少两台机器.推荐4X16.(完全安装KubeSphere会吃掉10G+内存) k8s安装(略1.14.8)可参考我上一篇文章或者基于kubeadmin快速安装 KubeSphere2.1前置条件 1 ...

  5. (数据科学学习手札122)Python+Dash快速web应用开发——内网穿透篇

    由我开源的先进Dash组件库feffery-antd-components正处于早期测试版本阶段,欢迎前往官网http://fac.feffery.tech/了解更多 1 简介 这是我的系列教程Pyt ...

  6. [洛谷]P1967-最小生成树-好题推荐

    [NOIP2013 提高组] 货车运输 题目背景 NOIP2013 提高组 D1T3 题目描述 A 国有 \(n\) 座城市,编号从 \(1\) 到 \(n\),城市之间有 \(m\) 条双向道路.每 ...

  7. ABP .net Core 将日志打印在控制台

    上效果图 来看一下操作流程: 一.分为.net Core 2.2 和 .net Core 3.0及以上 (一)..net Core 2.2 1.在 EntityFrameworkCore中安装Nuge ...

  8. 从零开始配置vim(23)——lsp基础配置

    上一章,我们初步认识了lsp,并且对 nvim-treesitter插件进行了配置,为编辑器提供了代码着色.自动格式化以及增量选中功能.算是初步体验了 lsp的相关功能.从这篇开始我们通过lsp的功能 ...

  9. Prompt工程师指南[高阶篇]:对抗性Prompting、主动prompt、ReAct、GraphPrompts、Multimodal CoT Prompting等

    Prompt工程师指南[高阶篇]:对抗性Prompting.主动prompt.ReAct.GraphPrompts.Multimodal CoT Prompting等 1.对抗性 Prompting ...

  10. C/C++ 通过CRC32实现反破解

    我们可以通过使用CRC32算法计算出程序的CRC字节,并将其写入到PE文件的空缺位置,这样当程序再次运行时,来检测这个标志,是否与计算出来的标志一致,来决定是否运行程序,一旦程序被打补丁,其crc32 ...