背景: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/
更多内容请关注每日编程。
閱讀更多 每日編程 的文章