CentOS 7+PostgreSQL9.4 でゆるいtextsearch_jaの動作を確認する
ぬこは激怒した。
必ず、かの杓子定規のtextsearchをユルくしなければならぬと決意した。
ぬこにはPostgreSQL内部実装がわからぬ。
ぬこは、ただのユーザである。
SQLを書き、psqlと遊んで暮して来た。
けれども検索結果に対しては、人一倍に敏感であった。
2月はばたばたしていて、MySQL 5.7の形態素解析全文検索と、PostgreSQLのtextsearch_jaとの比較に手が回らなかった。
pg_bigmとpgronngaの比較も結局できなかった。
そして2月末にはdocomoシェアパックの速度制限喰らってDLもままならんかったし・・・。
(そして2月末に測定したJSONB/MongoDBの1件更新の測定結果のblogアップもサボってる・・・)
3月になったので、改めてやってみることに。
まずはtextsearch_jaから。といっても、今使っているCF-SX4上のCentOS7上にmecabから入れなおす必要がある。
Mecabのインストール
インストールするバージョン。3年前にインストールしたものと変わってない。そういう意味ではMecabはもうオワコンなのかしらん。
これはCentOS7上のgcc 4.8.2でもフツーにビルドはできた。
(辞書は configure時に--with-charset=utf8オプションをつけて構築している)
textsearch_jaのインストール
ということで次はtextsearch_jaのビルドである。
せっかくなので、先日ビルドしたPostgreSQLの最新版、9.4.1上に組み込んでみることにする。
[nuko@localhost textsearch_ja-9.0.0]$ make USE_PGXS=1 gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fpic -I. -I./ -I/home/nuko/pgsql-9.4.1/include/server -I/home/nuko/pgsql-9.4.1/include/internal -D_GNU_SOURCE -c -o textsearch_ja.o textsearch_ja.c textsearch_ja.c: 関数 ‘ja_analyze’ 内: textsearch_ja.c:403:4: 警告: 関数 ‘heap_form_tuple’ の暗黙的な宣言です [-Wimplicit-function-declaration] tuple = heap_form_tuple(tupdesc, values, nulls); ^ textsearch_ja.c:403:10: 警告: 代入で整数からキャスト無しにポインタを作成しています [デフォルトで有効] tuple = heap_form_tuple(tupdesc, values, nulls); ^ textsearch_ja.c:424:2: 警告: 関数 ‘heap_copytuple’ の暗黙的な宣言です [-Wimplicit-function-declaration] result = heap_copytuple(tuple); ^ textsearch_ja.c:424:9: 警告: 代入で整数からキャスト無しにポインタを作成しています [デフォルトで有効] result = heap_copytuple(tuple); ^
9.3以降(だったかな?)、DLしたtextsearch_jaをそのままビルドすると上記の警告が出てしまうので、
textsearch_ja.c の最初のほうにあるinclude文のところに、access/htup_details.h のinclude文を追加する。
#include "textsearch_ja.h" #include <mecab.h> #include "access/htup_details.h" /* add */ #include "pgut/pgut-be.h"
これで警告は出なくなる。
なお、この警告を放置すると、textseach_jaの ja_analyze() とかでbackend異常終了することがあったはず。
なお、念のため?に9.5-develでもビルドしてみたが、今のところ警告なくビルドはできるっぽい。
まあ、検証自体は9.4.1でやるけど。
ビルドができたのでインストール・・・の前に。
textsearch_ja.sql 自体の修正をしないと、データベースへの組み込み時に(たしか)PostgreSQL 9.1以降はエラーになる。
具体的には、LANGUAGE 'C'となっている箇所をLANGUAGE 'c'に変更しないといけない(10箇所)
例えばこんな感じで修正する。
CREATE FUNCTION ts_ja_start(internal, int4) RETURNS internal AS '$libdir/textsearch_ja' LANGUAGE 'c' STRICT;
で、インストール。
[nuko@localhost textsearch_ja-9.0.0]$ make USE_PGXS=1 install /usr/bin/mkdir -p '/home/nuko/pgsql-9.4.1/lib' /usr/bin/mkdir -p '/home/nuko/pgsql-9.4.1/share/contrib' /usr/bin/install -c -m 755 textsearch_ja.so '/home/nuko/pgsql-9.4.1/lib/textsearch_ja.so' /usr/bin/install -c -m 644 uninstall_textsearch_ja.sql textsearch_ja.sql '/home/nuko/pgsql-9.4.1/share/contrib/' [nuko@localhost textsearch_ja-9.0.0]$
あとはデータベースに組み込めばいい。
今回は青空文庫の太宰治作品を幾つかロードしてためしてみる。。
utf8エンコーディングで作成したdazaiデータベースにtextsearch_jaをインストールする。
なお、DL版だとEXTENSIONに対応していないので textsearch_ja.sql をpsqlで実行しなければならない。
(libmecab.soにLD_LIBRARY_PATHを通しておかないと、上記の textsearch_ja.sql 実行時にエラーになるので注意)
ゆるいtextsearch_jaの組み込み
元々、mecab/textseach_ja環境を改めて構築したのは、これからMySQL 5.7の形態素解析全文検索機能と比較するためだったんだけど、せっかくなので(?)、自作の「だいたいあってる」textsearch_jaも確認してみた。
2年くらい前に、開催されたPostgreSQL Unconferenceで「ゆるいテキスト検索」というタイトルで、曖昧な比較が可能な文字型と、その曖昧な比較関数を(無理やり)textsearch_ja組み込んで、曖昧な全文検索を行うというのを発表した。
(ゆるいテキスト検索)
そのときはCentOS 6+PostgreSQL 9.2という環境でやってみたけど、CentOS7+PostgreSQL 9.4環境でも動作するのかどうかを確認してみた。
仕組みとしては、文字列同士を比較して「だいたいあってる」なら0を、その他なら正値あるいは負値を返却する(memcmpと入出力IFを合わせた)独自の比較関数を作成。
extern void _PG_init(void); ・・・ /* * TsearchCompare_hook * Custom approx compare function */ static int TsearchCompareApprox(char* a, char* b, int len) { ・・・実際の近似評価用のコード } ・・・ /* * Module initialization function */ void _PG_init(void) { /* activate hook module is loaded */ TsearchCompare_hook = TsearchCompareApprox; }
PostgreSQLのソース(backend/util/adt/tsvector_op.c)を、ちょっと修正して、その比較関数をHOOK関数として組み込み可能にする。
int (*TsearchCompare_hook) (char* a, char* b, int len) = NULL; // add by nuko ・・・ if (TsearchCompare_hook == NULL) { cmp = memcmp(a, b, Min(lena, lenb)); } else { // Custom Compare Hook Functoin Call cmp = (*TsearchCompare_hook) (a, b, Min(lena, lenb)); } ・・・ else if ((TsearchCompare_hook == NULL) && cmp == 0 && lena != lenb) // modify by nuko { cmp = (lena < lenb) ? -1 : 1; }
なお、この部分の修正方式はPostgreSQL 9.2とPostgreSQL 9.4でも特に変更はなかった。
で、HOOK関数を有効にするために、postgresql.conf に作成した比較関数のライブラリ読み込みのパラメータを追加する。
shared_preload_libraries = 'ts_compare_approx'
これで再起動すると、「だいたいあってる」ワードで全文検索ができる。
通常の textsearch_ja だと、当たり前だけど「セリヌンティウス」を含む文書を「センヌリティウス」や「セリンティウス」で検索することはできない。
が、この「だいたいあってる」比較関数を組み込んだ textsearch_ja だと、こんな感じで「だいたいあってる」ワードでも引っ掛けることができる。
以下は「センヌリティウス」で「セリヌンティウス」をヒットさせた例。
dazai=# SELECT ts_headline('japanese', t, 'センヌリティウス') FROM dazai WHERE to_tsvector('japanese', t) @@ to_tsquery('japanese', 'センヌリティ ウス'); ts_headline ---------------------------------------------------------------------------------------------------------------------------------------------------- ------------------- <b>セリヌンティウス</b>である。今は此のシラクスの市で、石工をしている。その友を、これから訪ねてみるつもりなのだ。久しく逢わ <b>セリヌンティウス</b>という石工がいます。私の無二の友人だ。あれを、人質としてここに置いて行こう。私が逃げてしまって、三日目の日暮まで、ここに帰っ <b>セリヌンティウス</b>は無言で首肯うなずき、メロスをひしと抱きしめた。友と友の間は、それでよかった。<b>セリヌンティウス</b>は、縄打た <b>セリヌンティウス</b>。よくも私を信じてくれた。それを思えば、たまらない。友と友の間の信実は、この世で一ばん誇るべき宝なのだからな。<b>セリヌンテ ウス</b> <b>セリヌンティウス</b>様の弟子でございます。」その若い石工も、メロスの後について走りながら叫んだ。「もう、駄目でございます。むだでございます。走る のは、やめて下さい <b>セリヌンティウス</b>は、徐々に釣り上げられてゆく。メロスはそれを目撃して最後の勇、先刻、濁流を泳いだように群衆を掻き ゆく友の両足に、齧かじりついた。群衆は、どよめいた。あっぱれ。ゆるせ、と口々にわめいた。<b>セリヌンティウス</b>の縄は、ほどかれたのである。 <b>セリヌンティウス</b>。」メロスは眼に涙を浮べて言った。「私を殴れ。ちから一ぱいに頬を殴れ。私は、途中で一度、悪い <b>セリヌンティウス</b>は、すべてを察した様子で首肯うなずき、刑場一ぱいに鳴り響くほど音高くメロスの右頬を殴っ メロスは腕に唸うなりをつけて<b>セリヌンティウス</b>の頬を殴った。 (10 rows)
実案件で使い物になるのかどうかはともかく、自分では結構気に入っている拡張なので、最新環境でも動作が確認できて嬉しかった。