- 第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行目)。
[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]$しかし、Python 2.6にリンクされたこのPL/Pythonモジュールだと前述した(summpy動作に必要な)Pythonライブラリ群が動作しませんので、Python 2.7にリンクされたPL/Pythonモジュールを用意する必要があります。
具体的には、PostgreSQLのソースコードから --with-python オプションを付けてビルドし、plpython2.so ファイルだけをRPMのものと入れ替えます。(入れ替えるのは plpython2.so だけで構いません。)
すると、以下のようにPython 2.7にリンクしたplpython.soモジュールを使うことができるようになります。
[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]$今回私が作成して使用した RHEL6/CentOS6 の PostgreSQL 9.4(x86_64版)のRPMで動作するplpython2.soは以下に置いておきます。 あるいは、もちろんソースコードから全部ビルドしたPostgreSQLを使っても構いません。
■PL/Pythonからsummpyを呼び出す関数を作成する
ここまで環境ができたら、pg_summpy.sqlを実行してsummpyライブラリを呼び出す関数をPostgreSQLのデータベースに登録します。ソースコードは以下です。[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()という関数とmcp_summarize()という関数が登録されて使用できるようになります。
関数自体は非常にシンプルで、例えば lexrank_summarize() 関数は、
- 第1引数: summpy ライブラリのあるディレクトリへのPATH(git cloneした時のトップディレクトリ)
- 第2引数: 要約したい文章
- 第3引数: 「いくつの文に要約するか」という上限値
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;そして、この関数は要約した文章1つを1レコードとして返却します。
■実際に文章を要約してみる
ここまでできたら、実際に文章を要約してみましょう。
今回は、先日ネット上で話題になっていた「東京カレンダー 東京女子図鑑」の「綾の銀座での”上質な”暮らし」を要約してみます。
- 31歳女性がするべき、銀座での“上質な”暮らし。大人の女の流儀とは?(1/2)[東京カレンダー]
https://tokyo-calendar.jp/article/4640
まず、本文が非常に長いので、以下のように第2引数にすべての文章をコピペしたSQLファイルを作成します。(ここでは5つの文章に要約することにします)
SELECT * FROM lexrank_summarize('/path/to/summpy', '20代後半頃から、同期が1人また1人と、会社を辞めていきました。辞める理由はいろいろ(・・・中略・・・)もうちょっとしたら、別の男性探さないととは思ってますが、今はもう少しだけこの生活楽しんでいたいなって思います。', 5);著作権の関係上、サンプルSQLをファイルで配布するのは避けますが、作成するとこんな感じ(↓)になります。
そして、このSQLを実際に実行すると、以下のような出力を得ることができます。
[snaga@localhost pg_summpy]$ psql -f tokyo-calendar.sql mydb lexrank_summarize -------------------------------------------------------------------------------------------------------------------------------------------------------------------- まさか、この私が、あの外資系ブランドで働くことになるとは思いませんでしたね。 その女性に住んでる場所を聞かれて「恵比寿です。」と言ったところ、あぁ、って苦笑いされました。 最初は、上司のいう一流のものがわからなかったけど、その人の行動をお手本に真似するようになって、やっと最近30歳を超えた大人の女の流儀が分かるようになった気がします。 レストランも詳しいし、私は、大分その人から大人にしてもらいました(笑)。 「女性が30歳になったら、歌舞伎デビューくらいしていないと」と彼は私を桟敷席に連れて行きました。 (5 rows) [snaga@localhost pg_summpy]$上記の通り、綾の銀座での暮らしを5つの文章に要約することができました。
綾が銀座の暮らしを通して大人になっていった様子が、ありありと、かつ簡潔にまとめられています(?)。
なお、形態素解析を正確に行うために文章に句点「。」を追加しなければならない個所がいくつかありますので、その点はご注意ください。
■まとめ
以上、簡単ではありますが、
Pythonはデータ処理を行うためのライブラリやノウハウなどのエコシステムがどんどん大きくなっています。
その結果として、データベースに蓄積したデータをPythonで処理したい、その時に極力シンプルにデータを扱いたい、データベース内部で処理したい(In-Database処理と言います)といったニーズも出てくるかと思います。
そんなニーズにPL/Pythonはうまくフィットするのではないかと思います。興味をもった方は、ぜひこれを機会にチャレンジしてみていただければと思います。
では。
0 件のコメント:
コメントを投稿