全文検索を高速化するために、2種類のインデックスが使えます。 GINとGiSTです。 全文検索でインデックスが必須ではありませんが、日常的に検索される列には、インデックスを使った方が良いでしょう。
このようなインデックスを作成するには、次のいずれかを実行します。
CREATE INDEX name
ON table
USING GIN (column
);
GIN (Generalized Inverted Index)インデックスを作ります。
column
はtsvector
型でなければなりません。
CREATE INDEX name
ON table
USING GIST (column
[ { DEFAULT | tsvector_ops } (siglen = number
) ] );
GiST (Generalized Search Tree)インデックスを作ります。column
は tsvector
またはtsquery
型です。
オプションの整数パラメータsiglen
は署名の長さをバイト単位で決定します(詳細は以下を参照してください)。
GINインデックスの方がより好ましいテキスト検索インデックス形式です。
転置インデックスなので、マッチした位置の圧縮されたリストと合わせて各単語(語彙素)へのインデックスエントリを含みます。
複数単語での検索は最初のマッチを見つけることができ、その後、追加の単語がない行を削除するのにインデックスを使えます。
GINインデックスはtsvector
値の単語(語彙素)のみを格納しており、重み付けラベルは格納していません。
そのため、重みを含む問い合わせを使う場合には、テーブル行の再検査が必要です。
GiSTインデックスは、非可逆です。つまり、インデックスは間違った結果を返すかも知れないので、間違った結果を排除するために、テーブルの行をチェックすることが必要です。
(PostgreSQLはこの処理が必要とされた時に自動的に行います。)
GiSTインデックスが非可逆なのは、インデックス中の各文書が固定長の署名によって表現されているからです。
署名のバイト単位の長さはオプションの整数のパラメータsiglen
の値で決まります。
(siglen
が指定されない場合)デフォルトの署名の長さは124バイトで、最大の署名の長さは2024バイトです。
署名は、各々の単語をハッシュして単一なビットにして、これらのビットをnビットの文書署名にORし、nビットの列中のビットにすることで実現されています。
2つの単語が同じビット位置を生成すると、間違った一致が起こります。
問い合わせ対象のすべての単語が照合すると(それが正しいか間違っているかは別として)、その照合が正しいものかどうかテーブルの行を取得して調べなければなりません。
長い署名では、インデックスはより大きくなってしまいますが、(インデックスのより小さな部分とより少ないヒープページを走査することで)検索がより正確になります。
GiSTインデックスはカバリングにできます、すなわちINCLUDE
句を使えます。
列には、GiST演算子クラスを持たないデータ型をINCLUDEで含めることができます。
含まれる属性は圧縮されずに格納されます。
非可逆性は、間違った照合によるテーブルからの不必要なデータ取得のため、性能を劣化させます。 テーブルへのランダムアクセスは遅いので、GiSTインデックスの有用性は制限されています。 誤った照合がどの位あるかという可能性はいくつか要因によりますが、とりわけユニークな単語の数に依存します。ですから、辞書を使ってユニークな単語の数を減らすことをお勧めします。
GINインデックスの構築時間はmaintenance_work_memを増やすことによってしばしば改善することができることに注意してください。一方GiSTインデックスの構築時間にはあまりそのパラメータは効きません。
大きなデータをパーティショニングし、GIN、GiSTインデックスを適切に使うことによってオンラインの更新を伴いながら、非常に高速な検索を実現することができます。 パーティショニングは、以下のどちらかの方法でデータベースレベルで実現できます。(1)テーブルの継承を使う。(2)文書を複数のサーバに分散させ、外部の検索結果を集約する。たとえば外部データアクセスを使います。 2の方法は、ランキング関数がローカルな情報しか使わないため可能です。