★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

F.35. pg_trgm

pg_trgmモジュールは、類似文字列の高速検索をサポートするインデックス演算子クラスだけではなく、トリグラム一致に基づくASCII英数字の類似度の決定に関する関数と演算子も提供します。

F.35.1. トリグラム(またはトリグラフ)の概念

トリグラムは文字列から3つの連続する文字を取り出したグループです。 共有するトリグラムの個数を数えることで、2つの文字列の類似度を測定することができます。 この単純な考えが、多くの自然言語における単語の類似度を測定する際に非常に効率的であることが判明しています。

注意: 文字列内に含まれるトリグラム集合を決める際、文字列の前に2つの空白、後に1つの空白が付いているものとみなされます。 例えば、"cat"という文字列のトリグラム集合は、" c"" ca""cat""at "です。

F.35.2. 関数と演算子

pg_trgmモジュールで提供される関数を表F-22に、演算子を表F-23に示します。

表 F-22. pg_trgm関数

関数戻り値説明
similarity(text, text)real2つの引数がどの程度似ているかを示す数値を返します。 結果はゼロ(2つの文字列にまったく類似度がないことを示す)から1(2つの文字列が同一であることを示す)までの範囲です。
show_trgm(text)text[]与えられた文字列内のすべてのトリグラムからなる配列を返します。 (実際これはデバッグ時を除いて役に立つことはほぼありません。)
show_limit()real%演算子で使用される現在の類似度閾値を返します。 これは、例えば2つの単語それぞれでミススペルがあったとしても類似しているものとみなす、その2つの単語間の最低の類似度を設定します。
set_limit(real)real%演算子で使用される現在の類似度閾値を設定します。 閾値は0から1までの値でなければなりません(デフォルトは0.3です)。 渡された値と同じ値が返ります。

表 F-23. pg_trgm演算子

演算子戻り値説明
text % textboolean2つの引数がset_limitで設定された類似度閾値以上の類似度を持つ場合trueを返します。
text <-> textreal引数間の"距離"、つまり1 - similarity()の値を返します。

F.35.3. インデックスサポート

pg_trgmモジュールは、テキスト列全体に非常に高速な類似度検索を行うためのインデックスを作成することができるように、GiSTおよびGINインデックス演算子クラスを提供します。 これらのインデックス種類は上記類似度演算子をサポートし、さらにLIKEおよびILIKE問い合わせにおけるトリグラムを基にしたインデックス検索をサポートします。 (これらのインデックスは等価性や単純な比較演算子をサポートしません。ですので通常のB-treeインデックスも必要になるかもしれません。)

例:

CREATE TABLE test_trgm (t text);
CREATE INDEX trgm_idx ON test_trgm USING gist (t gist_trgm_ops);

または

CREATE INDEX trgm_idx ON test_trgm USING gin (t gin_trgm_ops);

この段階で、テキスト列tに類似度検索で使用可能なインデックスがあります。 典型的な問い合わせを以下に示します。

SELECT t, similarity(t, 'word') AS sml
  FROM test_trgm
  WHERE t % 'word'
  ORDER BY sml DESC, t;

これはwordに十分似たテキスト列の値をすべて、類似度の高い順番に返します。 インデックスは非常に大規模なデータ群に対する高速操作を行うために使用されます。

以下は上の問い合わせを変形させたものです。

SELECT t, t <-> 'word' AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

これはGINインデックスではなくGiSTインデックスにより非常に効率的に実装することができます。 通常、類似度が高いものの中から少ない個数のみを必要とする場合、1番目の式よりも効率的です。

PostgreSQL 9.1から、これらのインデックス種類はLIKEおよびILIKEにおけるインデックス検索をサポートします。 以下に例を示します。

SELECT * FROM test_trgm WHERE t LIKE '%foo%bar';

インデックス検索は、検索文字列からトリグラムを抽出し、それらをインデックスから検索することによって動作します。 検索文字列内のトリグラムが多ければ、よりインデックス検索が効率的になります。 B-treeを基にした検索とは異なり、検索文字列の左側が固定されている必要はありません。

GiSTまたはGINインデックスの選択は、他で説明されるGiSTとGINの相対的な性能特性に依存します。 まとめとしては、GINインデックスはGiSTインデックスより検索が高速ですが、構築または更新は低速です。 このためGINは静的なデータに、GiSTはよく更新されるデータに適しています。

F.35.4. テキスト検索の統合

トリグラム一致は全文テキストインデックスと一緒に使用する時、非常に有用なツールです。 特に、全文検索機構では直接一致しない、ミススペルがある入力単語の認識を行うために役に立ちます。

第一段階は文書内で一意な単語からなる補助テーブルを生成することです。

CREATE TABLE words AS SELECT word FROM
        ts_stat('SELECT to_tsvector(''simple'', bodytext) FROM documents');

ここでdocumentsは、検索対象のbodytextテキストフィールドを持つテーブルです。 言語固有の設定を使用するのではなく、to_tsvector関数でsimple設定を使用する理由は、元の(語幹抽出されていない)単語のリストが欲しいためです。

次にword列にトリグラムインデックスを作成します。

CREATE INDEX words_idx ON words USING gin(word gin_trgm_ops);

これで、上の例に似たSELECT問い合わせを使用して、ユーザの検索語内でミススペルのある単語を提示できるようになります。 有用な追加された試験は、選択された単語の長さがミススペルのある単語の長さとほぼ同じになることを要求するものです。

注意: wordsテーブルは別に生成された静的なテーブルですので、文書群の更新に合理的に追従できるよう定期的に再生成する必要があります。 正確に最新状態を維持する必要性は通常ありません。

F.35.5. 参考

GiST開発サイト http://www.sai.msu.su/~megera/postgres/gist/

Tsearch2開発サイト http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/

F.35.6. 作者

Oleg Bartunov , Moscow, Moscow University, Russia

Teodor Sigaev , Moscow, Delta-Soft Ltd.,Russia

文書作成: Christopher Kings-Lynne

本モジュールはロシアモスクワのDelta-Soft Ltd.による後援です。