「JanusGraph」圖形數據庫 - 技術選型調研

JanusGraph各組件版本兼容性匹配表

JanusGraph

JanusGraph提供多種後端存儲和後端索引,使其能夠更靈活的部署。本章介紹了幾種可能的部署場景,以幫助解決這種靈活性帶來的複雜性。

在討論部署場景之前,理解JanusGraph本身的角色定位和後端存儲的角色定位是非常重要的。首先,應用程序與JanusGraph進行交互大多數情況下都是進行Gremlin遍歷,然後,JanusGraph把遍歷請求發給配置好的後端(存儲後端、索引後端)執行遍歷處理。當JanusGraph以服務的形式被使用的時候,將不會有主服務(master JanusGraph Server)。應用程序可以連接任何一個JanusGraph服務實例。這樣就可以使用負載均衡把請求分配到不同的實例上。JanusGraph服務實例之間本身是沒有之間聯繫的,當遍歷處理增大的時候這更容易擴容。

 

JanusGraph與Apache Cassandra的好處

  • 連續可用,沒有單點故障。
  • 由於沒有主/從架構,因此圖形沒有讀/寫瓶頸
  • 彈性可擴展性允許引入和移除機器。
  • 緩存層可確保內存中可連續訪問的數據。
  • 通過向羣集添加更多計算機來增加緩存的大小。
  • Apache Hadoop集成。

Cassandra本身優點

  • 適合做數據分析或數據倉庫這類需要迅速查找且數據量大的應用
  • 存儲結構比Key-Value數據庫(像Redis)更豐富
  • Cassandra 的數據模型是基於Column族的四維或五維模型(聚合查詢在列表上執行得更快)

Cassandra本身缺點

  • 不能簡單增加服務器解決請求量增長的問題,需要數據架構師精細的規劃
  • 數據先緩存到Mentable,再刷新到磁盤,
  • Memtable

JanusGraph與HBase的好處

JanusGraph和CAP定理

使用數據庫時,應充分考慮CAP定理(C =一致性,A =可用性,P =可分區性)

  • HBase以產量爲代價優先考慮一致性,即完成請求的概率。
  • Cassandra以收穫爲代價優先考慮可用性,即查詢答案的完整性(可用數據/完整數據)。

JanusGraph的CAP

CAP定理說的是:一個分佈式計算機系統無法同時滿足以下三點(定義摘自Wikipedia):

  • 一致性(Consistency) ,所有節點訪問同一份最新的數據副本
  • 可用性(Availability),每次請求都能獲取到非錯的響應——但是不保證獲取的數據爲最新數據
  • 分區容錯性(Partition tolerance),以實際效果而言,分區相當於對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味着發生了分區的情況,必須就當前操作在C和A之間做出選擇。

關於JanusGraph在CAP理論上的側重,是要看底層存儲的。如果底層是Cassandra,那麼就是偏向於AP(Cassandra是最終一致性的);如果底層是HBase,就是偏向於CP(強一致性);BerkleyDB單機不存在這個問題。

 

 

 

JG. Version 0.3.1各依賴組件版本兼容性 (Release Date: October 2, 2018)

<dependency>

<groupId>org.janusgraph</groupId>

<artifactId>janusgraph-core</artifactId>

<version>0.3.1</version></dependency>

Tested Compatibility:

  • Apache Cassandra 2.1.20, 2.2.10, 3.0.14, 3.11.0
  • Apache HBase 1.2.6, 1.3.1, 1.4.4
  • Google Bigtable 1.0.0, 1.1.2, 1.2.0, 1.3.0, 1.4.0
  • Oracle BerkeleyJE 7.4.5
  • Elasticsearch 1.7.6, 2.4.6, 5.6.5, 6.0.1
  • Apache Lucene 7.0.0
  • Apache Solr 5.5.4, 6.6.1, 7.0.0
  • Apache TinkerPop 3.3.3
  • Java 1.8

有關0.3.1中的功能和錯誤修復的更多信息,請參閱GitHub milestone:

JG安裝配置

JanusGraph0.3.1 OLAP開發環境搭建

https://blog.csdn.net/qq_37286005/article/details/85071050

 

安裝zookeeper

這裏安裝的是單機模式。版本是zookeeper-3.4.9.tar.gz。已裝,步驟略。(看我博客-集羣安裝)

 

安裝Hbase單機模式

配置Hbase

1.下載:https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/2.1.2/hbase-2.1.2-bin.tar.gz

2.~$ gedit .bashrc

# hbase
export HBASE_HOME=/home/raini/app/hbase
export PATH=${HBASE_HOME}/bin:$PATH

3.~$ source .bashrc

hbase-env.sh

## 追加:
export JAVA_HOME=/home/raini/app/jdk
export HBASE_CLASSPATH=/home/raini/app/hbase/conf/
export HBASE_PID_DIR=/home/raini/app/tmp/pids

# 不使用HBase自帶的zookeeper
export HBASE_MANAGES_ZK=false

 

zoo.cfg

在這裏我們使用的不是HBase自帶的zookeeper,而是之前已經裝好的,所以需要將我們現在的zookeeper的zoo.cfg文件複製到hbase的conf目錄下

hbase-site.xml 

#添加如下內容:
<configuration>
  <property>
    <name>hbase.rootdir</name>   
    <value>hdfs://biyuzhe:9000/hbase</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>   
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.quorum</name>   
    <value>127.0.0.1</value>
  </property>
<!--  <property>
		<name>hbase.zookeeper.property.clientPort</name>
		<value>2181</value>
  </property>
  <property>
    <name>hbase.tmp.dir</name>   
    <value>/home/raini/app/tmp/hbase/</value>
  </property>
  <property>
    <name>hbase.master</name>   
    <value>biyuzhe:60000</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/home/raini/app/tmp/hbase_zoo_dataDir</value>
  </property>
  <property>
    <name>hbase.wal.provider</name>
    <value>file://home/raini/tmp/hbase-wal</value>
  </property>-->
  <property>
           <name>dfs.replication</name>
           <value>1</value>
  </property>
  <property>
        <name>hbase.master.maxclockskew</name>
        <value>150000</value>
  </property>
  <property>

 

一些注意點:

<configuration>
	<property>
		<name>hbase.rootdir</name>
		<value>file:///usr/local/hbase-1.4.0/data-tmp</value>
	</property>
  	<property>
		<name>hbase.zookeeper.quorum</name>  
		<value>localhost</value>  
	</property>

	<property>
		<name>hbase.zookeeper.property.clientPort</name>
		<value>2181</value>
	</property>

	<property>
		<name>hbase.zookeeper.property.dataDir</name>  
		<value>/tmp/zookeeper</value>  
	</property>

	<property>
		<name>hbase.cluster.distributed</name>
		<value>true</value>
	</property>

	<property>
		<name>zookeeper.znode.parent</name>
		<value>/hbase</value>
	</property>
</configuration>

注意的環節:

  1. 一定要加上“僞分佈:hbase.cluster.distributed”的這個<property>標籤,否則即使是單機的分佈【雖然是單機,但是並沒有使用HBase自帶的zookeeper】,所以理論上還是應該使用僞分佈式的搭配。
  2. hbase.rootdir這個屬性的值在筆者的環境下是file:///usr/local/hbase-1.4.0/data-tmp,並沒有使用hdfs來存儲。也就意味着不需要事先啓動hdfs。但是如果將這個目錄改爲hdfs的對應目錄,則是需要在啓用hbase之前啓用hdfs。
  3. hbase.zookeeper.quorum指的是zookeeper服務器的地址,因爲這裏是單機版,所以直接填寫localhost即可。有些博客建議寫與hostname不同的主機ip。
  4. hbase.zookeeper.property.clientPort指的是zookeeper的端口號,如果沒有修改的話,默認的則是2181。
  5. zookeeper.znode.parent ZooKeeper中的Hbase的根ZNode。所有的Hbase的ZooKeeper會用這個目錄的值來配置相對路徑。【znode存放root region的地址】默認情況下,所有的Hbase的ZooKeeper文件路徑是用相對路徑,所以他們會都去這個目錄下面。默認: /hbase

---------------------

regionservers 

#修改爲主機名   <----建議寫與hostname不同的主機ip

 

啓動HBase

[raini@biyuzhe ~]# start-all.sh #啓動hadoop

[raini@biyuzhe ~]# zkServer.sh start #啓動zookeeper

[raini@biyuzhe ~]# zkServer.sh status #查看zookeeper狀態以及角色

[raini@biyuzhe ~]# start-hbase.sh #啓動Hbase

 

啓動報錯:Caused by: java.lang.ClassNotFoundException: org.apache.htrace.SamplerBuilder

解決:

cp $HBASE_HOME/lib/client-facing-thirdparty/htrace-core-3.1.0-incubating.jar $HBASE_HOME/lib/

 

[raini@biyuzhe ~]# JPS 查看hbase進程

 

Hbase簡單操作

raini@biyuzhe:~$ hbase shell

hbase(main):001:0> status #查看HBase運行狀態

1 active master, 0 backup masters, 1 servers, 0 dead, 0.0000 average load

Took 0.3634 seconds

hbase(main):002:0> exit #退出

 

遇到問題

hbase集羣[部分]節點HRegionServer啓動後自動關閉的問題

註釋掉hbase-size.xml這部分得以解決:

<!--  <property>

<name>hbase.zookeeper.property.clientPort</name>

<value>2181</value>

  </property>

  <property>

    <name>hbase.tmp.dir</name>   

    <value>/home/raini/app/tmp/hbase/</value>

  </property>

  <property>

    <name>hbase.master</name>   

    <value>biyuzhe:60000</value>

  </property>

  <property>

    <name>hbase.zookeeper.property.dataDir</name>

    <value>/home/raini/app/tmp/hbase_zoo_dataDir</value>

  </property>

  <property>

    <name>hbase.wal.provider</name>

    <value>file://home/raini/tmp/hbase-wal</value>

  </property>-->

:應該是舊數據的影響,可刪除掉這些臨時文件

 

JG+HBase+Caching+ES config

 

設置JanusGraph使用遠程運行的HBase存儲引擎,爲了獲取更好的性能,同時使用JanusGraph的緩存組件。

 

janusgarph.properties

storage.backend=hbase

storage.hostname=100.100.101.1

storage.port=2181

cache.db-cache = true

cache.db-cache-clean-wait = 20

cache.db-cache-time = 180000

cache.db-cache-size = 0.5

index.search.backend=elasticsearch

index.search.hostname=100.100.101.1, 100.100.101.2

index.search.elasticsearch.client-only=true

 

使用該配置遇到問題:

janusGraph(Hbase客戶端)連不上Hbase服務器,zookeeperNode我們在Hbase安裝時hbase-site.xml設置成了/hbase-jg,所以這裏需要明確指定:

storage.hbase.ext.hbase.zookeeper.property.clientPort=2181
storage.hbase.ext.zookeeper.znode.parent=/hbase-jp

 

 

JanusGraph單機部署-2法

 

注:

[1] ElasticSearch因爲是壓縮包的方式,只能以非root用戶啓動,所以需要使用普通用戶安裝

[2] Linux下JanusGraph自帶了一個JanusGraph Server的配置和腳本,可以直接啓動JanusGraph Server;

 

Linux下JanusGraph的安裝步驟

  • [1] 將壓縮包上傳到用戶根目錄下並解壓

注意:這裏假設用戶名爲raini,不能用root,前面已說明。

 

  • [2] 修改權限

修改安裝包的權限,以便raini用戶能夠訪問/opt下的janusgraph包

raini@biyuzhe:~/app$ sudo chown -R raini:raini janusgraph-0.3.1-hadoop2

 

  • JanusGraph的啓動

本文采用的是JanusGraph+Berkeley+ES的部署模式,也就是說後端存儲採用BerkeleyDB、外部索引採用ElasticSearch。因此,BerkeleyDB是嵌入式的,不需要單獨啓動,但ElasticSearch需要在JanusGraph之前啓動。

 

  • 啓動ElasticSearch

JanusGraph自帶了ElasticSearch的安裝包,先進入該目錄,加上&以便在後臺啓動

raini@biyuzhe:~/app/janusgraph$ elasticsearch/bin/elasticsearch &

 

  • JanusGraph的基本使用

JanusGraph的使用方式通常包括:

[1] 以嵌入式開發(Java)的方式訪問;

[2] 通過Gremlin Console控制檯訪問;

[3] 通過JanusGraph Server的方式訪問;

這裏先只介紹Gremlin Console的方式,其他方式將在後面陸續介紹。

 

  • JanusGraph Gremlin Console

[1] 啓動Gremlin Console

[raini@biyuzhe: janusgraph-0.3.1-hadoop2]$ bin/gremlin.sh

 

[2] 開啓一個圖數據庫實例

gremlin> graph = JanusGraphFactory.open('conf/janusgraph-berkeleyje-es.properties')

==>standardjanusgraph[berkeleyje:/opt/janusgraph-0.3.1-hadoop2/conf/../db/berkeley]

 

JanusGraph默認有很多種配置,這裏採用文前提到的配置模式。

 

[3] 獲取圖遍歷句柄

 

gremlin> g = graph.traversal()

==>graphtraversalsource[standardjanusgraph[berkeleyje:/opt/janusgraph-0.3.1-hadoop2/conf/../db/berkeley], standard]

 

[4] 通過圖遍歷句柄來進行各種圖操作

新增一個頂點(vertex)

gremlin> g.addV('person').property('name','Dennis')

==>v[4104]

 

查詢剛剛創建的頂點

gremlin> g.V().has('name', 'Dennis').values()

 

參考資料:

[1] http://janusgraph.org/

 

 

啓動janusGraph(gremlin-server)

備註:不要直接啓動bin目錄下的gremlin-server.sh,會缺少初始化,elasticsearch和cassandra等配置。

  cd /path_to/janusgraph-0.3.1-hadoop2 使用:

  bin/janusgraph.sh start

 

  • 啓動ElasticSearch

JanusGraph自帶了ElasticSearch的安裝包,先進入該目錄,加上&以便在後臺啓動

raini@biyuzhe:~/app/janusgraph$ elasticsearch/bin/elasticsearch &

raini@biyuzhe:~/app/janusgraph$ bin/janusgraph.sh stop

 

啓動janusgraph server:

bin/gremlin-server.sh ./conf/gremlin-server/byz-gremlin-server.yaml

 

JanusGraph Server

JanusGraph通過gremlin-server提供服務,有兩種模式:WebSocket和HTTP,兩種模式無法同時存在於同一個實例上,但是可以通過創建兩個實例達到共存的目的---(0.3以後貌似可以共存了,接下來測試一下)。官網描述略長,這裏總結得簡單一些。默認後端使用HBase+ElasticSearch。

具體步驟如下:

1. 從Github release頁下載 janusgraph-{VERSION}-hadoop2.zip ,並解壓

2. 準備 .properties 文件

cp conf/janusgraph-hbase-es.properties conf/gremlin-server/janusgraph-hbase-es-server.properties

並在新文件開始添加

gremlin.graph=org.janusgraph.core.JanusGraphFactory

3. 準備 gremlin-server.yaml ,這裏寫了兩個實例配置

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

3.1 修改 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

3.2 修改 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

4. 啓動server

bin/gremlin-server.sh ./conf/gremlin-server/socket-gremlin-server.yaml

bin/gremlin-server.sh ./conf/gremlin-server/http-gremlin-server.yaml

成功後會在屏幕上打log

[gremlin-server-boss-1] INFO  org.apache.tinkerpop.gremlin.server.GremlinServer  - Channel started at port XXXX.

 

Ps:因爲我配置的host是[0.0.0.0],所以service啓動的機器可能不確定,我這裏是node3。

    所以如下conf/remote.yaml中也需要配置爲node3才能連接上

 

5.1 測試WebSocket

使用gremlin測試,打開 bin/gremlin.sh

~/Setups/janusgraph-0.3.1-hadoop2/bin> bin/gremlin.sh

 

         \,,,/

         (o o)

-----oOOo-(3)-oOOo-----

plugin activated: janusgraph.imports

plugin activated: tinkerpop.server

plugin activated: tinkerpop.utilities

plugin activated: tinkerpop.hadoop

plugin activated: tinkerpop.spark

plugin activated: tinkerpop.tinkergraph

gremlin> :remote connect tinkerpop.server conf/byz-remote.yaml

==>Configured localhost/127.0.0.1:8182

gremlin> :remote console (如果不執行這一步,往下每一個操作的命令前都要加上 :> :>g.V().values('name'))

gremlin>

==>yiz96

:> 符號是立即執行的意思。如果修改過port,同時也要修改一下 conf/remote.conf 。

5.2 測試HTTP

1

curl -XPOST -Hcontent-type:application/json -d '{"gremlin":"g.V().values(\"name\")"}' http://localhost:8183

注意不要使用單引號,會報錯

1

{"requestId":"6542a2b5-15bb-4b8e-82cd-50ea1d12e586","status":{"message":"","code":200,"attributes":{}},"result":{"data":["yiz96"],"meta":{}}}%

 

失敗了:

問題:(啓動remote服務報錯)

 

java.lang.IllegalStateException: javax.script.ScriptException: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: graph for class: Script1

使用:

gremlin> :remote connect tinkerpop.server conf/byz-remote.yaml

==>Configured localhost/127.0.0.1:8182

gremlin> :remote console

==>All scripts will now be sent to Gremlin Server - [localhost/127.0.0.1:8182] - type ':remote console' to return to local mode

gremlin> map = new HashMap<String, Object>();

gremlin> map

No such property: map for class: Script4

Type ':help' or ':h' for help.

Display stack trace? [yN]

gremlin>

 

 

 

解決:

(錯誤的解決):

scripts/empty-sample.groovy定義了默認圖形“圖形”上的綁定,該圖形不可用。

需要從配置中更新或刪除scripts/empty-sample.groovy。或者註釋掉:
//定義默認的TraversalSource來綁定查詢 - 這個將被命名爲“g”。
// globals << [g:graph.traversal()]

 

正解:

不能去掉:scripts/empty-sample.groovy中~~ {files: [scripts/empty-sample.groovy]

如下加入正確的依賴即可:

問題:remote connect gremlin-server No such property: for class: Script

解決:

很簡單,是自己使用問題。因爲一般的教程、博客、官網都不會提到這個,還是去國外網站找到的。

加上session就行。

:remote connect tinkerpop.server conf/byz-remote.yaml session

:remote console

 

 

問題:GraphFactory could not instantiate this Graph implementation


1042 [main] WARN  org.apache.tinkerpop.gremlin.server.GremlinServer  - Graph [graph] configured at [conf/gremlin-server/ws-janusgraph-hbase-es.properties] could not be instantiated and will not be available in Gremlin Server.  GraphFactory message: GraphFactory could not instantiate this Graph implementation [class org.janusgraph.core.JanusGraphFactory]
java.lang.RuntimeException: GraphFactory could not instantiate this Graph implementation [class org.janusgraph.core.JanusGraphFactory]
at org.apache.tinkerpop.gremlin.structure.util.GraphFactory.open(GraphFactory.java:82)
at org.apache.tinkerpop.gremlin.structure.util.GraphFactory.open(GraphFactory.java:70)
at org.apache.tinkerpop.gremlin.structure.util.GraphFactory.open(GraphFactory.java:104)
at org.apache.tinkerpop.gremlin.server.util.DefaultGraphManager.lambda$new$0(DefaultGraphManager.java:57)
at java.util.LinkedHashMap$LinkedEntrySet.forEach(LinkedHashMap.java:671)
at org.apache.tinkerpop.gremlin.server.util.DefaultGraphManager.<init>(DefaultGraphManager.java:55)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.apache.tinkerpop.gremlin.server.util.ServerGremlinExecutor.<init>(ServerGremlinExecutor.java:80)
at org.apache.tinkerpop.gremlin.server.GremlinServer.<init>(GremlinServer.java:120)
at org.apache.tinkerpop.gremlin.server.GremlinServer.<init>(GremlinServer.java:84)
at org.apache.tinkerpop.gremlin.server.GremlinServer.main(GremlinServer.java:343)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tinkerpop.gremlin.structure.util.GraphFactory.open(GraphFactory.java:78)
... 13 more
Caused by: java.lang.IllegalArgumentException: Could not instantiate implementation: org.janusgraph.diskstorage.hbase.HBaseStoreManager
at org.janusgraph.util.system.ConfigurationUtil.instantiate(ConfigurationUtil.java:64)
at org.janusgraph.diskstorage.Backend.getImplementationClass(Backend.java:476)
at org.janusgraph.diskstorage.Backend.getStorageManager(Backend.java:408)
at org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.<init>(GraphDatabaseConfiguration.java:1254)
at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:160)
at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:131)
at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:111)
... 18 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.janusgraph.util.system.ConfigurationUtil.instantiate(ConfigurationUtil.java:58)
... 24 more
Caused by: java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/protobuf/generated/MasterProtos$MasterService$BlockingInterface
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.apache.hadoop.hbase.client.ConnectionFactory.createConnection(ConnectionFactory.java:228)
at org.apache.hadoop.hbase.client.ConnectionFactory.createConnection(ConnectionFactory.java:218)
at org.apache.hadoop.hbase.client.ConnectionFactory.createConnection(ConnectionFactory.java:119)
at org.janusgraph.diskstorage.hbase.HBaseCompat1_0.createConnection(HBaseCompat1_0.java:43)
at org.janusgraph.diskstorage.hbase.HBaseStoreManager.<init>(HBaseStoreManager.java:334)
... 29 more
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.protobuf.generated.MasterProtos$MasterService$BlockingInterface
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 36 more

解決:

引入hbase-protocol-1.4.9.jar與protobuf-java-2.5.0.jar包即可。

(必要時也可將hbase-hadoop2-compat-1.4.9.jar--hbase與hadoop的兼容性包 引入)

 

 

JanusGraph與TinkerPop的Hadoop-Gremlin整合

本章介紹如何利用Apache HadoopApache Spark配置JanusGraph以進行分佈式圖形處理。這些步驟將概述如何開始這些項目,但請參考這些項目社區以更熟悉它們。

JanusGraph-Hadoop與TinkerPop的hadoop-gremlin包一起用於通用OLAP。

對於下面示例的範圍,Apache Spark是計算框架,Apache Cassandra是存儲後端。可以使用其他包進行指示,並對配置屬性進行微小更改。

注意

本章中的示例基於在本地模式或獨立羣集模式下運行Spark。在YARN或Mesos上使用Spark時,需要進行其他配置。

配置Hadoop以運行OLAP

要從Gremlin控制檯運行OLAP查詢,需要滿足一些先決條件。您需要將Hadoop配置目錄添加到其中CLASSPATH,配置目錄需要指向實時Hadoop集羣。

Hadoop提供分佈式訪問控制的文件系統。運行在不同計算機上的Spark工作程序使用Hadoop文件系統來獲得基於文件的操作的公共源。各種OLAP查詢的中間計算可以保留在Hadoop文件系統上。

有關配置單節點Hadoop集羣的信息,請參閱官方Apache Hadoop文檔

一旦啓動並運行Hadoop集羣,我們將需要在中指定Hadoop配置文件CLASSPATH。下面的文檔希望您將這些配置文件放在下面/etc/hadoop/conf。

驗證後,按照以下步驟將Hadoop配置添加到CLASSPATH並啓動Gremlin控制檯,它將扮演Spark驅動程序的角色。

主要配置(bin/gremlin.sh)

在前邊加入:

export HADOOP_HOME=/home/raini/app/hadoop
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$HADOOP_HOME/lib/native"
export CLASSPATH=$HADOOP_CONF_DIR

一旦添加了Hadoop配置的路徑CLASSPATH,我們就可以通過以下快速步驟驗證Gremlin控制檯是否可以訪問Hadoop集羣:

從janusGraph中啓動:

$ bin/gremlin.sh

在終端輸入:

gremlin> hdfs

==>storage[org.apache.hadoop.fs.LocalFileSystem@65bb9029] // BAD(沒配置之前)

gremlin> hdfs

==>storage[DFS[DFSClient[clientName=DFSClient_NONMAPREDUCE_1229457199_1, ugi=user (auth:SIMPLE)]]] // GOOD(配置之後,可見使用hdfs進行存儲)

OLAP遍歷(使用Spark)

JanusGraph-Hadoop使用TinkerPop的hadoop-gremlin包進行通用OLAP遍歷圖,並通過利用Apache Spark並行化查詢。

配置使用Spark作爲OLAP執行引擎+Hbase後端

將需要特定於該存儲後端的附加配置。配置由gremlin.hadoop.graphReader屬性指定,該屬性指定從存儲後端讀取數據的類。

如JanusGraph的Hbase graphReader類:

HBaseInputFormat和HBaseSnapshotInputFormatHBase一起使用

以下屬性文件可用於連接Hbase中的JanusGraph實例,以便它可以與HadoopGraph一起使用來運行OLAP查詢。

Github地址:

https://github.com/JanusGraph/janusgraph/blob/d12adfbf083f575fa48860daa37bfbd0e6095369/janusgraph-dist/src/assembly/static/conf/hadoop-graph/read-hbase-snapshot.properties

 

conf/hadoop-graph/read-hbase-snapshot.properties

 

#

# Hadoop Graph Configuration

#

gremlin.graph=org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph

gremlin.hadoop.graphReader=org.janusgraph.hadoop.formats.hbase.HBaseSnapshotInputFormat

gremlin.hadoop.graphWriter=org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoOutputFormat

 

gremlin.hadoop.jarsInDistributedCache=true

gremlin.hadoop.inputLocation=none

gremlin.hadoop.outputLocation=output

 

#

# JanusGraph HBaseSnapshotInputFormat configuration

#

janusgraphmr.ioformat.conf.storage.backend=hbase

janusgraphmr.ioformat.conf.storage.hostname=localhost

janusgraphmr.ioformat.conf.storage.hbase.table=janusgraph

janusgraphmr.ioformat.conf.storage.hbase.snapshot-name=janusgraph-snapshot

janusgraphmr.ioformat.conf.storage.hbase.snapshot-restore-dir=/tmp

janusgraphmr.ioformat.conf.storage.hbase.ext.hbase.rootdir=/hbase

 

#

# SparkGraphComputer Configuration

#

spark.master=local[4]

spark.serializer=org.apache.spark.serializer.KryoSerializer

 

conf/hadoop-graph/read-hbase.properties

#

# Hadoop Graph Configuration

#

gremlin.graph=org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph

gremlin.hadoop.graphReader=org.janusgraph.hadoop.formats.hbase.HBaseInputFormat

gremlin.hadoop.graphWriter=org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoOutputFormat

 

gremlin.hadoop.jarsInDistributedCache=true

gremlin.hadoop.inputLocation=none

gremlin.hadoop.outputLocation=output

 

#

# JanusGraph HBase InputFormat configuration

#

janusgraphmr.ioformat.conf.storage.backend=hbase

janusgraphmr.ioformat.conf.storage.hostname=localhost

janusgraphmr.ioformat.conf.storage.hbase.table=janusgraph

 

#

# SparkGraphComputer Configuration

#

spark.master=local[4]

spark.serializer=org.apache.spark.serializer.KryoSerializer

 

。。。更多看文檔:https://github.com/JanusGraph/janusgraph/blob/dee1400a3ab953ed5f4bd43eec8a38f2d7b6ff3c/docs/hadoop.adoc


使用Spark Standalone Cluster進行OLAP遍歷

上一節中遵循的步驟也可以與Spark獨立羣集一起使用,只需進行少量更改:

更新spark.master屬性以指向Spark主URL而不是本地URL

更新spark.executor.extraClassPath以啓用Spark執行程序以查找JanusGraph依賴項jar

將JanusGraph依賴項jar複製到每個Spark執行器計算機上一步中指定的位置

注意

我們將janusgraph-distribution / lib下的所有jar複製到/ opt / lib / janusgraph /中,並在所有worker中創建相同的目錄結構,並在所有worker中手動複製jar。

用於OLAP遍歷的最終屬性文件如下:

。。。

參考文檔:

https://github.com/JanusGraph/janusgraph/blob/dee1400a3ab953ed5f4bd43eec8a38f2d7b6ff3c/docs/hadoop.adoc

小例子:

(gremlin以及其它參考配置:janusgraph/janusgraph-dist/src/assembly/static/conf/hadoop-graph/

g.V().hasLabel('NewsPaper').has('identifier', 'xyz').inE('belongsTo').outV().hasLabel('NewsDocument')

.has('publishedDate', between(begin.getTime, end.getTime))

數據類型

(導入數據第一步,首先去掉空行、缺失頂點、重複頂點等,然後將數據做成這種格式-GraphSon)

多條:

{"id":2000,"label":"message","inE":{"link":[{"id":5,"outV":2000}]},"outE":{"link":[{"id":4,"inV":2001},{"id":5,"inV":2000}]},"properties":{"name":[{"id":2,"value":"a"}]}}
{"id":2001,"label":"message","inE":{"link":[{"id":4,"outV":2000}]},"properties":{"name":[{"id":3,"value":"b"}]}}
{"id":1000,"label":"loops","inE":{"self":[{"id":1,"outV":1000}]},"outE":{"self":[{"id":1,"inV":1000}]},"properties":{"name":[{"id":0,"value":"loop"}]}}

單條:


{
  "id": 2000,
  "label": "message",
  "inE": {
    "link": [
      {
        "id": 5,
        "outV": 2000
      }
    ]
  },
  "outE": {
    "link": [
      {
        "id": 4,
        "inV": 2001
      },
      {
        "id": 5,
        "inV": 2000
      }
    ]
  },
  "properties": {
    "name": [
      {
        "id": 2,
        "value": "a"
      }
    ]
  }
}

 

圖形配置

janusgraph-hbase.properties:

gremlin.graph=org.janusgraph.core.JanusGraphFactory
storage.backend=hbase
storage.hostname=localhost
cache.db-cache=true
cache.db-cache-clean-wait=20
cache.db-cache-time=180000
cache.db-cache-size=0.5
index.search.backend=elasticsearch
index.search.hostname=localhost
#storage.hbase.ext.zookeeper.znode.parent=/hbase-unsecure
storage.hbase.table=Medical-POC
index.search.index-name=Medical-POC

hadoop-graphson.properties

#gremlin.graph=org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph
#gremlin.hadoop.graphReader=org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoInputFormat
#gremlin.hadoop.graphWriter=org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoOutputFormat
#gremlin.hadoop.jarsInDistributedCache=true
gremlin.hadoop.defaultGraphComputer=org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer

gremlin.graph=org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph
gremlin.hadoop.graphInputFormat=org.apache.tinkerpop.gremlin.hadoop.structure.io.graphson.GraphSONInputFormat
gremlin.hadoop.graphOutputFormat=org.apache.hadoop.mapreduce.lib.output.NullOutputFormat
gremlin.hadoop.inputLocation=./data/byz/test-modern.json
gremlin.hadoop.outputLocation=output
gremlin.hadoop.jarsInDistributedCache=true

#####################################
# GiraphGraphComputer Configuration
#####################################
giraph.minWorkers=2
giraph.maxWorkers=2
giraph.useOutOfCoreGraph=true
giraph.useOutOfCoreMessages=true
mapred.map.child.java.opts=-Xmx1024m
mapred.reduce.child.java.opts=-Xmx1024m
giraph.numInputThreads=4
giraph.numComputeThreads=4
giraph.maxMessagesInMemory=100000

#
# SparkGraphComputer Configuration
#
#spark.master=local[4]
spark.master=spark://localhost:7077
spark.executor.memory=1g
spark.serializer=org.apache.spark.serializer.KryoSerializer
spark.kryo.registrator=org.apache.tinkerpop.gremlin.spark.structure.io.gryo.GryoRegistrator
spark.driver.memory=1g
# 爲了executor能找到janus相關包
spark.executor.extraClassPath=/home/raini/app/janusgraph/lib/*

編寫數據Schema:

janusgraph-schema.groovy

def defineGratefulDeadSchema(janusGraph) {
    m = janusGraph.openManagement()
    //人信息節點label
    person = m.makeVertexLabel("person").make()
    //properties
    //使用IncrementBulkLoader導入時,去掉下面註釋
    //blid  = m.makePropertyKey("bulkLoader.vertex.id").dataType(Long.class).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
    index = m.buildIndex("nameCompositeIndex", Vertex.class).addKey(name).unique().buildCompositeIndex()
    //使用IncrementBulkLoader導入時,去掉下面註釋
    //bidIndex = m.buildIndex("byBulkLoaderVertexId", Vertex.class).addKey(blid).indexOnly(person).buildCompositeIndex()
    m.commit()
}

執行Gremlin數據導入語句:

raini@biyuzhe:~/app/janusgraph$ bin/gremlin.sh

(1)
:load /home/raini/pro/GraphDatabase/test/src/main/scala/janusgraph-load/test-janusgraph-schema.groovy
graph = JanusGraphFactory.open('/home/raini/pro/GraphDatabase/test/src/main/scala/janusgraph-load/janusgraph-test.properties')
defineGratefulDeadSchema(graph)

(2)
graph = GraphFactory.open('data/zl/hadoop-graphson.properties')
blvp = BulkLoaderVertexProgram.build().bulkLoader(OneTimeBulkLoader).writeGraph('data/zl/janusgraph-test.properties').create(graph)
graph.compute(SparkGraphComputer).program(blvp).submit().get()
報錯:
    java.lang.InstantiationException

(3)
graph = JanusGraphFactory.open('data/zl/janusgraph-test.properties')
g = graph.traversal()
g.V().valueMap()

 

 

 

 

 

Configuring JanusGraph Server for ConfiguredGraphFactory

(配置JanusGraph的默認圖形配置)

配置在:/home/raini/app/janusgraph/conf/gremlin-server/gremlin-server-configuration.yaml

文檔說明:https://docs.janusgraph.org/latest/configuredgraphfactory.html

 

爲了能夠使用ConfiguredGraphFactory,您必須配置服務器以使用ConfigurationManagementGraphAPI。爲此,您必須在服務器的YAML graphs映射中注入名爲“ConfigurationManagementGraph”的圖形變量。例如:

graphManager: org.janusgraph.graphdb.management.JanusGraphManager
graphs: {
  ConfigurationManagementGraph: <--(修改這裏文件爲默認配置,如後端改爲Hbase

conf/JanusGraph-configurationmanagement.properties
}

在此示例中,我們的ConfigurationManagementGraph圖形將使用存儲在conf/JanusGraph-configurationmanagement.properties其中的屬性進行配置 ,例如,如下所示:

gremlin.graph=org.janusgraph.core.JanusGraphFactory
storage.backend=cql
graph.graphname=ConfigurationManagementGraph
storage.hostname=127.0.0.1

 

PS:(如上幾個參數一定爲必填項)

 

 

 

JG的3中使用方式

[1] 以嵌入式開發(Java)的方式訪問;

[2] 通過Gremlin Console控制檯訪問;

[3] 通過JanusGraph Server的方式訪問;

 

小測試例子

1.使用JanusGraph Gremlin Console方式

gremlin> graph = JanusGraphFactory.open('conf/janusgraph-berkeleyje-es.properties')

gremlin>graph.io(IoCore.graphson()).readGraph('/home/raini/app/janusgraph/data/tinkerpop-sink-v2d01.json')

gremlin> dennis = graph.addVertex(T.label, "person", "name", "Dennis","city", "Chengdu")

jady = graph.addVertex(T.label, "person", "name", "Jady","city", "Beijing")

dennis.addEdge("knows", jady, "date", "20121201")

或者gremlin>  g.addV('person').property('name','Dennis')

 

執行圖遍歷:

gremlin> g = graph.traversal()

使用Spark:gremlin> g=graph.traversal().withComputer(SparkGraphComputer)

 

gremlin> g.V().has('name', 'Dennis').values()

// ==>Dennis

// ==>Chengdu

 

gremlin> g.V().count()

// ==>2

 

gremlin> g.V().hasLabel('person')

// ==>v[4296]

// ==>v[4232] <---- lable是節點唯一值

 

2.使用GraphFactory Gremlin Console方式

graph = GraphFactory.open(...)

g = graph.traversal()

jupiter = g.addV("god").property("name", "jupiter").property("age", 5000).next()

sky = g.addV("location").property("name", "sky").next()

g.V(jupiter).as("a").V(sky).addE("lives").property("reason", "loves fresh breezes").from("a").next()

g.tx().commit()

g.V().has("name", "jupiter").valueMap(true).tryNext()

 

3.使用Gremlin io 錄入GraphSon數據

gremlin> graph = JanusGraphFactory.open('conf/janusgraph-hbase-spark.properties')

gremlin>graph.io(IoCore.graphson()).readGraph('/home/raini/app/janusgraph/data/tinkerpop-sink-v2d01.json')

gremlin> dennis = graph.addVertex(T.label, "person", "name", "Dennis","city", "Chengdu")

jady = graph.addVertex(T.label, "person", "name", "Jady","city", "Beijing")

dennis.addEdge("knows", jady, "date", "20121201")

//g = graph.traversal() 需要在.properties配置使用Spark
g=graph.traversal().withComputer(SparkGraphComputer)

 

 

 

問題:

遠程使用

:load ../schema.groovy

時,請注意其中

.cardinality(Cardinality.SINGLE)

Cardinality

使用的類:

正確爲應爲janusgraph中的類:

gremlin> Cardinality.SINGLE

==>SINGLE

gremlin> Cardinality

==>class org.janusgraph.core.Cardinality

 

而remote的爲tinkerpop中的類:

gremlin> :remote connect tinkerpop.server conf/byz-remote.yaml session
==>Configured biyuzhe/127.0.0.1:8182-[2ed42d86-882c-42b6-af31-6ca4fb5ee712]
gremlin> :remote console
==>All scripts will now be sent to Gremlin Server - [biyuzhe/127.0.0.1:8182]-[2ed42d86-882c-42b6-af31-6ca4fb5ee712] - type ':remote console' to return to local mode
gremlin> Cardinality.SINGLE
No such property: SINGLE for class: org.apache.tinkerpop.gremlin.structure.VertexProperty$Cardinality
Type ':help' or ':h' for help.
Display stack trace? [yN]
gremlin> Cardinality
==>class org.apache.tinkerpop.gremlin.structure.VertexProperty$Cardinality

解決:

name = mgmt.makePropertyKey("name").dataType(String.class).cardinality(Cardinality.SINGLE).make()

改爲明確類:

.cardinality(org.janusgraph.core.Cardinality.SINGLE)

 

還有BulkLoader:

gremlin> BulkLoaderVertexProgram

==>class org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgram

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章