Neo4jのストアドプロシージャとファンクション #neo4j
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
はじめに
Neo4jでは、豊富なファンクションの他、300本を超えるプロシージャが利用できます。ここでは、プロシージャとファンクションの違いやそれぞれのタイプ、利用方法などを簡略に紹介します。
プロシージャとファンクション
プロシージャとファンクションの特徴を簡略にまとめると、次の通りです。
プロシージャ
- 一連のデータ処理を行う
- 各種UI/APIで実行する
- 単独で実行又は、Cypherと組み合わせで利用する
ファンクション
- 1つのリターン値を返すデータ処理を行う
- Cypherに組み込んで利用する
共通
- Javaでコードを書く
- JARファイルをサーバ側に配置する
プロシージャとファンクションのタイプ
次のような3つのタイプがあります。
ビルトインタイプ
Neo4jの標準機能に含まれており、特にプロシージャはシステム情報の出力、システム管理などに利用できます。Cypherクエリが提供している関数も、広い意味ではビルトインタイプに入るでしょう。下記のサンプルの図は、ラベル一覧を出力しているプロシージャの実行例です。
APOCタイプ
APOCは、パターンマッチ、グラフアルゴリズム処理、トリガなど、多様な機能を実装したプロシージャとファンクションの集合です。Neo4j v3.3.x対応版で245本の機能が実装されており、パッケージをインストールするだけで簡単に利用できます。ライセンスは、Apache2.0です。
- User Defined Functions
- Text and Lookup Indexes
- Utility Functions
- Graph Algorithms
- Spatial
- Data Integration
- Graph Refactorings
- Cypher Operations
- Virtual
- Triggers
- Schema
- Atomic
- Bolt
より詳しい情報は、次を参照してください。
APOC User Guide 3.3.0.1
[APOCとは]
APOC(A Package Of Components)は、2009年5月にリリースされましたが、当初はNeo4jの全面的なバックアップを受けるどころか、むしろ、敬遠されて来たそうです。APOCが登場したのは、Cypherが現在のような形で確立される前の事であり、当時のよちよちなCypherにはAPOCが脅威だったのかもしれません。再び、明かりが照らされたのは、2006年3.xの発表以降からです。Neo4jは、標準機能の一部にプロシージャを導入します。そこで、拡張版としてAPOCの存在は再び注目を浴びます。APOCの関係者は呟いていたそうです。APOCはCypherのために殺されかけたとか。
ユーザ定義タイプ
Java言語でコードを書きます。具体的な記述方法は、次のURLを参照してください。
user-defined-procedures
user-defined-functions
ストアドプロシージャとファンクションの導入方法
ビルトインタイプ
Neo4jのインストールパッケージに含まれているので別途の作業は不要です。
APOCタイプ
APOCのパッケージをダウンロードして解凍し、JARファイルをサーバ側の既定のディレクトリにコピーしてからNeo4jを再起動します。
$NEO4J_HOME/plugins/apoc-3.x.x-all.jar
ユーザ定義タイプ
Javaで開発し、JARファイルをサーバ側の既定のディレクトリにコピーし、Neo4jを再起動します。
$NEO4J_HOME/plugins/hogehoge.jar
ストアドプロシージャとファンクションの実行方法
プロシージャの実行
プロシージャは、Neo4jのUI又はAPIで実行できます。
call dbms.procedures()
戻り値のフィールドを指定してフィルターしたい場合は、次のようにyieldを宣言し、フィールド名を明示します。戻り値として、どのようなフィールドが存在するのかは、プロシージャ一覧のシグネチャーで確認できます。
call dbms.procedures() yield name
戻り値をRETURN句に引き渡すことができます。
call dbms.procedures() yield name as procedure_list return *
WITH * WHEREを使って特定のプロシージャをフィルターすることができます。
call dbms.procedures() yield name with * where name=~"apoc.mongodb.*" return name
プロシージャは、Cypherと組み合わせて実行することができます。
match (p:Person)
call apoc.index.addNode(p,["name","born"])
return p.name,p.born limit 10
ここでは、3つのタイプの実行例を紹介します。
ビルトインタイプ
メターグラフ(グラフデータベースのスキーマ)を出力してみます。
$ call db.schema()
プロシージャの一覧を出力してみます。
$ call dbms.procedures()
ビルトインタイプのプロシージャのみを出力したい場合は、次のようにフィルターできます。
$ call dbms.procedures() yield name,signature,description with * where name=~"db.*" return name,signature,description
name signature description
"db.awaitIndex" "db.awaitIndex(index :: STRING?, timeOutSeconds = 300 :: INTEGER?) :: VOID" "Wait for an index to come online (for example: CALL db.awaitIndex(\":Person(name)\"))."
…省略
OR
$ call dbms.procedures() yield name,signature,description with * where name=~"dbms.*" return name,signature,description
name signature description
"dbms.changePassword" "dbms.changePassword(password :: STRING?) :: VOID" "Change the current user's password. Deprecated by dbms.security.changePassword."
…省略
ログインしているデータベースのシステムパラメータ一覧と設定値が確認できます。
call dbms.listConfig() yield name,description,value with * where name=~"dbms.*" return name,description,value
name description value
"dbms.active_database" "Name of the database to load" "graph.db"
…省略
他にも有用な機能が沢山あります。プロシージャ一覧から個別に確認してください。
APOCタイプ
APOCタイプのプロシージャとファンクション一覧は、次のようにフィルターしてみることができます。
$ call dbms.procedures() yield name,signature,description with * where name=~"apoc.*" return name,signature,description
次は、前方一致の名前を検索しています。
$ call apoc.index.nodes('Person','name:Ke*') yield node
return node.name limit 10
node.name
"Kevin Bacon"
"Kevin Pollak"
"Kelly McGillis"
"Kelly Preston"
"Diane Keaton"
"Keanu Reeves"
[インデックスが必要]
このタイプの場合、インデックスが必要です。次のように作成してください。
create index on :Person(name)
もっと、複雑なパターンも書けます。次は、"Keanu Reeves"が出演した映画のどれかをプロデュースし、さらに関係者をフォローしている人を3パス以内の範囲で探索しています。
「>」はOUTGOING、「<」はINCOMMINGを意味し、「+」は、処理対象のラベルを意味しています。
$ match (tom:Person {name :"Keanu Reeves"})
call apoc.path.expand(tom,"ACTED_IN>|PRODUCED<|FOLLOWS<","+Movie|Person",0,3) yield path
return *
このようなAPOCの使用は、プロシージャ固有の仕様を十分に理解している必要があります。詳細は、下記のURLを参照してください。
APOC User Guide 3.3.0.1
Expand paths
上記のパターンマッチングをCypherで書くと、次のようになります。
match (p:Person {name :"Keanu Reeves"})-[:ACTED_IN*..3]->(m)
optional match (m)<-[:PRODUCED*..3]-(pp)
optional match (pp)<-[:FOLLOWS*..3]-()
return *
さらに、APOCはファンクションで様々な便利機能を提供しています。次は、ドメインを切り取っています。
WITH 'foo@bar.com' AS email
RETURN apoc.data.domain(email) as value // will return 'bar.com'<
value
"bar.com"
コンマ区切りの数字のフォーマットも簡単に編集できます。
return apoc.number.format(12345.67) as value //will return 12,345.67
value
"12,345.67"
APOCのパフォーマンス測定は?と疑問を持つかもしれませんが、実行計画だってCypher同様に出力できます。
explain match (p:Person)
call apoc.index.addNode(p,["name","born"])
return p.name, p.born
ユーザ定義タイプ
実行方法は基本的にAPOCタイプと同じです。APOCは、広い意味でユーザ定義タイプの一種であるとも言えます。
まとめ
今回は、プロシージャとファンクションの存在をアピールする程度の記事にしています。ある機能をプロシージャやファンクションで開発する必要性が生じた場合、APOCの導入を検討してみたほうがいいかも知れません。苦労して開発した結果が、「実は、APOCに既に存在している車輪を再発明した。」みたいなことが起きないとも限りません。