昨日、PostgreSQL勉強会で「PostgreSQLハッキング 最初の一歩」と題して、PostgreSQLの拡張開発の初歩についていくつかお話させていただきました。
(右のサムネイルの意味は本エントリの最後に分かります)
自動要約APIは、10月末にリクルートテクノロジーズさんがリリースされた自然言語処理のライブラリで、Pythonで書かれたものです。
詳細については上記ブログおよびGithubを参照してください。
このライブラリを最初に見た時、PostgreSQLに組み込んでみると面白そうだな、と感じました。
というのは、
というわけで、このPythonライブラリ「summpy」をPostgreSQLからSQLを使って実行できるような拡張モジュール「pg_summpy」を作ってみます。
まず、summpyを動作させる環境を構築する必要があります。
summpyを動作させる環境は README.md を参照していただきたいのですが、以下のソフトウェアがインストールされている必要があります。
次にPL/Pythonの準備をします。
もともと、PL/Pythonのモジュール(plpython2.so)はPythonのスクリプトを実行するためにPython本体の共有ライブラリをリンクしています。
RHEL6/CentOS6用のコミュニティ版のPostgreSQL RPMからインストールすると、PL/PythonのライブラリはOSデフォルトのPython 2.6のライブラリにリンクされてます(以下のlddの出力の2行目)。
具体的には、PostgreSQLのソースコードから --with-python オプションを付けてビルドし、plpython2.so ファイルだけをRPMのものと入れ替えます。(入れ替えるのは plpython2.so だけで構いません。)
すると、以下のようにPython 2.7にリンクしたplpython.soモジュールを使うことができるようになります。
関数自体は非常にシンプルで、例えば lexrank_summarize() 関数は、
ここまでできたら、実際に文章を要約してみましょう。
今回は、先日ネット上で話題になっていた「東京カレンダー 東京女子図鑑」の「綾の銀座での”上質な”暮らし」を要約してみます。
まず、本文が非常に長いので、以下のように第2引数にすべての文章をコピペしたSQLファイルを作成します。(ここでは5つの文章に要約することにします)
そして、このSQLを実際に実行すると、以下のような出力を得ることができます。
綾が銀座の暮らしを通して大人になっていった様子が、ありありと、かつ簡潔にまとめられています(?)。
なお、形態素解析を正確に行うために文章に句点「。」を追加しなければならない個所がいくつかありますので、その点はご注意ください。
以上、簡単ではありますが、綾が銀座で大人になっていった様子PL/Pythonを使ったPostgreSQLの拡張方法をご紹介しました。
Pythonはデータ処理を行うためのライブラリやノウハウなどのエコシステムがどんどん大きくなっています。
その結果として、データベースに蓄積したデータをPythonで処理したい、その時に極力シンプルにデータを扱いたい、データベース内部で処理したい(In-Database処理と言います)といったニーズも出てくるかと思います。
そんなニーズにPL/Pythonはうまくフィットするのではないかと思います。興味をもった方は、ぜひこれを機会にチャレンジしてみていただければと思います。
では。
- 第33回 PostgreSQL 勉強会(2015年11月14日)
http://www.postgresql.jp/wg/shikumi/pgstudy_33/view
(右のサムネイルの意味は本エントリの最後に分かります)
■「自動要約API」とは?
自動要約APIは、10月末にリクルートテクノロジーズさんがリリースされた自然言語処理のライブラリで、Pythonで書かれたものです。
- 自動要約APIを作ったので公開します | RECRUIT TECHNOLOGIES Member's blog
http://blog.recruit-tech.co.jp/2015/10/30/summpy-released/ - recruit-tech/summpy
https://github.com/recruit-tech/summpy
詳細については上記ブログおよびGithubを参照してください。
■なぜPostgreSQLと組み合わせるのか?
このライブラリを最初に見た時、PostgreSQLに組み込んでみると面白そうだな、と感じました。
というのは、
- PostgreSQLにはPL/Pythonがあり、Pythonでストアドプロシージャ(ファンクション)を書ける。もちろん、外部のライブラリを使うことができる。
- データベースに蓄積したデータに対していろいろな加工・分析処理をしたい、というニーズはある。
- 自分自身はPL/Pythonでプロシージャを書いたことがなかったので、試してみるにはいいレベル。
というわけで、このPythonライブラリ「summpy」をPostgreSQLからSQLを使って実行できるような拡張モジュール「pg_summpy」を作ってみます。
■「summpy」の動作環境の準備
まず、summpyを動作させる環境を構築する必要があります。
summpyを動作させる環境は README.md を参照していただきたいのですが、以下のソフトウェアがインストールされている必要があります。
- Python 2.7
- MeCab, MeCab-ipadic
- python-mecab
- networkx
- numpy
- scipy
- sklearn
- pulp
- cherrypy
■PL/Pythonの準備
次にPL/Pythonの準備をします。
- PL/Python - Python手続き言語
https://www.postgresql.jp/document/9.4/html/plpython.html
もともと、PL/Pythonのモジュール(plpython2.so)はPythonのスクリプトを実行するためにPython本体の共有ライブラリをリンクしています。
RHEL6/CentOS6用のコミュニティ版のPostgreSQL RPMからインストールすると、PL/PythonのライブラリはOSデフォルトのPython 2.6のライブラリにリンクされてます(以下のlddの出力の2行目)。
しかし、Python 2.6にリンクされたこのPL/Pythonモジュールだと前述した(summpy動作に必要な)Pythonライブラリ群が動作しませんので、Python 2.7にリンクされたPL/Pythonモジュールを用意する必要があります。
[snaga@localhost pg_summpy]$ ldd /usr/pgsql-9.4/lib/plpython2.so
linux-vdso.so.1 => (0x00007fff243ac000)
libpython2.6.so.1.0 => /usr/lib64/libpython2.6.so.1.0 (0x00007f0c174be000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0c1712a000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0c16f0c000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f0c16d08000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f0c16b05000)
libm.so.6 => /lib64/libm.so.6 (0x00007f0c16880000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0c17a8d000)
[snaga@localhost pg_summpy]$
具体的には、PostgreSQLのソースコードから --with-python オプションを付けてビルドし、plpython2.so ファイルだけをRPMのものと入れ替えます。(入れ替えるのは plpython2.so だけで構いません。)
すると、以下のようにPython 2.7にリンクしたplpython.soモジュールを使うことができるようになります。
今回私が作成して使用した RHEL6/CentOS6 の PostgreSQL 9.4(x86_64版)のRPMで動作するplpython2.soは以下に置いておきます。 あるいは、もちろんソースコードから全部ビルドしたPostgreSQLを使っても構いません。
[snaga@localhost pg_summpy]$ ldd /usr/pgsql-9.4/lib/plpython2.so
linux-vdso.so.1 => (0x00007fffda0fb000)
libpython2.7.so.1.0 => /usr/local/lib/libpython2.7.so.1.0 (0x00007f1aa594c000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1aa55ac000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1aa538f000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f1aa518b000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f1aa4f87000)
libm.so.6 => /lib64/libm.so.6 (0x00007f1aa4d03000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1aa5f4b000)
[snaga@localhost pg_summpy]$
■PL/Pythonからsummpyを呼び出す関数を作成する
ここまで環境ができたら、pg_summpy.sqlを実行してsummpyライブラリを呼び出す関数をPostgreSQLのデータベースに登録します。ソースコードは以下です。すると、lexrank_summarize()という関数とmcp_summarize()という関数が登録されて使用できるようになります。
[snaga@localhost pg_summpy]$ psql -f pg_summpy.sql mydb
CREATE FUNCTION
DROP FUNCTION
CREATE FUNCTION
DROP FUNCTION
CREATE FUNCTION
[snaga@localhost pg_summpy]$
関数自体は非常にシンプルで、例えば lexrank_summarize() 関数は、
- 第1引数: summpy ライブラリのあるディレクトリへのPATH(git cloneした時のトップディレクトリ)
- 第2引数: 要約したい文章
- 第3引数: 「いくつの文に要約するか」という上限値
そして、この関数は要約した文章1つを1レコードとして返却します。
CREATE OR REPLACE FUNCTION lexrank_summarize(p text, t text, s_limit integer)
RETURNS SETOF text
AS $$
import sys
sys.path.append(p)
from summpy import lexrank
res = lexrank.summarize(unicode(t, 'utf-8'), sent_limit=s_limit)
for s in res:
yield(s.encode('utf-8'))
$$ LANGUAGE plpythonu;
■実際に文章を要約してみる
ここまでできたら、実際に文章を要約してみましょう。
今回は、先日ネット上で話題になっていた「東京カレンダー 東京女子図鑑」の「綾の銀座での”上質な”暮らし」を要約してみます。
- 31歳女性がするべき、銀座での“上質な”暮らし。大人の女の流儀とは?(1/2)[東京カレンダー]
https://tokyo-calendar.jp/article/4640
まず、本文が非常に長いので、以下のように第2引数にすべての文章をコピペしたSQLファイルを作成します。(ここでは5つの文章に要約することにします)
著作権の関係上、サンプルSQLをファイルで配布するのは避けますが、作成するとこんな感じ(↓)になります。
SELECT * FROM lexrank_summarize('/path/to/summpy', '20代後半頃から、同期が1人また1人と、会社を辞めていきました。辞める理由はいろいろ(・・・中略・・・)もうちょっとしたら、別の男性探さないととは思ってますが、今はもう少しだけこの生活楽しんでいたいなって思います。', 5);
そして、このSQLを実際に実行すると、以下のような出力を得ることができます。
上記の通り、綾の銀座での暮らしを5つの文章に要約することができました。
[snaga@localhost pg_summpy]$ psql -f tokyo-calendar.sql mydb
lexrank_summarize
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
まさか、この私が、あの外資系ブランドで働くことになるとは思いませんでしたね。
その女性に住んでる場所を聞かれて「恵比寿です。」と言ったところ、あぁ、って苦笑いされました。
最初は、上司のいう一流のものがわからなかったけど、その人の行動をお手本に真似するようになって、やっと最近30歳を超えた大人の女の流儀が分かるようになった気がします。
レストランも詳しいし、私は、大分その人から大人にしてもらいました(笑)。
「女性が30歳になったら、歌舞伎デビューくらいしていないと」と彼は私を桟敷席に連れて行きました。
(5 rows)
[snaga@localhost pg_summpy]$
綾が銀座の暮らしを通して大人になっていった様子が、ありありと、かつ簡潔にまとめられています(?)。
なお、形態素解析を正確に行うために文章に句点「。」を追加しなければならない個所がいくつかありますので、その点はご注意ください。
■まとめ
以上、簡単ではありますが、
Pythonはデータ処理を行うためのライブラリやノウハウなどのエコシステムがどんどん大きくなっています。
その結果として、データベースに蓄積したデータをPythonで処理したい、その時に極力シンプルにデータを扱いたい、データベース内部で処理したい(In-Database処理と言います)といったニーズも出てくるかと思います。
そんなニーズにPL/Pythonはうまくフィットするのではないかと思います。興味をもった方は、ぜひこれを機会にチャレンジしてみていただければと思います。
では。