本文首发于 Nebula Graph Community 公众号

经常看技术文章的小伙伴可能会留意到除了正在阅读的那篇文章,在文章页面的正文下方或者右侧区域会有若干同主题、同作者的文章等你阅读;经常逛淘宝、京东的小伙伴可能发现了,一旦你购买或者查看过某个商品之后,猜你喜欢的推荐商品会贴近你刚拔草的商品…这些日常生活中常遇到的事情,可能是由一个名叫图学习的“家伙”提供技术支持。

图学习,顾名思义是基于图的机器学习,按照本期项目介绍的参赛队伍——图学习兴趣小队队长杨鑫的话就是,图学习是一个通过深度学习方法,基于图的结构与属性生成一个向量作为点、边或者整个图的表征。

在之前 Nebula Hackathon 2021 年的参赛项目中,图学习兴趣小队“豪气”地说要让 Nebula Graph 具备支持图学习的能力,在本文接下来的内容中,你将了解到他们是怎么实现这一目标的。

图学习小课堂

在讲述项目实现之前,项目负责人杨鑫先给大家上了一课“图解图学习”。

以获取顶点的向量表征为例来讲解下图学习过程,第一步需要对图中顶点邻居进行采样拿到邻居的拓扑结构以及属性;第二步便是通过自定义的聚合函数聚合邻居顶点蕴含的信息进行计算;最后一步基于聚合信息得到图中各顶点的向量表示。

杨鑫表示,衡量一个图学习算法的好坏是通过生成向量中包含图中顶点属性及拓扑结构的丰富程度来判断的。

故事的开始

在选择图学习框架时,图学习兴趣小队有自己的一套选型标准:首先它是开源组件,方便二次开发,其次它支持分布式,最后框架本身和图数据库的耦合程度要低方便定制化开发。经过深入调研,由于 DGL(链接:https://www.dgl.ai/)同底层的图数据库耦合过高,PYG(链接:https://pytorch-geometric.readthedocs.io/en/latest/)不支持分布式,最终他们采用了 Euler(GitHub 地址:https://github.com/alibaba/euler),而在 Nebula Hackathon 2021 中,图学习兴趣小队的重点工作便是用 Nebula Graph 替换 Euler 原生图数据库,让社区用户可以基于 Nebula Graph 低成本尝试图学习能力。

设计思路

在方案设计上,架构分为三层:底层是 Nebula Graph 图数据库,中间层是图采样算子层,为上层 Euler 图算法提供多种采样图数据的能力。图采样算子则是他们本次工作的重点——重写 22 个 TF 采样算子、6 种 nGQL 采样语法。

高强度的开发量

以全局带权采样语法设计为例,

这里采用了预计算(离线)+ 计算下推(实时)的方式来实现全局采样,主要过程为(上图 1-4)

  1. graphd 提交异步构建任务给 metad;
  2. metad 下发任务给各个 storaged 节点进行计算;
  3. storaged 将计算结果上报给 metad 汇总;
  4. metad 通过心跳将结果同步给 graphd。

详细展开来讲,在图学习训练过程中,数据采样是一个非常高频的操作,采样性能好坏对图学习训练耗时影响很大。

在这里,杨鑫他们采用别名采样算法作为全局带权采样语法的核心算法,它的基本原理是首先对进行采样的全部数据根据各自的权重计算出一份采样表,采样表由行号(sid)、vid1、采样概率(prob)、vid2 四部分组成,其中行号是从 0 开始的编号,vid1、vid2 表示可以被采样的某个顶点的 vid;采样流程是首先在表中随机选择一行,然后再随机生成一个 0~1 之间的值 p,如果 p < prob,则本次采样的数据是 vid1,否则采样 vid2。

目前图学习是基于静态图数据训练,因此我们可以通过预计算的方式离线生成一份别名采样表,而实时采样过程简化为基于预计算的采样表做两次随机采样,时间复杂度由 O(n) 降到 O(1),可以极大地提高采样效率。

下面是基于 Nebula Graph 实现的全局带权采样具体实现,跟 Nebula Graph 的索引重建逻辑很相似。

  1. Graph 服务调用 Meta 服务启动一个异步构建采样表任务,并支持异步任务的状态查询。
  2. Meta 服务的作用是控制异步任务的执行,包括分配每个 Storage 节点需要处理的数据(根据 partition 的 leader 分布决定)、异步触发各个 Storage 节点进行采样表的计算、记录任务的执行状态、记录全局信息(点、边权重和)、通过心跳逻辑将全局信息缓存在 Graph 服务中。
  3. Storage 服务的任务是生成所负责数据的采样表。采样表的计算是整个流程中的核心逻辑,计算过程需要对所有点、边编号,并根据权重大小对点、边进行分类,很显然这些数据是无法全部存储在内存中的,所以我们在 Storage 中增加了一个采样统计信息 RocksDB 实例来存储采样表、点边总数、点边权重、计算中间变量等数据。以计算某一类点的采样表的过程为例:

第一步遍历全图来统计这一类点的权重和数量,同时为了给生成采样表做准备,将点的序号(点的读取顺序)、vid、权重等数据存储在了图中(B1)结构中。其中 key 的数据结构是 type + tagid + sid,type 标识了数据是 B1 类型,tagid 就是点的 tag,sid 是点的序号,跟采样表的 key 结构相同。

第二步将数据分类,根据权重值以点的总数的倒数为界将所有的点分成两部分,分别以(B2)、(B3)的结构存储,key 的组成与 (B1) 结构相比就是type 值不同。

第三步分别遍历(B2)、(B3),根据别名采样算法的理论来计算每个点的采样概率 prob。这里每个点是用 sid 来标识的,也就是说实际上是在计算第 sid 个点的采样概率,概率值作为采样表的一部分会更新到(B1)结构中。

第四步将中间变量(B2)、(B3)结构删除掉,释放磁盘空间。

利用采样表进行实时采样的过程就比较简单了。完成采样表的预计算后会将点、边权重的统计信息上报到 Meta 服务存储,然后通过心跳通知 Graph 服务将这些数据缓存在本地。根据这些数据可以计算出点、边在各 Storage 服务上所占的权重比例,将用户指定的采样数量按比例分配到各 Storage 服务,然后在 Storage 服务上通过两次的随机数操作采样到足够数量的数据后返回,最后在 Graph 服务上进行数据聚合,这样就完成了一次带权采样。

另外为了提高异步任务的健壮性,还实现了失败重试、任务重复限制、重建采样表后脏数据清理、导出采样表等功能。

提到项目设计以及重写其他算子过程中遇到的问题,图学习兴趣小队队长杨鑫表示因为 Nebula Graph 的数据都存储在磁盘中,要用 Nebula Graph 替换 Euler 原生内存图数据库,改造后的 Euler 在采样效率上肯定要低于原生 Euler,因此怎么保证改造后 Euler 的图学习训练耗时尽可能接近原生 Euler 是要解决的首要问题,至少得保证两者采样性能不能有数据级上的差距

原生 Euler 中的图学习算法由 Python 实现,通过 TensorFlow 的 OP 机制来调用 C++ 实现的采样算子,然后在采样算子内直接调用内存图数据库获取数据,这样就完成了一次数据采样。

图兴趣小队最初的方案是将采样算子用 Python 实现,这样一次数据采样过程就变成了图学习算法直接调用采样算子,然后在采样算子内则通过 Nebula Graph 的 Python 客户端执行采样语法获取数据。这样改造后的系统会有更清晰的处理流程,但是经过测试他们发现其训练耗时要远大于原生 Euler,具体到训练过程中的每次数据采样上,其耗时是原生 Euler 的几十倍,这样的结果显然是不能满足要求的。通过分析各阶段执行耗时他们发现,数据采样的耗时要远大于采样语法的执行耗时,所以他们认为是 Python 客户端在反序列化上消耗了大量时间。因此图兴趣小队进行了第一次优化,使用 fbthrift fastproto 替换 Nebula Graph 原生客户端的序列化组件,优化后的性能提高了一倍,整体训练耗时确实有所降低,但是这样的结果却仍然无法满足他们的使用要求。

这时候用上了第二个方案,重写 C++ 版本的采样算子,在采样算子中通过 Nebula Graph 的 C++ 客户端执行采样语法获取数据,相比第一个方案多了一些适配工作,算子的重写主要是适配 C++ 客户端的输入输出,另外改造了 C++ 客户端以便采样算子的调用。

这也是他们最终的方案,这样改造后的 Euler 虽然在训练耗时上仍然高于原生 Euler,但是差距控制在了二倍以内,符合预期。

有意思的 Hackathon

当谈到本次有什么值得图学习兴趣小队留意的项目时,队长杨鑫表示比较关注的是大油条东北虎队伍的项目——如何吊打 Nebula 的深度查询,这个项目的优化思路对他们很有借鉴意义。

因为在实际使用中,图兴趣小队所在团队的业务方有很多的多跳查询需求,包括 GO 查询、FINDPATH 查询等。这本应该是 Nebula Graph 所擅长的部分,在大部分场景下也确实如此,但是在遇到出度很大的顶点的时候,查询性能会急剧恶化。其主要原因还是基于目前 Nebula Graph 的架构,多跳查询只能先将一跳的结果集汇总到 Graph 服务后才能进行下一跳计算,完全不能将多跳计算下推。而这个项目正好给他们提供了一个解决这个难题的思路。

附:图学习兴趣小队项目设计文稿:https://docs.qq.com/doc/DVnZQUVBzd1dmS0lS


交流图数据库技术?加入 Nebula 交流群请先填写下你的 Nebula 名片,Nebula 小助手会拉你进群~~

关注公众号

基于 Nebula Graph 构建图学习能力的更多相关文章

  1. 图数据库|基于 Nebula Graph 的 BetweennessCentrality 算法

    本文首发于 Nebula Graph Community 公众号 ​在图论中,介数(Betweenness)反应节点在整个网络中的作用和影响力.而本文主要介绍如何基于 Nebula Graph 图数据 ...

  2. GraphX 在图数据库 Nebula Graph 的图计算实践

    不同来源的异构数据间存在着千丝万缕的关联,这种数据之间隐藏的关联关系和网络结构特性对于数据分析至关重要,图计算就是以图作为数据模型来表达问题并予以解决的过程. 一.背景 随着网络信息技术的飞速发展,数 ...

  3. 图数据库 Nebula Graph 的数据模型和系统架构设计

    Nebula Graph:一个开源的分布式图数据库.作为唯一能够存储万亿个带属性的节点和边的在线图数据库,Nebula Graph 不仅能够在高并发场景下满足毫秒级的低时延查询要求,而且能够提供极高的 ...

  4. Nebula Graph 在微众银行数据治理业务的实践

    本文为微众银行大数据平台:周可在 nMeetup 深圳场的演讲这里文字稿,演讲视频参见:B站 自我介绍下,我是微众银行大数据平台的工程师:周可,今天给大家分享一下 Nebula Graph 在微众银行 ...

  5. Nebula Graph 在企查查的应用

    本文首发于 Nebula Graph Community 公众号 背景 企查查是企查查科技有限公司旗下的一款企业信用查询工具,旨在为用户提供快速查询企业工商信息.法院判决信息.关联企业信息.法律诉讼. ...

  6. Nebula Graph 在网易游戏业务中的实践

    本文首发于 Nebula Graph Community 公众号 当游戏上知识图谱,网易游戏是如何应对大规模图数据的管理问题,Nebula Graph 又是如何帮助网易游戏落地游戏内复杂的图的业务呢? ...

  7. Nebula Graph 技术总监陈恒:图数据库怎么和深度学习框架进行结合?

    引子 Nebula Graph 的技术总监在 09.24 - 09.30 期间同开源中国·高手问答的小伙伴们以「图数据库的设计和实践」为切入点展开讨论,包括:「图数据库的存储设计」.「图数据库的计算设 ...

  8. 使用 Docker 构建 Nebula Graph 源码

    Nebula Graph 介绍 Nebula Graph 是开源的高性能分布式图数据库.项目使用 C++ 语言开发,cmake 工具构建.其中两个重要的依赖是 Facebook 的 Thrift RP ...

  9. 分布式图数据库 Nebula Graph 的 Index 实践

    导读 索引是数据库系统中不可或缺的一个功能,数据库索引好比是书的目录,能加快数据库的查询速度,其实质是数据库管理系统中一个排序的数据结构.不同的数据库系统有不同的排序结构,目前常见的索引实现类型如 B ...

  10. 图数据库 Nebula Graph TTL 特性

    导读 身处在现在这个大数据时代,我们处理的数据量需以 TB.PB, 甚至 EB 来计算,怎么处理庞大的数据集是从事数据库领域人员的共同问题.解决这个问题的核心在于,数据库中存储的数据是否都是有效的.有 ...

随机推荐

  1. Linux命令行从x度网盘下载数据

    技术背景 做开源项目的时候,尤其是现在的数据量越来越大,经常会面临到数据往哪里存放的问题.因为自己刚好有一个某度云的会员,看了一下还有几十个TB的空间还没用上.于是考虑把这个网盘变成一个定向共享数据的 ...

  2. 【JS 逆向百例】某易支付密码 MD5+AES 加密分析

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...

  3. docker 镜像导出和导入(适用于内网无法拉镜像的问题)

    1.在外网将镜像从指定的仓库拉下来 docker pull consul 现在已将consul镜像拉到了可连外网的服务器  2.将镜像把包到指定的tar文件中 docker save consul:l ...

  4. pycharm alt+f7(查找)显示动态用法的结果过多(dynamic usages)

    在脚本语言中查找引用时,如果有同名函数,在动态用法那一栏会出现大量的结果,,如何缩小或者动态用法(dynamic usages)的结果呢? 在官网上也有提出了这个问题,但官方没有给出答案issue:P ...

  5. LyScript 验证PE程序开启的保护

    有些漏洞利用代码需要在某个保护模式被关闭的情况下才可以利用成功,在此之前需要得到程序开启了何种保护方式.验证其实有很多方法,其原理是读入PE文件头部结构,找到OPTIONAL_HEADER.DllCh ...

  6. Python-pymysql如何向SQL语句中传参

    方法一:不传递参数 ## 方式一.不传递参数 id = "01" name = "语文" sql = "select * from course wh ...

  7. Power BI 2 DAY

    目录 Power BI零散知识点 M函数 Power BI零散知识点 纵向合并 = 主页-组合-追加查询-追加查询(修改数据源)-将查询追加为信查询(创建新数据源) 横向合并 = 主页-组合-合并查询 ...

  8. NC20477 [ZJOI2008]树的统计COUNT

    题目链接 题目 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II ...

  9. APB_AHB_AXI协议的简单介绍

    一.AMBA概述 今天要介绍的三种嵌入式总线技术:APB.AHB.AXI,它们都属于AMBA 片上总线协议.所以,在介绍这几种总线技术之前,有必要先了解一下AMBA 片上总线协议是什么. AMBA ( ...

  10. MySQL8.0使用mysqlsh配置主从复制 InnoDB ReplicaSet

    InnoDB ReplicaSet InnoDB ReplicaSet 由一个主节点和多个从节点构成. 可以使用ReplicaSet对象和AdminAPI操作管理复制集, 例如检查InnoDB复制集的 ...