1. 程式人生 > >圖解JanusGraph內部資料儲存結構

圖解JanusGraph內部資料儲存結構

本文以圖解的形式詳細介紹了圖資料庫JanusGraph的內部資料儲存結構,包括Vertex/Property/Edge等資訊如何儲存於HBase資料表中,以及各自的資料格式定義。

在前面的文章中,我們介紹了圖資料庫的基本概念,並對Titan做了簡單的介紹。開源Titan專案已經停止更新,JanusGraph是Titan專案的演進產品。到目前為止,JanusGraph與Titan在核心機制上相差不大。JanusGraph/Titan有如下關鍵設計:

  • 支援大規模圖資料儲存,Titan圖資料庫是建立在分散式叢集上,資料儲存容量和叢集節點數量成正比;

  • 支援彈性和線性擴充套件,高可用,高容錯;

  • 支援Gremlin圖查詢語言;

  • 支援利用Hadoop計算框架對圖資料進行分析;

  • 支援外部索引:ElasticSearch、Solr、Lucene;

  • 支援多儲存引擎:Cassandra、HBase、Berkeley DB和InMemory模式;

  • 基於Apache License 2.0;

本文內容以HBase作為Storage Backend,詳細介紹JanusGraph的內部資料儲存結構。

JanusGraph基本概念

在介紹關係資料的資料儲存結構之前,我們先來看一下JanusGraph的基本概念。

如同大多數圖資料庫一樣,JanusGraph採用屬性圖進行建模。基於屬性圖的模型,JanusGraph有如下概念:

  • Vertex Label:節點的型別,用於表示現實世界中的實體型別,比如”人”,“車”。在JanusGraph中,每一個節點有且只有一個Vertex Label。當不顯式指定Vertex Label時,採用預設的Vertex Label。

  • Vertex:節點/頂點,用於表示現實世界中的實體物件。

  • Edge Label:邊的型別,用於表示現實世界中的關係型別,比如“通話關係”,“轉賬關係”,“微博關注關係”等;

  • Edge: 邊,用於表示一個個具體的聯絡。JanusGraph的邊都是單向邊。如果需要雙向邊,則通過兩條相反方向的單向邊組成。JanusGraph不存在無向邊。

  • Property Key

    :屬性的型別,比如“姓名”,“年齡”,“時間”等。Property Key有Cardinality的概念。Cardinality有SINGLE、LIST和SET三種選項。這三種選項分別用於表示一個Property中,對於同一個Property Key是隻允許有一個值、允許多個可重複的值,還是多個不可重複的值。

  • Property:屬性,用於表示一個個具體的附加資訊,採用Key-Value結構。Key就是Property Key,Value就是具體的值。

屬性圖舉例

張三與李四是同事關係,他們從2017年開始成為同事,用屬性圖表達:

圖切割

作為一種分散式圖資料庫,JanusGraph需要將資料切分儲存到多臺機器上。

典型的圖切割方法有兩種: 一種是按點切割,另一種是按邊切割

  • 按點切割(Vertex-Cut)

按Vertex切割時,切割線通過圖的Vertex,而不是Edge。每一條Edge邊只儲存一次,並且每一條Edge只出現在一臺機器上,鄰居多的Vertex會被分發到不同的機器上。

  • 按邊切割(Edge-Cut)

按Edge切割時,切割線只穿過連線vertex的edge,此時,每一個vertex只儲存一次。切斷的Edge會儲存到多臺機器上。

JanusGraph採用的分片方式是按Edge切割,而且是對於每一條邊,都會被切斷。切斷後,該邊會在起始Vertex上和目的Vertex上各儲存一次。通過這種方式,JanusGraph不管是通過起始Vertex,還是從目的Vertex,都能快速找到對端Vertex。

備註:

  1. 對於Super Node的儲存模式不同,這裡暫不展開討論。

  2. JanusGraph允許將Edge Label定義為單向感知的edge. 對於單向感知的edge,只會從起始vertex查詢此edge,不會從目的vertex反向查詢。因此,這種情況下,目的節點不儲存該vertex,僅在起始節點儲存。

儲存方式

還是以上面的例子為例,按邊切割後,變成如下結果:

在JanusGraph中,是點為中心,按切邊的方式儲存資料的。節點的ID作為HBase的Rowkey,節點上的每一個屬性和每一條邊,作為該Rowkey的一個個獨立的Cell。即每一個屬性、每一條邊,都是一個個獨立的KCV結構(Key-Column-Value)

如下圖所示:

備註: 簡化起見,此處暫不考慮節點中如何記錄其所屬的Vertex Label。

詳細儲存格式

Vertex儲存格式

  • Vertex ID以Rowkey的形式儲存在HBase中。Vertex ID總共64個bit。

  • Vertex ID由partition id、count、ID padding三部分組成。

  • 最高位5個bit是partition id. partition是JanusGraph抽象出的一個概念。當Storage Backend是HBase時,JanusGraph會根據partition數量,自動計算並配置各個HBase Region的split key,從而將各個partition均勻對映到HBase的多個Region中。然後通過均勻分配partition id最終實現資料均勻打散到Storage Backend的多臺機器中。

  • 中間的count部分是流水號,其中最高位位元固定為0.

  • 最後幾個bit是ID padding, 表示Vertex的型別。具體的位數長度根據不同的Vertex型別而不同。最常用的普通Vertex,其值為’000’。

各個Vertex型別字尾劃分如下(拷貝自原始碼):

Property儲存格式

一個Property Key所關聯的屬性值有可能有一個,也有可能有多個,因此,JanusGraph使用Cardinality來描述Property Key的這種特點。CardinalitySINGLE,LISTSET三種類型:

  • SINGLE表示一個Property Key只對應一個Value,這是最常用的場景。

  • LIST表示一個Property Key可以對應多個Value,多個Value可以有重複值。

  • SET表示一個Property Key可以對應多個Value,多個Value不可以有重複值。

JanusGraph的Property,在不同的Cardinality下,資料儲存結構略有不同。整體原則是:根據Cardinality的不同,列名本身能夠確定唯一的一個屬性

  • Cardinality為SINGLE時的儲存結構

HBase的列名只儲存Property Key的ID及方向。具體的Property Value值以及Property ID(JanusGraph為每一個Property分配的唯一ID),都存放在Cell的Value中。另外,如果該Property還有額外的Remaining properties,也會放在Value中。Remaining properties一般不使用,僅在一些特殊場景下,用於為該Property記錄更多的附加資訊(比如儲存元資料Edge Labe的定義等)。

PropertyKeyID及方向整個結構的詳細結構在後文中描述;屬性的值佔用一個或多個欄位,具體格式在後文描述;屬性的IDRemaining屬性採用相同的格式,具體格式在後文描述。

  • Candinality為LIST時的儲存結構

各個部分與Cardinality為SINGLE時的結構相似,區別在於屬性的ID被放在了列名中,而不是放在Value中。

  • Candinality為SET儲存結構

各個部分與Cardinality為SINGLE時的結構相似,區別在於屬性的值被放在了列名中,而不是放在Value中。

  • 屬性的Property Key ID和方向儲存結構

每一個Property Key本身也有一個唯一的ID。為標識各個屬性是屬於哪一種Property Key,JanusGraph記錄了各個屬性對應的Property Key的ID。JanusGraph在儲存時,會將Property Key ID以及DirectionID(分系統型別/隱藏/常規不隱藏三種屬性)組裝在一起,使用多個位元組來表示。

  • 屬性的ID和屬性值儲存結構

屬性的值根據Property Key中定義的資料型別不同,有不同的序列化器。比如,String有StringSerializer, integer有IntegerSerializer. 其中IntegerSerializer與屬性ID的格式化方式相同。

屬性的ID作為一種無符號整數,JanusGraph將其格式化為多個位元組。每一個位元組的最高位位元用於表示是最後一個位元組。0表示不是最後一個位元組,1表示是最後一個位元組。

邊儲存格式

JanusGraph的Edge Label也有一個MULTIPLICITY概念。MULTIPLICITYMULTI等不同的取值,其中以MULTI取值最為常用。

  • MULTIPLICITY為MULTI時的儲存結構

邊的儲存格式與屬性類似,Property Key和Edge Label被抽象成了Relation Type,並採用相同的資料結構。SortKey是一種特殊的屬性。JanusGraph允許在定義Edge Label時指定其中的一個或多個屬性為Sort Key。對於邊的Sort Key屬性,JanusGraph在儲存時會將其儲存在Relation Type ID的後面,其他所有欄位的前面。通過這種方式,可以保證一個節點的多條同一個型別的邊,會按Sort Key屬性排序儲存。這對於一個節點有大量邊時,對查詢效能提升有幫助。

 

  • MULTIPLICITY不是MULTI並且此方向有多條邊時的儲存結構

  • MULTIPLICITY不是MULTI並且此方向僅有一條邊時的儲存結構

以上系作者根據自己對原始碼的理解整理而成,難免有不準確或者不全面的地方。歡迎指正,交流。