背景:JanusGraph是Titan的一個fork。Titan項目創建於2012年,於2016年停止維護,是一個方便拓展的圖數據庫,支持HBase、Cassandra等作為後端(BerkleyDB不提了),ES、Lucene等做全文索引,以TinkerPop作為圖的查詢和計算框架。2017年,JanusGraph項目fork了Titan,到目前已經推出了0.2.0版本。
JanusGraph是一個開源的分佈式圖數據庫。它具有很好的擴展性,通過多機集群可支持存儲和查詢數百億的頂點和邊的圖數據。JanusGraph是一個事務數據庫,支持大量用戶高併發地執行復雜的實時圖遍歷。
特性:
支持數據和用戶增長的彈性和線性擴展;
通過數據分發和複製來提過性能和容錯;
支持多數據中心的高可用和熱備份;
支持ACID 和最終一致性;
支持多種後端存儲:
Apache Cassandra
Apache HBase
Google Cloud Bigtable
Oracle BerkeleyDB(僅供測試環境)
支持全局的圖數據分析,報表以及和如下大數據平臺的ETL集成:
Apache Spark
Apache Giraph
Apache Hadoop
支持geo, 數值範圍以及通過如下工具進行全文檢索:
ElasticSearch
Apache Solr
Apache Lucene
支持與Apache TinkerPop圖棧進行原生集成:
Gremlin 圖查詢語言
Gremlin 圖服務器
Gremlin 應用
可以通過如下工具來可視化存儲在JanusGraph中的圖數據:
Cytoscape
Apache TinkerPop的Gephi插件
Graphexp
KeyLines by Cambridge Intelligence
Linkurious
### JaunsGraph數據模型
JanusGraph採用鄰接表(adjacency list)的方式存儲圖,也即圖以頂點(vertex)和其鄰接表組成。
鄰接表中保存某個頂點的所有入射邊(incident edges)。
通過將圖採用鄰接表的形式存儲,JanusGraph確保了某個頂點的所有入射邊和屬性都被緊湊的存儲在一起,從而能夠加快遍歷速度,缺點是數據存儲了兩次。而且JanusGraph以sort key指定的順序存儲數據。
JanusGraph可以採用任何支持big table數據模型的存儲後端存儲鄰接表。
JanusGraph將每個鄰接表作為以個row保存在存儲後端,64位的vertex id是指向鄰接表的key。
每個邊和屬性都是作為獨立的cell保存的,以實現更高效插入和刪除。每行中最大能保存的cell的個數,也就是vertex的edge的數量限制。
vertex id ---- cell,cell,cell……
cell --- 一個cell是由列和值組成的,每個edge和property都作為鄰接表的一個cell存儲
### JanusGraph支持兩種類型的索引:graph index和vertex-centric index。
graph index常用於根據屬性查詢Vertex或Edge的場景;
vertex index在圖遍歷場景非常高效,尤其是當Vertex有很多Edge的情況下。
JanusGraph支持兩種不同的Graph Index,Composte(複合) index和Mixed(混合) Index;
通過JanusGraph的management操作的:
JanusGraphManagement.buildIndex(String,Class)
第一個參數是index的名稱,第二個參數是要索引的類(如Vertex.class)
注意:如果沒有建索引,會進行全表掃面,此時性能非常低,可以通過配置force-index參數禁止全表掃描。Mixed index效率要比Composite Index低。
### JanusGraph中的事務
graph.V()即會開啟一個事務,graph.commit()則會提交一個事務。用戶也可以使用graph.newTransaction()獲取對事務的控制權。
事務在commit()或數據庫shutdown()時才結束。
對JanusGraph的每個操作都是在事務執行,無需顯式聲明,由第一次操作開啟。
### JanusGraph的schema及數據建模
每個JanusGraph都有一個schema,該schema由edge labels, property keys和vertex labels組成。
在JanusGraph中,一個Graph用於一個schema。
定義schema
def defineGratefulDeadSchema(janusGraph) {
m = janusGraph.openManagement()
person = m.makeVertexLabel("person").make()
birth = m.makePropertyKey("birth").dataType(Date.class).make()
age = m.makePropertyKey("age").dataType(Integer.class).make()
name = m.makePropertyKey("name").dataType(String.class).make()
index = m.buildIndex("nameCompositeIndex", Vertex.class).addKey(name).unique().buildCompositeIndex()
m.commit()
}
{"id":4700,"label":"person","properties":{"name":[{"id":"171-38o-5j9","value":"fu2 "}],"birth":[{"id":"1zh-38o-3yd","value":1509043638976}],"age":[{"id":"1l9-38o-4qt","value":1}]}}
### 安裝部署:centos 7 64bit,存儲後端為Hbase 1.3.1,Java取1.8.0_171,ElasticSearch;
JanusGraph通過gremlin-server提供服務,默認後端使用HBase+ElasticSearch。
Java8環境
安裝hadoop和hbase
安裝ES
安裝janusgraph
下載:https://github.com/JanusGraph/janusgraph/releases
janusgraph-0.2.1-hadoop2.zip
unzip ~/janusgraph-0.2.1-hadoop2.zip
cd janusgraph-0.2.1-hadoop2/
cp conf/janusgraph-hbase-es.properties conf/gremlin-server/janusgraph-hbase-es-server.properties
添加gremlin.graph=org.janusgraph.core.JanusGraphFactory
cp conf/gremlin-server/gremlin-server.yaml conf/gremlin-server/socket-gremlin-server.yaml
cp conf/gremlin-server/gremlin-server.yaml conf/gremlin-server/http-gremlin-server.yaml
修改 socket-gremlin-server.yaml
// host和port不爽也可以改,默認8182
graphs: {
graph: conf/gremlin-server/janusgraph-hbase-es-server.properties
}
channelizer: org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer
修改 http-gremlin-server.yaml
// port一定不要和websocket模式的衝突了…… 我設置的8183
graphs: {
graph: conf/gremlin-server/janusgraph-hbase-es-server.properties
}
channelizer: org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer
啟動server
bin/gremlin-server.sh ./conf/gremlin-server/socket-gremlin-server.yaml
bin/gremlin-server.sh ./conf/gremlin-server/http-gremlin-server.yaml
補充:
Gremlin控制檯解釋器使用的是Apache Groovy
默認情況下,JanusGraph使用Berkeley DB作為後端存儲引擎,使用Elasticsearch作為索引引擎。
如果配置JanusGraph集群, 需要定義存儲後臺. JanusGraphFactory接受一個分號分割的字符串, 分號前是存儲後臺類型的名稱, 分號後是主機名稱或者是目錄
graph = JanusGraphFactory.open('cassandra:localhost')
graph = JanusGraphFactory.open('berkeleyje:/tmp/graph')
Gremlin是一種函數式數據流語言,可以使得用戶使用簡潔的方式表述複雜的屬性圖(property graph)的遍歷或查詢。
每個Gremlin遍歷由一系列步驟(可能存在嵌套)組成,每一步都在數據流(data stream)上執行一個原子操作。
Gremlin包括三個基本的操作:
map-step
對數據流中的對象進行轉換;
filter-step
對數據流中的對象就行過濾;
sideEffect-step
對數據流進行計算統計;
參考文獻:
https://docs.janusgraph.org/latest/
更多內容請關注每日編程。
閱讀更多 每日編程 的文章