LoginSignup
4
1

More than 3 years have passed since last update.

JanusGraphの2つの使い方 - EmbeddedとServer

Last updated at Posted at 2020-04-30

JanusGraphを使ってグラフDBを構築するには、大きく2つの方法がある。EmbeddedとGremlin Serverである。

Embedded

TinkerPop - Embedded
その名の通り、実行するJVM(Java Virtual Machine)上に組み込まれるグラフDBであり、最小構成ではスタンドアロンで運用できる。シンプルなスタイル。

この方法の手順は概ね以下の通りになる。

  1. Graphのインスタンスを生成する
  2. GraphTraversalSourceのインターフェースを取得する
  3. クエリを発行し、結果を受け取る

簡単なソースコードで表すと以下のようになる(言語はgroovy)。

groovy
Graph graph = TinkerGraph.open();  // 空のグラフを生成
GraphTraversalSource g = graph.traversal();
g.addV("person").iterate();

グラフの生成の方法は様々ある。TinkerPopが用意するグラフ用のクラスはTinkerGraphTinkerFactoryがあるが、これらはデータの永続化やトランザクション処理が出来ない。JanusGraphは標準の方法としてJanusGraphFactoryを提供しており、これなら永続化もトランザクションも出来る。

以下はGremlinコンソール上でJanusGraphFactoryを使ってみるサンプルである(Windows10上でJanusGraph0.5.1を使用)。

Console
gremlin> graph = JanusGraphFactory.open("conf/janusgraph-berkeleyje-lucene.properties")
==>standardjanusgraph[berkeleyje:C:\******\janusgraph-0.5.1\conf\../db/berkeley]
gremlin> g = graph.traversal()
==>graphtraversalsource[standardjanusgraph[berkeleyje:C:\******\janusgraph-0.5.1\conf\../db/berkeley], standard]
gremlin> g.addV("person").property("name", "bob")
==>v[4112]

設定ファイルにはconf/janusgraph-berkeleyje-lucene.propertiesを使用した。これはストレージ・バックエンドにBerkeley DB、インデックス・バックエンドにLuceneライブラリを使用する設定である。ストレージはdb/berkeleyに生成・保存される。

JanusGraphではドキュメント中のコードではEmbeddedグラフを使ったコードを記載しているので、まずはこちらに親しむのが得策と思われる。

Gremlin Server

サーバーについては既にJanusGraphによるグラフDB入門という記事の中で少し説明しているので、そちらも参照のこと。

こちらはEmbeddedとは違い、専用のサーバープロセスを立ち上げ、ポートを通じてクライアントと接続する。こちらの方法ではJanusGraphFactoryなどは使用できない。その代わりに以下の2種類の接続方法が使える。

  • DriverRemoteConnectionAnonymousTraversalSourceを使った接続
  • ClusterClientを使った接続

DriverRemoteConnection&AnonymousTraversalSource

TinkerPopドキュメント - Connecting Gremlin Server

こちらはEmbeddedの場合と似通っていて、分かりやすい手法である。

  1. DriverRemoteConnectionを使ってサーバーとの接続を確立する
  2. AnonymousTraversalを使ってGraphTraversalSource(g)を獲得する
  3. クエリを送信し、結果を取得する
  4. 終わったら接続を閉じる
groovy
connection = DriverRemoteConnection.using('localhost', 8182, 'g')
g = AnonymousTraversalSource.traversal().withRemote(connection)
vertices = g.V().id().toList()
connection.close()

この方法の場合の特徴は2つある
- GraphTraversalSource(g)は取得できるが、Graph(graph)は取得できないので、ManagementSystem(スキーマやインデックスの定義インターフェース)や、AddVertexaddEdgeといった"structure API"へのアクセスが制限される。
- 毎回のクエリ実行は1つのトランザクションでラッピングされて実行される。自分で複数のクエリを1つのトランザクションとして実行するような制御は出来ない。

TinkerPop javadoc - DriverRemoteConnection
TinkerPop javadoc - AnonymousTraversalSource

Cluster&Client

TinkerPopドキュメント - Connecting Via Drivers

こちらは比較的泥臭いスタイルとなる。

  1. Clusterを使ってサーバーとの接続を確立する(言語によっては不要)
  2. Clientを使って、クエリメッセージを送信できる状態にする
  3. クエリを送信し、結果を受け取る
  4. Clientを使い終わったら、Client.closeで処分
  5. Clusterを使い終わったら、Cluster.closeで処分
groovy
cluster = Cluster.open()  // 引数省略時はlocalhost:8182に接続
client = cluster.connect()
result = client.submit("g.V().count()")  // 直接文字列で送信
print(result[0].object)
client.close()
cluster.close()

この場合、クエリは文字列で指定する。なおGremlinの場合もインジェクション攻撃が存在し、Gremlin Injectionと呼ばれている。対策については大体SQLの場合と同じ(Parameterized Scriptsを参照)

Cluster.connectは2引数のオーバーライドconnect(sessionID, manageTransactions)を持つ。第二引数のmanageTransactionsfalseの場合、自動でのトランザクション管理は行われず、ユーザーが自分でトランザクションを管理することができる(ただし正しく扱う責任が生じる)。trueの場合はsubmitを行うたびに自動的にトランザクションが開始され、送信したクエリの最後にコミットまたはロールバックが行われる。引数なしのconnectを実行した場合はmanageTransactions=trueがデフォルトである。

groovy
cluster = Cluster.open()
client = cluster.connect("mysession", true)  // managed
client.submit("g.addV('person').property('name', 'joseph').iterate()")  // 登録される(自動コミット)
client.submit("g.tx().rollback()")  // コミット済みなので取り消せない
client.close()

client = cluster.connect("mysession", false)  // not managed
client.submit("g.addV('person').property('name', 'joseph').iterate()")  // まだ登録されない
client.submit("g.tx().rollback()") // 取り消せる
client.close()
cluster.close()

Gremlinコンソールではリモート接続した際、ユーザーが打ち込んだコマンドをそのままClient.submitで送信している(コード)。つまりGremlinコンソール上のリモート送信(:>)で実行できることは全てこの方法で実行可能である。

TinkerPop Javadoc - Cluster
TinkerPop Javadoc - Client

サーバーの接続方法はどちらを使うべき?

どちらにも一長一短があるため、状況に応じて両方を併用するのが良いと思われる。
単純なクエリを扱うなら前者を、複雑またはトランザクションが必要なクエリなら後者を使うのが良さそうだ。

EmbeddedとServerはどちらがいいの?

練習用、あるいは単一プロセスで済むようなアプリケーションならEmbeddedで良さそう。
一方、複数のプロセスが並列にデータアクセスするような状況ではサーバーを立てるべきだと考えられる。

まとめ

方式 DB接続方法 リモート接続 手動トランザクション制御 備考
Embedded JanusGraphFactory ×
Server DriverRemoteConnection&
AnonymousGraphTraversal
× Graphインターフェースに対するアクセスができない
Server Cluster&Client クエリは文字列で送信(インジェクションに注意)
4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1