fbpx

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を再起動します。

APOC Fall Release 3.3.0.1

$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に既に存在している車輪を再発明した。」みたいなことが起きないとも限りません。

Author

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

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

leeの記事一覧

新規CTA