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/