fbpx

Neo4jのマルチデータベースとデータベースファブリック #neo4j

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

Neo4j v4.0(2020-01-15)からマルチデータベースとデータベースファブリックが実装されました。

マルチデータベースはMySQLやMongoDBなど、他のデータベースエンジンでは当たり前の機能なので、やっとバランスが取れた状態になりました。

データベースファブリックはマルチデータベースにグラフを水平分散し、Cypherで統合して問い合わせができる機能です。
これでグラフでは難題だったスケールアウトが可能になりました。

今回の実装でNeo4jの可能性はさらに広がりました。
ここでは、Neo4jのマルチデータベースとデータベースファブリックを簡略に紹介します。

マルチデータベース

マルチデータベースとは

1つのDBMS上で複数のデータベースを作成し、それぞれ異なる内容のグラフを格納します。

  • CREATE DATABASE database_name

ログイン時には、neo4j(デフォルトデータベース)に接続します。
シェルコマンド(:dbs)を使ってデータベースのリストを表示してみましょう。

neo4j$ :dbs

次のように2つの初期データベースが存在します。

  • neo4jはユーザーが任意で使ってもいいデフォルトのデータベースです
  • systemはシステム情報を保存するリポジトリデータベースです

SYSTEMデータベースにスイッチし、データベースのステータスを表示してみます。

neo4j$ :use system
system$ show databases;
name        address         role        requestedStatus currentStatus   error   default
"neo4j"     "localhost:7687"    "standalone"    "online"    "online"    ""  true
"system"    "localhost:7687"    "standalone"    "online"    "online"    ""  false

マルチデータベースの作成

SYSTEMデータベース上でMOVIEとNORTHWINDを作成し、ステータスを見てみます。

system$ CREATE DATABASE movie
(1 system update, no records)
system$ CREATE DATABASE northwind
(1 system update, no records)
 
system$ show databases;
name        address         role        requestedStatus currentStatus   error   default
"neo4j"     "localhost:7687"    "standalone"    "online"    "online"    ""  true
"system"    "localhost:7687"    "standalone"    "online"    "online"    ""  false
"movie"     "localhost:7687"    "standalone"    "online"    "online"    ""  false
"northwind" "localhost:7687"    "standalone"    "online"    "online"    ""  false

DB0とDB1にムービーグラフを作成します。

system$ :use mvie
movie$ :play movie graph
movie$ call db.schema.visualization

movie$ :use northwind
northwind$ :play northwind graph
northwind$ call db.schema.visualization

このようにシングルのDBMS上で複数のデータベースを構築し、排他的に運用できます。

マルチデータベースの用途

  • 基本的に繋がりがない内容のグラフを複数利用する場合

データベースファブリック(シャーディング&フェデレーション)

データベースファブリックとは

通常、Neo4jのようなマスタータイプのアーキテクチャーではスケールアウトを実装する時、シャーディングという方式を利用しています(MySQL/MongoDB)。
この方式では一連のデータのレンジを一定のサイズのシャードと呼ばれるパーティションに分割して格納します。

ここで、それぞれのシャードは物理的に分散されたサーバー上に配置することで、データや処理負荷の分散、リソースの拡張を同時に解決しています。

今回、データベースファブリックでは巨大グラフをサブグラフに分けて複数のデータベース上に分散して格納しています。
そして、それぞれのデータベースは1サーバー上に複数構築することもできれば、サーバー毎に分散することもできます。

  • 複数のデータベースに一連の繋がりを持つグラフを分散して格納します(シャーディング)
  • Cypherで複数のデータベースにまたがる問合せが実行できます(フェデレーション)
  • それぞれのデータベースを物理的に離れたサーバー上に分散できます

データベースファブリックの構成

【ファブリック】

  • グラフを複数のデータベースにパーティション化して分散したり、統合して問い合わせを行う方式のことです
  • ファブリックの構成は、既存のマルチデータベースからマイグレーションすることも可能です

【ファブリックデータベース】

  • 分散されているデータベースを統合するデータベースです
  • ファブリックデータベースはデータを持ちません
  • ファブリックデータベースは明示的に作成しません(パラメーター設定のみ)

【ターゲットデータベース】

  • 一連のグラフをパーティション化して持っているデータベースです
  • シングルDBMS、複数のDBMS、又はクラスターで構成します

シングルDBMSでデータベースファブリックを構成

これはシングルDBMSに仮想データベース及びターゲットデータベースを配置する方式です。

Neo4jファブリックを実装してみましょう。

neo4j.confでNeo4jファブリックを構成します。

dbms.mode=SINGLE
fabric.database.name=example
 
fabric.graph.0.uri=neo4j://localhost:7687
fabric.graph.0.database=db0
fabric.graph.0.name=graphA
 
fabric.graph.1.uri=neo4j://localhost:7687
fabric.graph.1.database=db1
fabric.graph.1.name=graphB

  • fabric.graph.0.nameはデータベースの論理名称です(任意定義可能)
  • db0とdb1はデータベースの物理名称です(既存のデータベースでも構いません)
  • exampleは明示的に作成しません(ここに設定しておくと自動生成されます)

neo4j$ :use system
system$ CREATE DATABASE db0
(1 system update, no records)
system$ CREATE DATABASE db1
(1 system update, no records)

データベースのステータスを確認します。

system$ show databases;
name        address         role        requestedStatus currentStatus   error   default
"neo4j"     "localhost:7687"    "standalone"    "online"    "online"    ""  true
"system"    "localhost:7687"    "standalone"    "online"    "online"    ""  false
"movie"     "localhost:7687"    "standalone"    "online"    "online"    ""  false
"northwind" "localhost:7687"    "standalone"    "online"    "online"    ""  false
"db0"       "localhost:7687"    "standalone"    "online"    "online"    ""  false
"db1"       "localhost:7687"    "standalone"    "online"    "online"    ""  false

DB0とDB1にムービーグラフを作成します。

system$ :use db0
db0$ :play movie graph
db0$ :use db1
db1$ :play movie graph

ファブリックデータベース上でCypherを実行

データベースファブリックでは、あるターゲットデータベースから属性を取り出して別のターゲットデータベースに引き渡してパターンマッチを実行できます。

graphAとgraphBを統合するCypherを実行してみましょう。
次のCypherはgraphAからTom Hanksの名前を抽出し、graphBに渡して出演した映画を探索するパターンマッチを行っています。

db1$ :use example
example$
CALL {
USE example.graphA
 MATCH (p:Person)
 WHERE p.name = 'Tom Hanks'
 RETURN p.name AS names
}
CALL {
 USE example.graphB
 WITH names
 MATCH (a:Person { name: names} )-[r:ACTED_IN]->(m:Movie)
 RETURN a,r,m
}
RETURN a,r,m

次のCypherはgraphAでTom Hanksが出演した映画のタイトルを抽出し、graphBで映画に出演した俳優を探索するパターンマッチを行っています。

CALL {
USE example.graphA
 MATCH (p:Person)-->(m:Movie)
 WHERE p.name = 'Tom Hanks'
 RETURN collect(m.title) AS titles
}
CALL {
 USE example.graphB
 WITH titles UNWIND titles AS n
 MATCH (a)-[r:ACTED_IN]->(m:Movie{ title : n} )
 RETURN a,r,m
}
RETURN a,r,m

データベースファブリックの制約

USE句は、サブクエリのなかで宣言しなければなりません。

CALL {
 USE example.graphA
 MATCH (p:Person)
 WHERE p.name = 'Tom Hanks'
 RETURN p.name AS names
}
USE example.graphB
WITH names
MATCH (a:Person { name: names} )-[r:ACTED_IN]->(m:Movie)
RETURN a,r,m
Neo.ClientError.Statement.SyntaxError
USE can only appear at the beginning of a (sub-)query
"USE example.graphB"

リモートのサブクエリにノードデータの引き渡しはできません。

CALL {
 USE example.graphA
 MATCH (p:Person)
 WHERE p.name = 'Tom Hanks'
 RETURN p AS person
}
CALL {
 USE example.graphB
 WITH person
 
 MATCH (a:Person { name: person.name} )-[r:ACTED_IN]->(m:Movie)
 RETURN a,r,m
}
RETURN a,r,m
Neo.ClientError.Statement.TypeError
Importing node values in remote subqueries is currently not supported

ファブリックデータベースとターゲットデータベースの分離

ファブリックデータベースとターゲットデータベースのDBMSを分離することができます。
次の構成は「シングルファブリックデータベース:1DBMS」、「マルチターゲットデータベース:1DBMS」の構成です。

dbms.mode=SINGLE
 
fabric.database.name=example
 #fabric.routing.servers=server1:7687
 
fabric.graph.0.name=graphA
fabric.graph.0.uri=neo4j://server1:7687
fabric.graph.0.database=db1
 
fabric.graph.1.name=graphB
fabric.graph.1.uri=neo4j://server1:7687
fabric.graph.1.database=db2
 
fabric.graph.2.name=graphC
fabric.graph.2.uri=neo4j://server1:7687
fabric.graph.2.database=db3 

次は「シングルファブリックデータベース:1DBMS」、「マルチターゲットデータベース:N DBMS」の構成です。

dbms.mode=SINGLE
 
fabric.database.name=example
 #fabric.routing.servers=server1:7687
 
fabric.graph.0.name=graphA
fabric.graph.0.uri=neo4j://server1:7687
fabric.graph.0.database=db1
 
fabric.graph.1.name=graphB
fabric.graph.1.uri=neo4j://server2:7687
fabric.graph.1.database=db2
 
fabric.graph.2.name=graphC
fabric.graph.2.uri=neo4j://server3:7687
fabric.graph.2.database=db3 

どちらもサーバーの障害では単一障害点になるリスクがあります。

データベースファブリックのHA構成

ファブリックデータベースを冗長化し、ターゲットデータベースをクラスター化することで高可用性を確保できます。

dbms.mode=SINGLE
 
fabric.database.name=example
fabric.routing.servers=server1:7687,server2:7687
 
fabric.graph.0.name=graphA
fabric.graph.0.uri=neo4j://core1:7687,neo4j://core2:7687,neo4j://core3:7687
fabric.graph.0.database=db1
 
fabric.graph.1.name=graphB
fabric.graph.1.uri=neo4j://core1:7687,neo4j://core2:7687,neo4j://core3:7687
fabric.graph.1.database=db2
 
fabric.graph.2.name=graphC
fabric.graph.2.uri=neo4j://core1:7687,neo4j://core2:7687,neo4j://core3:7687
fabric.graph.2.database=db3

データベースファブリックの用途

  • 規模を問わずなんらかの繋がりを持つ複数のグラフ(データベース)を統合して利用したい場合
  • Cypherの処理負荷分散、又は特定のグラフに大量のリソースを確保したい場合

まとめ

マルチデータベースの登場は当たり前すぎてむしろ遅い感さえありますが、データベースファブリックは正直に嬉しかったです。これでNeo4jはスケールアウトできないという、これまでの汚名を返上し、さらなる可能性を示してくれました。ただし、マルチデータベースやデータベースファブリックはエンタープライズ版の機能であり、コミュニティ版では利用できないことがとても残念です。

[参考]
https://neo4j.com/docs/operations-manual/4.0/fabric/queries/
https://neo4j.com/docs/cypher-manual/4.0/clauses/use/
https://neo4j.com/developer/neo4j-fabric-sharding/

Author

モダンアーキテクチャー基盤のソリューションアーキテクトとして活動しています。

[著書]
・Amazon Cloudテクニカルガイド―EC2/S3からVPCまで徹底解析
・Amazon Elastic MapReduceテクニカルガイド ―クラウド型Hadoopで実現する大規模分散処理
・Cypherクエリー言語の事例で学ぶグラフデータベースNeo4j
・Neo4jを使うグラフ型データベース入門(共著)
・RDB技術者のためのNoSQLガイド(共著)

leeの記事一覧

新規CTA