pg_bigmで全文検索する
PostgreSQLインサイド

PostgreSQLの周辺ツールの1つであるpg_bigmを使って、全文検索する方法について解説します。

1. pg_bigmとは

pg_bigm(ピージーバイグラム)は、SQL文で全文検索を使用できるツールです。このツールは、2-gram(バイグラム)と呼ばれる方法で、文字列から全文検索用のインデックスを作成します。このインデックスを使って、ユーザーは高速に文字列検索を実行できます。
PostgreSQLには、pg_trgm(ピージートライグラム)という全文検索モジュールがcontribに付属されていますが、pg_trgmは日本語のようなマルチバイト文字列の検索には適していません。そこで、マルチバイト文字列を扱う全文検索用の周辺オープンソースソフトウェアとして、pg_trgmをベースに開発されたのがpg_bigmです。pg_trgmとpg_bigmの違いを簡単にまとめます。

表1. pg_trmgとpg_bigmの違い

機能や特長 pg_trgm pg_bigm
全文検索用のインデックスの作成方法 3-gram 2-gram
利用できるインデックスの種類 GINとGiST GIN
利用できるテキスト検索演算子 LIKE(~~)、ILIKE(~~*)、~、~* LIKE
日本語検索 未対応 対応済

全文検索用のインデックスとは

全文検索とは、複数の検索対象の全文書から特定の文字列を検索することです。PostgreSQLで全文検索を高速化するためには、GiSTインデックスとGINインデックスが使用できますが、pg_bigmと組み合わせる場合はGINインデックスにのみ対応します。GINインデックスは文書中の単語の位置を保持しているため、特定の単語の検索を効率的に行えるようになります。GINインデックスの詳細については、「PostgreSQL文書」を参照してください。

2-gramとは

全文検索技術の1つに「N-gram」という方法があります。これは任意の文字列や文章を連続したN個の文字単位または単語単位で分割するテキスト分割方法です。Nが1の場合を1-gram(ユニグラム)、 Nが2の場合を2-gram(バイグラム)、 Nが3の場合を3-gram(トライグラム)と呼びます。
「これは本です。」という例文をN-gramに適用して文字単位に分割すると、以下になります。

種別 1 2 3 4 5 6 7
1-gram
2-gram これ れは は本 本で です す。  
3-gram これは れは本 は本で 本です です。    

pg_bigmは2-gramを採用しているため、文字列中の連続する2文字ごとに全文検索用のインデックスを作成します。

参考

  • pg_bigmの仕様については、オープンソースソフトウェアに同梱されているマニュアルを参照してください。
  • pg_bigmは便利な機能ですが、注意点もあります。ご利用の前には必ず「4. pg_bigm利用時の注意点」をお読みください。

2. 準備

pg_bigmを利用するには、以下の準備が必要です。なお、pg_bigmはLinuxとMac OS上で動作します。今回は、Linux上でpg_bigm 1.2をベースに説明します。
PostgreSQLおよびpg_bigmのインストールは完了し、インスタンスのエンコーディングはUTF8とします。

  1. postgresql.confファイルのshared_preload_librariesに「pg_bigm」を追加します。
shared_preload_libraries = 'pg_bigm'
  1. PostgreSQLを起動または再起動します。
  2. 本機能を利用するデータベースpostgresに対して、CREATE EXTENSION を実施します。
$ psql -d postgres -c "CREATE EXTENSION pg_bigm;"

3. pg_bigmの使い方

実際にpg_bigmを使って、文字列を検索する方法について説明します。
使用したデータは、PostgreSQLインサイドの「PostgreSQL技術インデックス」に掲載されている各記事のタイトルと記事本文を抽出したものです。

3.1 GINインデックスの作成

データベースpostgres上にテーブルを作成し、GINインデックスを作成します。

  1. 検索対象のテーブルpg_tblを作成してデータを格納し、全文検索用のインデックスpg_idxを作成します。
    (1)インデックスメソッドには"gin"を指定します。
    (2)演算子クラスには"gin_bigm_ops"を指定します。

検索対象のテーブルpg_tblを作成してデータを格納し全文検索用のインデックスpg_idxを作成

  1. pg_tblテーブルの構成を確認します。

pg_tblテーブルの構成を確認

3.2 全文検索の実行

pg_bigmでは、LIKE演算子の中間一致検索を使って全文検索ができます。

例1)複数のキーワードを検索する

記事本文に「レプリケーション」および「トランザクションログ」という単語を含む、PostgreSQL技術インデックスのタイトルを検索します。

複数のキーワードを検索

例2)英字を含む文字列を検索する

記事本文に「Index Only Scan」という単語を含む、PostgreSQL技術インデックスのタイトルを検索します。

英字を含む文字列を検索

ヒント

検索キーワードに英字を指定する場合、大文字と小文字は区別する必要があります。大文字と小文字を区別せずに検索する場合は、文字列関数のlower関数やupper関数を使うことで対応できます。

大文字と小文字を区別せずに検索する場合

pg_bigmを使いこなすためには、以下の関数が用意されています。本記事では、bigm_similarity関数の使用例を紹介します。

関数名 機能の説明
bigm_similarity(引数1,引数2) 文字列(引数1)と文字列(引数2)の類似度(文字列がどの程度似ているかを示す数値)を返却する関数
likequery(引数1) 全文検索できるように、検索文字列(引数1)をLIKE演算子のパターンに変換する関数
pg_gin_pending_stats(引数1) GINインデックス(引数1)の待機リストに含まれているデータのページ数とタプル数を返却する関数
show_bigm(引数1) 文字列(引数1)のすべての2-gram文字列を配列として表示する関数

3.3 類似度検索の実行

pg_bigmでは、=%演算子を使って類似度検索もできます。類似度検索では、検索条件の文字列との類似度が閾値以上の行が検索結果となり、検索キーワードに指定した文字列と似ている文字列を検索できます。類似度は、postgresql.confファイルにpg_bigm.similarity_limitパラメーターを追加指定します。設定値は0以上1以下の小数点で、デフォルトは0.3です。1に近いほど類似度が高いことを示します。

  1. pg_bigm.similarity_limitの値を確認します。タイトルに「pg_statinfo」と類似の単語を持つ、PostgreSQL技術インデックスのタイトルを検索します。

pg_bigm.similarity_limitの値を確認

  1. pg_bigm.similarity_limitの類似度を「0.15」に変更して、同様に検索します。
    類似度を0.3から0.15に下げることで、「pg_statinfo」に近いタイトルが2件追加されました。

pg_bigm.similarity_limitの類似度を0.15に変更して検索

  1. 「pg_statinfo」と「pg_statsinfo」の類似度、および「pg_statinfo」と「pg_dbms_stats」の類似度をbigm_similarity関数で計算してみましょう。

pg_statinfoとpg_statsinfo、pg_statinfoとpg_dbms_statsの類似度をbigm_similarity関数で計算

検索キーワードに類似した文字列に絞りたい場合は類似度を高くし、類似した文字列をより多く検出したい場合は類似度を低くするなど調整してください。類似度の計算方法などについては、オープンソースソフトウェアに同梱されているマニュアルのbigm_similarity関数を参照してください。

3.4 大量データによる全文検索の性能検証

約17万件の日本語版Wikipediaの要約データを使って、全文検索の性能を検証します。

  1. 検索対象のテーブルwiki_tblを作成してデータを格納します。全文検索用のインデックスを作成せずに、要約文中に「平安時代後期から鎌倉時代前期にかけての公卿」という文言を含む、Wikipediaのタイトルを検索します。
    (1)検索処理の実行時間は、約1.1秒です。

全文検索用のインデックスを作成せずに検索

  1. SELECT文の実行計画を確認します。
    (2)全文検索用のインデックスが無いため、テーブルwiki_tblに対して検索方式「Parallel Seq Scan」が選択されています。

SELECT文の実行計画を確認

  1. 検索対象のテーブルに、全文検索用のインデックスwiki_idxを作成し、手順1.と同じSQL文で検索します。
    (3)全文検索用のインデックスの作成時間です。約7秒かかっています。
    (4)検索処理の実行時間は、約1.3ミリ秒です。全文検索用のインデックスがない(1)と比較して、約856倍速くなっています。

全文検索用のインデックスを作成して検索

  1. SELECT文の実行計画を確認します。
    (5)全文検索用のインデックスwiki_idxを利用した検索方式「Bitmap Index Scan」が選択され、高速に処理できていることが確認できます。

SELECT文の実行計画を確認

4. pg_bigm利用時の注意点

実際にpg_bigmを利用する際の注意点について紹介します。

大文字と小文字を同一視しない

「3.2 全文検索の実行」の「ヒント」に示したようにpg_bigm は英字の大文字と小文字を同一視せずに、区別することに注意してください。
「INDEX」と「index」の類似度をbigm_similarity関数で確認すると、以下になります。

「INDEX」と「index」の類似度をbigm_similarity関数で確認

列の最大サイズ

pg_bigmのインデックス対象文字列にはサイズ上限があります。107,374,180 Bytes(約102MB)を超える文字列には適用できません。

チューニングパラメーターの設定

pg_bigmの動作をチューニングできるパラメーターのうち、正常な動作をさせるために「pg_bigm.enable_recheck」は、デフォルト値(on)のまま利用してください。
pg_bigmを使った全文検索では、内部的には以下2つの処理で検索結果が取得されます。

  • 全文検索用のインデックスからの検索結果候補の取得
  • 検索結果候補からの正しい検索結果の選択

この後者の処理がRecheckと呼ばれます。全文検索用のインデックスからの検索結果の取得では、必ずしも正しい結果だけが得られるとは限りません。誤った結果が含まれる可能性があります。この誤った結果を取り除くのがRecheckになります。このパラメーターは、正しい検索結果を得る必要がある運用時には必ずonに設定されていなければなりません。ただし、Recheckのオーバーヘッドを評価するなど、デバッグ時にoffに設定しても構いません。

ここまで説明してきましたが、pg_bigmは比較的簡単な手順で利用できることがおわかりいただけたと思います。注意事項に気を付けて、文字列検索処理の業務要件に合わせてご利用をご検討ください。

参考

FUJITSU Software Enterprise Postgresでは、バージョン10からpg_bigmを同梱しています。製品のインストール時にpg_bigmをプリインストールしているので、追加モジュールを取得する必要はありません。

2021年9月24日

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ