JanusGraph数据存储

2022-03-21 00:00:00 多个 属性 顶点 邻接 切割

本文将为您继续介绍开源的分布式图数据库JanusGraph----数据存储



上一篇文章为您对JanusGraph的基本概念进行了简要介绍,接下来本文将进一步为您介绍有关开源的分布式图数据库JanusGraph数据存储的详细内容,将从图数据模型和内部数据存储模型两个方面进行讲解。



图数据模型——属性图


1.1基本概念介绍


VertexLabel。节点的类型,用于表示现实世界中的实体对象;

EdgeLabel。边的类型,用于表示现实世界中的关系类型;

Edge。边,用于表示具体的联系。JanusGraph的边都是单向边。如果需要双向边,则通过两条相反方向的单向边组成;

PropertyKey。属性的类型。Property Key有Cardinality的概念。Cardinality有SINGLE、LIST和SET三种选项;

Property。属性,用于表示具体的附加信息,采用Key-Value结构。

Edge多样性:
  • MULTI 在一对vertex间可以有任意多个同样label的edge;

  • SIMPLE在一对vertex间多只能有一个同样label的edge;

  • MANY2ONE多对一。在任何顶点上多允许此标签的一个传出边,但不对传入边施加约束。如mother;

  • ONE2MANY一对多。在任何顶点上多允许此标签的一个传入边,但不对传出边施加约束。如winnerOf;

  • ONE2ONE 某verex中具有同样Label的edge,只能有多一个incomingedge和多一个outgoing edge,如marry。

Property Key Cardinality:

  • SINGLE。每个KEY只允许一个Value (默认);

  • LIST。以LIST形式保存Value,也即可以有重复值;

  • SET。以SET形式保存Value,不能有重复值;

Property Key Data Type:



内部数据存储模型

  •  图切割
经典图切割方法:







按Vertex切割时,切割线通过图的Vertex,而不是Edge。每一条Edge边只保存一次,并且每一条Edge只出现在一台机器上,邻居多的Vertex会被分发到不同的机器上。按Edge切割时,切割线只穿过连接vertex的edge,此时,每一个vertex只保存一次。切断的Edge会保存到多台机器上。

作为一种分布式图数据库,JanusGraph需要将数据切分存储到多台机器上。JanusGraph采用的分片方式是按Edge切割,而且对于每一条边,都会被切断。切断后,该边会在起始Vertex上和目的Vertex上各存储一次。通过这种方式,JanusGraph不管是通过起始Vertex,还是从目的Vertex,都能快速找到对端Vertex。

如上述例图: 

按边切割后,得到如下结果:


JanusGraph采用邻接表存储图,存储了顶点的邻接表集合。以顶点为key,顶点的邻接表中包含所有的边,边的属性以及顶点属性。这种存储结构,允许JanusGraph将数据存储在任何支持bigtable的存储后端中。  

  •  JanusGraph Data Model:



Bigtabel Data Model:cell(单元格)、column(列)、value(列值):

在Bigtable数据模型中,每个表是行的集合,由一个key标识。每行由任意数量的cell组成。cell由column和value组成。cell由给定行内的column标识。cell(单元格)、column(列)、value(列值); JanusGraph对Bigtable数据模型有一个额外要求:存储边的单元格必须按column排序,并且列范围指定的单元格子集必须是有效可检索的(例如,通过使用索引结构,跳过列表或进行二进制搜索)。特定的Bigtable实现可以使行按其键的顺序排序。JanusGraph可以利用这样的键序来有效地划分图形,从而为非常大的图形提供更好的加载和遍历性能。但是这并不是必需的。
JanusGraph使用Bigtable模型进行存储数据,如果使用的存储后台支持键顺序(如Hbase),则邻接列表将按Vertex Id排序进行顺序存储的。在JanusGraph存储数据的表中,行的key可以是任意字符串。每次在一行中读或写数据都是一个原子操作,这个设计使客户端可以更加方便的推导出在并发更新相同行时的系统行为。
JanusGraph将每个邻接表作为一行存储在底层存储后端。顶点id (分配)是指向包含顶点邻接表的行的Key。若以HBase为存储,后端顶点的id作为HBase的Rowkey,节点上的每一个属性和每一条边,作为该Rowkey的一个个独立的Cell。即每一个属性、每一条边,都是一个个独立的KCV结构(Key-Column-Value)。
通过以邻接列表格式存储图形,JanusGraph确保所有顶点的边和属性紧密地存储在存储后端中(比如Hbase/Cassandra等),从而可以加速遍历。
缺点是每个边必须存储两次一次作为source顶点的出边被存储,一次作为target顶点入边被存储,当然这也使我们可以在source Vertex和target Vertex中任意顶点都可以快速找到对端。
2.1  Vertex id

 Vertex id以Rowkey的形式存储在HBase中。共有64个bit,三部分组成:partition id、count、ID padding

后几个bit是ID padding, 表示Vertex的类型。具体的位数长度根据不同的Vertex类型而不同。常用的普通Vertex,其值为’000’。下图是所有可能的ID padding:


2.2 Property

每个Property和Edge都作为一个cell存储在其相邻顶点的行中。它们会被序列化并且column的字节顺序会遵循edge的column中的sort key进行存储。变量id编码方案和压缩对象序列化使每个cell所占存储空间都尽可能小。

可变长度编码方案编码的数字,以减少它们消耗的字节数;Edge和Property在cell中都是由column(列)和value(值)组成。

一个PropertyKey所关联的属性值有可能有一个,也有可能有多个,JanusGraph使用Cardinality来描述这种特点,有三种类型。

 SINGLE:HBase的列名只存储Property Key的id。具体的PropertyValue值以及Property id,都存放在Cell的Value中

 LIST:Propertyid放在列名中

 SET:Propertyid放在列名中

2.2.1 Property Key id

     Property Key和EdgeLabel被抽象成了Relation Type,并采用相同的数据结构:

2.2.2 Property id & Property Value 
 


 

2.3 Edge

每个Edge都作为一个cell存储在其相邻顶点的行中。它会被序列化并且column的字节顺序会遵循edge的column中的sortkey进行存储。变量id编码方案和压缩对象序列化使每个cell所占存储空间都尽可能小。
此处的组成元素SortKey是一种特殊的属性,JanusGraph允许在定义Edge Label时指定其中的一个或多个属性为Sort Key,主要的作用是:将数据序列化进行存储时,序列化中edge会根据你设定的sort key进行排序,比如A有多个朋友关系的edge,每一个edge都有一个建立时间(createtime),sort key便可以在存储时将边按照建立时间进行顺序存储,这样便于查找某个createtime的边,也便于范围查找。
 此处的signaturekey是一个list数组,里面存储边的property keyid,作用是:边的other properties是被序列化存储在磁盘中,当我们查找边是否包含某一属性时不可能将其序列化回来再进行查找,这时候signature key的作用就体现出来了,通过其就可以知道这条边有什么属性,就可以更快的进行查找。现在再看‘红框表示使用关联属性键中引用压缩元数据序列化的一个或多个属性值’这句话,说的就是引用属性的key id。signature key是一种空间的换时间的做法。
2.3.1 Edge Label id + direction


2.3 2 Others

JanusGraph允许在定义Edge Label时指定其中的一个或多个属性为Sort Key。对于边的Sort Key属性,JanusGraph在存储时会将其存储在Relation Type ID的后面,其他所有字段的前面。通过这种方式,可以保证一个节点的多条同一个类型的边,会按SortKey属性排序存储。这对于当一个节点有大量边的情况时,对查询性能提升有帮助。


相关文章