pg_bigm(ピージーバイグラム)は、PostgreSQL上で全文検索機能を提供するモジュールです。このモジュールを使うことで、ユーザは全文検索用のインデックスを作成でき、高速に文字列検索を行えるようになります。このモジュールは、2-gram(バイグラム)と呼ばれる方法で、文字列から全文検索用のインデックスを作成します。
pg_bigmプロジェクトでは以下の1つのモジュールを提供します。
モジュール名 | 概要 | ソースアーカイブファイル名 |
---|---|---|
pg_bigm | PostgreSQL上で全文検索機能を提供するモジュール | pg_bigm-x.y-YYYYMMDD.tar.gz |
ソースアーカイブファイル名のx.yとYYYYMMDDの部分は、それぞれ、そのファイルのバージョン番号とリリース年月日です。 例えば、2013年11月22日リリースのバージョン1.1のファイルでは、x.yは1.1、YYYYMMDDは20131122です。
pg_bigmのライセンスはThe PostgreSQL License(BSDに似たライセンス)です。
PostgreSQLには、pg_trgmという3-gram(トライグラム)の全文検索モジュールがcontribに付属されています。 pg_bigmは、pg_trgmをベースに開発されています。 pg_trgmとpg_bigmでは、機能や特徴に以下の違いがあります。
機能や特徴 | pg_trgm | pg_bigm |
---|---|---|
全文検索インデックスの作成方法 | 3-gram | 2-gram |
利用できるインデックスの種類 | GINとGiST | GINのみ |
利用できるテキスト検索演算子 | LIKE (~~)、ILIKE (~~*)、~、~* | LIKEのみ |
日本語検索 | 未対応(*1) | 対応済 |
検索キーワード1~2文字での検索 | 低速 (検索時に全文検索インデックスを使えない(*2)) |
高速 (検索時に全文検索インデックスを使える) |
類似文字列の検索 | 対応済 | 未対応 |
インデックス作成が可能な列の最大サイズ | 238,609,291Byte (約228MB) | 107,374,180 Bytes (約102MB) |
pg_trgmとpg_bigmを同じデータベース内で共存させることはできません。 pg_bigmを登録するデータベースには、pg_trgmを同時に登録しないでください。
pg_bigmは、以下の環境で動作確認をしています。
カテゴリ | モジュール名 |
---|---|
OS | Red Hat Enterprise Linux 6.1 x86_64 |
DBMS | PostgreSQL 9.1, 9.2 |
pg_bigmは、PostgreSQL9.1以降に対応しています。9.0以前には未対応です。
PostgreSQLのオフィシャルサイトからPostgreSQLのソースアーカイブファイルpostgresql-X.Y.Z.tar.gz(X.Y.Zは実際のバージョン番号に置き換えてください)をダウンロードし、ビルドとインストールを行います。
$ tar zxf postgresql-X.Y.Z.tar.gz $ cd postgresql-X.Y.Z $ ./configure --prefix=/opt/pgsql-X.Y.Z $ make $ su # make install # exit
RPMからPostgreSQLをインストールしてもpg_bigmは利用可能です。 この場合、postgresql-develパッケージをインストールしなければならないことに注意してください。
ここからpg_bigmのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。
$ tar zxf pg_bigm-x.y-YYYYMMDD.tar.gz $ cd pg_bigm-x.y-YYYYMMDD $ make USE_PGXS=1 PG_CONFIG=/opt/pgsql-X.Y.Z/bin/pg_config $ su # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-X.Y.Z/bin/pg_config install # exit
データベースクラスタの作成後、postgresql.confを編集、PostgreSQLを起動し、pg_bigmをデータベースに登録します。
$ initdb -D $PGDATA --locale=C --encoding=UTF8 $ vi $PGDATA/postgresql.conf shared_preload_libraries = 'pg_bigm' custom_variable_classes = 'pg_bigm' $ pg_ctl -D $PGDATA start $ psql -d <データベース名> =# CREATE EXTENSION pg_bigm; =# \dx pg_bigm List of installed extensions Name | Version | Schema | Description ---------+---------+--------+--------------------------------------- pg_bigm | 1.0 | public | text index searching based on bigrams (1 row)
pg_bigmのインストールは以上で終わりです。
pg_bigmについて、データベースからの登録解除とアンインストールを行います。
$ psql -d <データベース名> =# DROP EXTENSION pg_bigm CASCADE; =# \q $ pg_ctl -D $PGDATA stop $ su # cd <pg_bigmのソースディレクトリ> # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-X.Y.Z/bin/pg_config uninstall # exit
postgresql.confの以下の設定を削除します
GINインデックスを利用して全文検索用のインデックスを作成します。
以下の実行例では、PostgreSQL関連ツールの名前と説明を管理するテーブルpg_toolsを作成し、4件データを投入します。その後、ツールの説明に対して全文検索用のインデックスを作成します。
=# CREATE TABLE pg_tools (tool text, description text); =# INSERT INTO pg_tools VALUES ('pg_hint_plan', 'PostgreSQLでHINT句を使えるようにするツール'); =# INSERT INTO pg_tools VALUES ('pg_dbms_stats', 'PostgreSQLの統計情報を固定化するツール'); =# INSERT INTO pg_tools VALUES ('pg_bigm', 'PostgreSQLで2-gramの全文検索を使えるようにするツール'); =# INSERT INTO pg_tools VALUES ('pg_trgm', 'PostgreSQLで3-gramの全文検索を使えるようにするツール'); =# CREATE INDEX pg_tools_idx ON pg_tools USING gin (description gin_bigm_ops);
また、以下の実行例のように、全文検索用のマルチカラムインデックスを作成したり、作成時にGINインデックスのパラメータを指定することもできます。
=# CREATE INDEX pg_tools_multi_idx ON pg_tools USING gin (tool gin_bigm_ops, description gin_bigm_ops) WITH (FASTUPDATE = off);
pg_bigmでは、LIKE演算子の中間一致検索により全文検索を行います。
=# SELECT * FROM pg_tools WHERE description LIKE '%全文検索%'; tool | description ---------+------------------------------------------------------ pg_bigm | PostgreSQLで2-gramの全文検索を使えるようにするツール pg_trgm | PostgreSQLで3-gramの全文検索を使えるようにするツール (2 rows)
likequeryは、全文検索できるように、検索文字列(引数1)をLIKE演算子のパターンに変換する関数です。
引数1がNULLの場合、戻り値はNULLです。
変換は、具体的には以下を行います。
pg_bigmでは、LIKE演算子の中間一致検索により全文検索を行います。このため、上記のとおり検索文字列を変換して、LIKE演算子に渡す必要があります。この変換は、通常、クライアントアプリケーション側で実装しなければなりません。しかし、likequeryを利用することで、その実装の手間を省くことができます。
=# SELECT likequery('pg_bigmは検索性能を200%向上させました。'); likequery --------------------------------------------- %pg\_bigmは検索性能を200\%向上させました。% (1 row)
「全文検索の実行」の実行例の検索SQLは、likequeryを使うことで、以下のように書き換えられます。
=# SELECT * FROM pg_tools WHERE description LIKE likequery('全文検索'); tool | description ---------+------------------------------------------------------ pg_bigm | PostgreSQLで2-gramの全文検索を使えるようにするツール pg_trgm | PostgreSQLで3-gramの全文検索を使えるようにするツール (2 rows)
show_bigmは、文字列(引数1)のすべての2-gram文字列を配列として表示する関数です。
2-gram文字列とは、文字列の先頭と末尾に空白文字を追加した上で、文字列を1文字ずつずらしながら、2文字単位で抽出した文字列のことです。例えば、文字列「ABC」の2-gram文字列は、「(空白)A」「AB」「BC」「C(空白)」の4つになります。
=# SELECT show_bigm('PostgreSQLの全文検索'); show_bigm ----------------------------------------------------------------- {の全,全文,文検,検索,"索 "," P",Lの,Po,QL,SQ,eS,gr,os,re,st,tg} (1 row)
pg_gin_pending_statsは、GINインデックス(引数1)の待機リストに含まれているデータのページ数とタプル数を返却する関数です。
FASTUPDATEオプション無効で作成されたGINインデックスが引数1の場合、そのGINインデックスは待機リストを持たないため、戻り値1と2は0となることに注意してください。 GINインデックスの待機リストとFASTUPDATEオプションの詳細は、GIN高速更新手法を参照してください。
=# SELECT * FROM pg_gin_pending_stats('pg_tools_idx'); pages | tuples -------+-------- 1 | 4 (1 row)
pg_bigm.last_updateは、pg_bigmモジュールの最終更新日付を報告するパラメータです。このパラメータは読み取り専用です。 postgresql.confやSET文で設定値を変更することはできません。
=# SHOW pg_bigm.last_update; pg_bigm.last_update --------------------- 2013.11.22 (1 row)
pg_bigm.enable_recheckは、全文検索の内部処理であるRecheckを行うかどうか指定するパラメータです。デフォルト値はonで、Recheckを行います。このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。全文検索において正しい検索結果を得るには、このパラメータは有効化されていなければなりません。
pg_bigmを使った全文検索では、内部的には以下2つの処理で検索結果が取得されます。
この後者の処理がRecheckと呼ばれます。全文検索インデックスからの検索結果の取得では、必ずしも正しい結果ばかりが得られるとは限りません。誤った結果が含まれる可能性があります。この誤った結果を取り除くのがRecheckになります。
例えば、テーブルに「ここは東京都」「東京と京都に行く」の2つの文字列が格納されている状況を想像してください。検索文字列「東京都」で検索した場合、正しい結果は「ここは東京都」です。しかし、全文検索インデックスからの結果取得では、「東京と京都に行く」も結果候補として取得できてしまいます。これは、検索文字列の2-gram文字列である「東京」と「京都」が「東京と京都に行く」に含まれているためです。 Recheckは、結果候補それぞれについて検索文字列「東京都」が含まれるのか再チェックを行い、正しい結果だけを選択します。
このRecheckによる検索結果の絞り込みの様子は、EXPLAIN ANALYZEの結果から確認できます。
=# CREATE TABLE tbl (doc text); =# INSERT INTO tbl VALUES('ここは東京都'); =# INSERT INTO tbl VALUES('東京と京都に行く'); =# CREATE INDEX tbl_idx ON tbl USING gin (doc gin_bigm_ops); =# SET enable_seqscan TO off; =# EXPLAIN ANALYZE SELECT * FROM tbl WHERE doc LIKE likequery('東京都'); QUERY PLAN ----------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tbl (cost=12.00..16.01 rows=1 width=32) (actual time=0.022..0.023 rows=1 loops=1) Recheck Cond: (doc ~~ '%東京都%'::text) -> Bitmap Index Scan on tbl_idx (cost=0.00..12.00 rows=1 width=0) (actual time=0.015..0.015 rows=2 loops=1) Index Cond: (doc ~~ '%東京都%'::text) Total runtime: 0.059 ms (5 rows)
Bitmap Index Scanのrowsは2となっており、全文検索インデックスからは2件結果を取得しています。 Recheck実行後のBitmap Heap Scanのrowsは1となっており、2件の結果候補から1件に絞り込まれた様子を確認できます。
pg_bigm.enable_recheckを無効化することで、Recheckをスキップさせ、全文検索インデックスから取得した結果候補をそのまま最終的な検索結果とすることができます。以下の実行例では、このパラメータの無効化により、誤った検索結果の「東京と京都に行く」を得られています。
=# SELECT * FROM tbl WHERE doc LIKE likequery('東京都'); doc -------------- ここは東京都 (1 row) =# SET pg_bigm.enable_recheck TO off; =# SELECT * FROM tbl WHERE doc LIKE likequery('東京都'); doc ------------------ ここは東京都 東京と京都に行く (2 rows)
このパラメータは、正しい検索結果を得る必要がある運用時には必ずonに設定されていなければなりません。一方、Recheckのオーバーヘッドを評価するなど、デバッグ時にoffに設定しても構いません。
pg_bigm.gin_key_limitは、検索文字列の2-gram文字列のうち最大で何個を全文検索インデックスの検索に使うか指定するパラメータです。設定値が0(デフォルト値)の場合は、検索文字列のすべての2-gram文字列をインデックス検索に使います。このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。
pg_bigmの全文検索では、基本的に、検索文字列のすべての2-gram文字列を使ってGINインデックスを検索します。ただし、現在のGINインデックスの実装では、検索に使う2-gram文字列の個数が多いほどインデックス検索の負荷は高くなります。このため、検索文字列の文字数が多く、2-gram文字列の個数が多くなりやすいシステムでは、検索性能は劣化しやすいです。 pg_bigm.gin_key_limitによりGINインデックスの検索に使う2-gram文字列の最大数を制限することで、この性能問題を解決できます。
ただし、インデックス検索に使う2-gram文字列の個数が減ると、インデックスから取得した検索結果候補にはより多くの誤った結果が含まれることになります。このため、Recheckの負荷が高まり、逆に、より性能劣化する可能性もあるため注意が必要です。
pg_bigmでは、列サイズが107,374,180Byte (約102MB)を越える列へインデックスを作成できません。制限を越える大きさのデータを挿入するとエラーを起こします。
=# CREATE TABLE t1 (description text); =# CREATE INDEX t1_idx ON t1 USING gin (description gin_bigm_ops); =# INSERT INTO t1 SELECT repeat('A', 107374181); ERROR: out of memory
この制約はpg_trgmにも存在しますが、pg_trgmでは最大238,609,291Byte (約228MB)までインデックスの作成が可能です。