【图数据库实战】HugeGraph架构

一、概述

      作为一款通用的图数据库产品,HugeGraph需具备图数据的基本功能,如下图所示。HugeGraph包括三个层次的功能,分别是存储层、计算层和用户接口层。 HugeGraph支持OLTP和OLAP两种图计算类型,其中OLTP实现了Apache TinkerPop3框架,并支持Gremlin查询语言。 OLAP计算是基于SparkGraphX实现。

二、组件

      HugeGraph的主要功能分为HugeCore、ApiServer、HugeGraph-Client、HugeGraph-Loader和HugeGraph-Studio等组件构成,各组件之间的通信关系如下图所示。

  • HugeCore :HugeGraph的核心模块,TinkerPop的接口主要在该模块中实现。HugeCore的功能涵盖包括OLTP和OLAP两个部分。

  • ApiServer :提供RESTFul Api接口,对外提供Graph Api、Schema Api和Gremlin Api等接口服务。

  • HugeGraph-Client:基于Java客户端驱动程序。HugeGraph-Client是Java版本客户端驱动程序,后续可根据需要提供Python、Go、C++等多语言支持。

  • HugeGraph-Loader:数据导入模块。HugeGraph-Loader可以扫描并分析现有数据,自动生成Graph Schema创建语言,通过批量方式快速导入数据。

  • HugeGraph-Studio:基于Web的可视化IDE环境。以Notebook方式记录Gremlin查询,可视化展示Graph的关联关系。HugeGraph-Studio也是本系统推荐的工具。

三、设计理念

        常见的图数据表示模型有两种,分别是RDF(Resource Description Framework)模型和属性图(Property Graph)模型。RDF和Property Graph都是最基础、最有名的图表示模式,都能够表示各种图的实体关系建模。RDF是W3C标准,而Property Graph是工业标准,受到广大图数据库厂商的广泛支持。HugeGraph目前采用Property Graph。

      HugeGraph对应的存储概念模型也是参考Property Graph而设计的,具体示例详见下图:

      在HugeGraph内部,顶点仅存储Id不包含任何属性信息,顶点所有的属性和Label都通过边来存储。如图所示顶点(Id=1)有3个属性分别是name、age和lives,则由三条对应的边指向其具体的属性值,这三条边的Label和顶点属性名相同分别是name、age和lives。

      在HugeGraph内部,顶点与顶点之间的关系也通过边来存储的。但关系的属性并没有像顶点一样分来存储,而是和关系存储在一起。

      顶点属性值通过边指针方式存储时,如果要更新一个顶点特定的属性值直接通过覆盖写入即可,其弊端是冗余存储了VertexId;如果要更新关系的属性需要通过read-and-modify方式,先读取所有属性,修改部分属性,然后再写入存储系统,更新效率较低。从经验来看顶点属性的修改需求较多,而边的属性修改需求较少,例如PageRank和Graph Cluster等计算都需要频繁修改顶点的属性值。

四、 图分区方案

      对于分布式图数据库而言,图的分区存储方式有两种:分别是边分割存储(Edge Cut)和点分割存储(Vertex Cut),如下图所示。使用Edge Cut方式存储图时,任何一个顶点只会出现在一台机器上,而边可能分布在不同机器上,这种存储方式有可能导致边多次存储。使用Vertex Cut方式存储图时,任何一条边只会出现在一台机器上,而每相同的一个点可能分布到不同机器上,这种存储方式可能会导致顶点多次存储。

      采用EdgeCut分区方案可以支持高性能的插入和更新操作,而VertexCut分区方案更适合静态图查询分析,因此EdgeCut适合OLTP图查询,VertexCut更适合OLAP的图查询。HugeGraph目前采用EdgeCut的分区方案。

五、 VertexId 策略

      HugeGraph的Vertex支持三种ID策略,在同一个图数据库中不同的VertexLabel可以使用不同的Id策略,目前HugeGraph支持的Id策略分别是:

  • 自动生成(AUTOMATIC):使用Snowflake算法自动生成全局唯一Id,Long类型;

  • 主键(PRIMARY_KEY):通过VertexLabel+PrimaryKeyValues生成Id,String类型;

  • 自定义(CUSTOMIZE_STRING|CUSTOMIZE_NUMBER):用户自定义Id,分为String和Long类型两种,需自己保证Id的唯一性;

      默认的Id策略是AUTOMATIC,如果用户调用primaryKeys()方法并设置了正确的PrimaryKeys,则自动启用PRIMARY_KEY策略。启用PRIMARY_KEY策略后HugeGraph能根据PrimaryKeys实现数据去重。

     1.AUTOMATIC ID策略

schema.vertexLabel("person")

.useAutomaticId()

.properties("name", "age", "city")

.create();

graph.addVertex(T.label, "person","name", "marko", "age", 18, "city", "Beijing");

     2.PRIMARY_KEY ID策略

schema.vertexLabel("person")

.usePrimaryKeyId()

.properties("name", "age", "city")

.primaryKeys("name", "age")

.create();

graph.addVertex(T.label, "person","name", "marko", "age", 18, "city", "Beijing");

3.CUSTOMIZE_STRING ID策略

schema.vertexLabel("person")

.useCustomizeStringId()

.properties("name", "age", "city")

.create();

graph.addVertex(T.label, "person", T.id, "123456", "name", "marko","age", 18, "city", "Beijing");

4.CUSTOMIZE_NUMBER ID策略

schema.vertexLabel("person")

.useCustomizeNumberId()

.properties("name", "age", "city")

.create();

graph.addVertex(T.label, "person", T.id, 123456, "name", "marko","age", 18, "city", "Beijing");

如果用户需要Vertex去重,有三种方案分别是:

  1. 采用PRIMARY_KEY策略,自动覆盖,适合大数据量批量插入,用户无法知道是否发生了覆盖行为

  2. 采用AUTOMATIC策略,read-and-modify,适合小数据量插入,用户可以明确知道是否发生覆盖

  3. 采用CUSTOMIZE_STRING或CUSTOMIZE_NUMBER策略,用户自己保证唯一

六、 EdgeId 策略

      HugeGraph的EdgeId是由srcVertexId+edgeLabel+sortKey+tgtVertexId四部分组合而成。其中sortKey是HugeGraph的一个重要概念。在Edge中加入sortKey作为Edge的唯一标识的原因有两个:

  1. 如果两个顶点之间存在多条相同Label的边可通过sortKey来区分

  2. 对于SuperNode的节点,可以通过sortKey来排序截断。

      由于EdgeId是由srcVertexId+edgeLabel+sortKey+tgtVertexId四部分组合,多次插入相同的Edge时HugeGraph会自动覆盖以实现去重。需要注意的是如果批量插入模式下Edge的属性也将会覆盖。

      另外由于HugeGraph的EdgeId采用自动去重策略,对于self-loop(一个顶点存在一条指向自身的边)的情况下HugeGraph认为仅有一条边,对于采用AUTOMATIC策略的图数据库(例如TitianDB)则会认为该图存在两条边。

HugeGraph的边仅支持有向边,无向边可以创建Out和In两条边来实现。

七 HugeGraph 事务处理

7.1 TinkerPop事务概述

      TinkerPop transaction事务是指对数据库执行操作的工作单元,一个事务内的一组操作要么执行成功,要么全部失败。详细介绍请参考TinkerPop官方文档:http://tinkerpop.apache.org/docs/current/reference/#transactions

7.2 TinkerPop事务操作接口
  • open 打开事务

  • commit 提交事务

  • rollback 回滚事务

  • close 关闭事务

7.3 TinkerPop事务规范
  • 事务必须显式提交后才可生效(未提交时修改操作只有本事务内查询可看到)

  • 事务必须打开之后才可提交或回滚

  • 如果事务设置自动打开则无需显式打开(默认方式),如果设置手动打开则必须显式打开

  • 可设置事务关闭时:自动提交、自动回滚(默认方式)、手动(禁止显式关闭)等3种模式

  • 事务在提交或回滚后必须是关闭状态

  • 事务在查询后必须是打开状态

  • 事务(非threaded tx)必须线程隔离,多线程操作同一事务互不影响

更多事务规范用例见:Transaction Test

7.4 HugeGraph事务实现
  • 一个事务中所有的操作要么成功要么失败

  • 一个事务只能读取到另外一个事务已提交的内容(Read committed)

  • 所有未提交的操作均能在本事务中查询出来,包括:

    • 增加顶点能够查询出该顶点

    • 删除顶点能够过滤掉该顶点

    • 删除顶点能够过滤掉该顶点相关边

    • 增加边能够查询出该边

    • 删除边能够过滤掉该边

    • 增加/修改(顶点、边)属性能够在查询时生效

    • 删除(顶点、边)属性能够在查询时生效

  • 所有未提交的操作在事务回滚后均失效,包括:

    • 顶点、边的增加、删除

    • 属性的增加/修改、删除

      示例:一个事务无法读取另一个事务未提交的内容

1. static void testUncommittedTx(final HugeGraph graph) throws InterruptedException {

2. final CountDownLatch latchUncommit = new CountDownLatch(1);

3. final CountDownLatch latchRollback = new CountDownLatch(1);

4. Thread thread = new Thread(() -> {

5. // this is a new transaction in the new thread

6. graph.tx().open();

7. System.out.println("current transaction operations");

8. Vertex james = graph.addVertex(T.label, "author",

9. "id", 1, "name", "James Gosling",

10. "age", 62, "lived", "Canadian");

11. Vertex java = graph.addVertex(T.label, "language", "name", "java",

12. "versions", Arrays.asList(6, 7, 8));

13. james.addEdge("created", java);

14. // we can query the uncommitted records in the current transaction

15. System.out.println("current transaction assert");

16. assert graph.vertices().hasNext() == true;

17. assert graph.edges().hasNext() == true;

18. latchUncommit.countDown();

19. try {

20. latchRollback.await();

21. } catch (InterruptedException e) {

22. throw new RuntimeException(e);

23. }

24. System.out.println("current transaction rollback");

25. graph.tx().rollback();

26. });

27. thread.start();

28. // query none result in other transaction when not commit()

29. latchUncommit.await();

30. System.out.println("other transaction assert for uncommitted");

31. assert !graph.vertices().hasNext();

32. assert !graph.edges().hasNext();

33. latchRollback.countDown();

34. thread.join();

35. // query none result in other transaction after rollback()

36. System.out.println("other transaction assert for rollback");

37. assert !graph.vertices().hasNext();

38. assert !graph.edges().hasNext();

39. }

   事务实现原理

  • 服务端内部通过将事务与线程绑定实现隔离(ThreadLocal)

  • 本事务未提交的内容按照时间顺序覆盖老数据以供本事务查询最新版本数据

  • 底层依赖后端数据库保证事务原子性操作(如Cassandra/RocksDB的batch接口均保证原子性)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/158622.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何从Android手机恢复已删除的联系人

联系人应该是最重要的信息之一。 如果您不小心从Android手机中删除了联系人,该怎么办? 如果不容易找回丢失的联系人,您可以使用奇客数据恢复安卓版。 从Android的手机中恢复已删除的联系人 只需删除Android联系人,然后您就可以通…

【Java 进阶篇】揭秘 JQuery 广告显示与隐藏:打造令人惊艳的用户体验

在当今互联网时代,广告已经成为网页中不可忽视的一部分。然而,如何通过巧妙的交互设计,使广告既能吸引用户的眼球,又不会给用户带来干扰,成为了许多前端开发者需要思考的问题之一。在这篇博客中,我们将深入…

Pytorch1.7复现PointNet++点云分割(含Open3D可视化)(文末有一个自己做的书缝识别项目代码)

毕设需要,复现一下PointNet的对象分类、零件分割和场景分割,找点灵感和思路,做个踩坑记录。 下载代码 https://github.com/yanx27/Pointnet_Pointnet2_pytorch   我的运行环境是pytorch1.7cuda11.0。 训练 PointNet代码能实现3D对象分类、…

centos7中安装Nginx和使用Nginx详细操作

环境: 准备了三台centos7虚拟机:192.168.213.4、192.168.213.5、192.168.213.6。 一、安装 三台虚拟机都安装下面的步骤执行,安装Nginx,为后面的使用演示使用。 1、安装必备组件: sudo yum install yum-utils2、配置yum源 在下面的文件目录…

详解自动化测试之 Selenium

目录 1. 什么是自动化 2.自动化测试的分类 3. selenium(web 自动化测试工具) 1)选择 selenium 的原因 2)环境部署 3)什么是驱动? 4. 一个简单的自动化例子 5.selenium 常用方法 5.1 查找页面元素&…

如何合理估算 Java 线程池大小

前 言 Java 中的线程创建会产生显著的成本。创建线程会消耗时间,增加请求处理的延迟,并且涉及 JVM 和操作系统的大量工作。为了减轻这些开销,线程池发挥了作用。 在本文中,我们将深入研究确定理想线程池大小的艺术。经过微调的线…

【C++】模版-初阶

目录 泛型编程--模版 函数模版 类模版 泛型编程--模版 函数模版 如何实现一个通用的交换函数呢?void Swap(int& left, int& right){int temp left;left right;right temp;}void Swap(double& left, double& right){double temp left;left right;righ…

基于ssm+vue交通事故档案系统

摘要 摘要是对文章、论文或其他文本的主要观点、结论和关键信息的简洁概括。由于你没有提供具体的文章或主题,我将为你创建一个通用的摘要。 本文介绍了一种基于SSM(Spring Spring MVC MyBatis)和Vue.js的交通事故档案管理系统的设计与实现…

设计模式-备忘录模式-笔记

动机(Motivation) 在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节…

ROS服务(Service)通信:通信模型、Hello World与拓展

服务通讯是基于请求响应模式的,是一种应答机制。 用于偶然的、对时时性有要求、有一定逻辑处理需求的数据传输场景。 一、服务通讯模型 服务是一种双向通讯方式,它通过请求和应答的方式传递消息,该模型涉及到三个角色: Master…

USART(1)

什么是USART 单片机上有的许多的外设 单片机通过这些外设实现特殊的功能 如果单片机想要和蓝牙模块实现数据的传输那么就也需要单片机有串口模块来和蓝牙模块的串口进行连接 相互传输数据 在单片机上的串口就叫USART USART就是单片机上的外设 来实现串口之间的通信功能 USART名…

基于51单片机步进电机节拍步数正反转LCD1602显示( proteus仿真+程序+原理图+设计报告+讲解视频)

基于51单片机步进电机节拍步数正反转LCD1602显示 📑1. 主要功能:📑2. 讲解视频:📑3. 仿真📑4. 程序代码📑5. 设计报告📑6. 设计资料内容清单&&下载链接📑[资料下…

基于SSM的宠物医院管理系统

基于SSM的宠物医院管理系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringMyBatisSpringMVC工具:IDEA/Ecilpse、Navicat、Maven 系统展示 主页 后台 摘要 随着人们对宠物健康关注的增加,宠物医疗服务的需求也…

许战海战略文库|企业竞争优势三大获取路径:产业、品牌和产品竞争优势

在快速发展和变革的全球化市场中,企业面临着持续的竞争压力。要在这种环境中脱颖而出,企业需要建立持久的竞争优势。通常,竞争优势可以从三个主要路径来获取:产业竞争优势、品牌竞争优势和产品竞争优势。 1. 产品竞争优势为什么很…

电子科技大学 分布式系统 期末复习笔记

第一章 为什么需要分布式系统:功能分离,固有的分布性,负载均衡,可靠性,经济性。 定义:分布式系统是这样一种系统,其中位于联网计算机上的组件仅通过传递消息来通信和协调它们的操作。 特点&am…

线性表的概念

目录 1.什么叫线性表2.区分线性表的题 1.什么叫线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上是…

【Vue配置项】 computed计算属性 | watch侦听属性

目录 前言 computed计算属性 什么是计算属性? Vue的原有属性是什么? 得到的全新的属性是什么? 计算属性怎么用? 计算属性的作用是什么? 为什么说代码执行率高了? computed计算属性中的this指向 co…

【Java 进阶篇】JQuery 遍历 —— 无尽可能性的 `each` 之旅

在前端的征途中,操作元素是开发者不可避免的任务之一。而在 JQuery 中,each 方法则是处理这个任务的得力助手。本文将深入探讨 each 方法的奇妙之处,以及它与原生的 for...of 循环的关系,带你领略无尽可能性的遍历之旅。 起步&am…

modbusRTU通信简单实现(使用NModbus4通信库)

本文实现ModbusRTU通信,使用的是NModbus4通信库,使用 Modbus Slave是一个模拟Modbus协议从机的上位机软件,主要用于模拟测试跟其他主机设备通信的过程。与之成套存在的另一个软件--Modbus Poll,则是模拟Modbus协议主机的上位机软件…

元宇宙数字展厅无代码编辑工具的功能特点

商场如战场,营销是每个企业都必须重视的环节。随着科技的发展,3D展示营销制作平台作为企业快速搭建3D互动展厅的SaaS平台,逐渐崭露头角,为企业提供了诸多便利,让营销变得更加高效和引人入胜。 为企业提供身临其境的产品…