これはPGroonga 2.X and 3.X用のドキュメントです。古いPGroongaを使っているならPGroonga 1.xのドキュメントを見てください。

PGroonga対textsearch対pg_trgm

PostgreSQLは2つの全文検索モジュールを提供しています。textsearchpg_trgmです。

textsearchモジュールはPostgreSQL組み込みの全文検索機能です。GiSTインデックスとGINインデックスをサポートしています。GiSTインデックスまたはGINインデックスを使うと全文検索性能を高めることができます。

pg_trgmモジュールはcontribモジュールです。pg_trgmは全文検索機能を提供します。pg_trgmもGiSTインデックスとGINインデックスをサポートしています。GiSTインデックスまたはGINインデックスを使うと全文検索機能を高めることができます。

このドキュメントはPGroongaとtextsearchとpg_trgmの違いを説明します。

特徴

各モジュールの特徴は次の通りです。

PGroonga

PGroongaは言語に特化した全文検索も言語に依存しない全文検索もどちらもサポートしています。PGroongaはデフォルトでは言語に依存しない全文検索を使います。通常、PGroongaはデフォルトで十分満足のいく全文検索結果を返します。

PGroongaはデフォルトで言語に依存しない全文検索を使うので、デフォルトですべての言語をサポートしています。ソースコードを変更する必要はありません。

「recheck」する必要がないのでPGroongaの検索は高速です。

PGroongaは更新中の検索をブロックしないので更新中も高速に検索できます。PGroongaは更新中も検索性能を落としません。

PGroongaは更新も高速です。

PGroongaはPostgreSQLに保存しているインデックス対象のテキストも保存しているのでインデックスサイズは大きいです。

textsearchモジュール

textsearchモジュールは言語に特化した全文検索を実装しています。英語の単語はステミングされます。「work」も「works」も「worked」もすべて「work」に変換します。ステミングは再現率を高めます。

言語に特化した全文検索はよりよい全文検索機能になるかもしれません。しかし、「言語に特化」しているということはだれかが「言語に特化」した処理を実装しなければいけないということです。PostgreSQL 9.6.1は英語やフランス語やロシア語と言った15の言語をサポートしています。しかし、日本語や中国語、韓国語を含むアジアの言語など多くの言語は未対応です。

textsearchモジュールは「recheck」する必要がないので検索は高速です。(重み機能を使う場合は「recheck」が必要です。)

textsearchモジュールは大きなテキストを扱うことができません。テキストの最大バイト数は1MiB - 1Bです。1MiB以上のテキストを追加した場合は次のエラーが発生します。

string is too long for tsvector (XXX bytes, max 1048575 bytes)

pg_trgmモジュール

pg_trgmモジュールは言語に依存しない全文検索を実装しています。しかし、pg_trgmはASCII以外の文字のサポートが無効になっています。つまり、デフォルトでは日本語や中国語といったアジアの言語はサポートしていないということです。ASCII以外の言語もサポートするにはcontrib/pg_trgm/trgm.h内の次の行をコメントアウトする必要があります。

#define KEEPONLYALNUM

Debianベースのシステムを使っている場合はC.UTF-8ロケールを使うことでpg_trgmのソースコードを変更しなくても非ASCII文字サポートを有効にできます。

pg_trgmモジュールは大量のドキュメントがマッチして各ドキュメントが長い場合は遅いです。なぜならpg_trgmはインデックスを使った検索のあとに「recheck」する必要があるからです。

概要

モジュール サポートしている言語 検索 更新 インデックスサイズ
PGroonga 全言語 速い 速い 大きい
textsearch 15(アジアの言語は未サポート) 速い とても遅い 小さい
pg_trgm ASCIIのみの言語 遅い 遅い 小さい

ベンチマーク

このセクションでは英語版Wikipediaを使ったベンチマーク結果を示します。ベンチマークスクリプトはpostgresql.shにあります。

概要

以下は全文検索インデックス作成のベンチマーク結果の概要です。

インデックス作成時間

以下は全文検索インデックスのサイズのベンチマーク結果の概要です。

インデックスサイズ

以下は全文検索性能のベンチマーク結果の概要です。

全文検索性能

以下はpg_trgmが遅すぎるのでpg_trgmを除いた全文検索性能のグラフです。

pg_trgmを除いた全文検索性能

環境

以下はベンチマーク環境です。

CPU Intel(R) Xeon(R) CPU E5-2660 v3 @ 2.60GHz (24cores)
メモリー 32GiB
スワップ 2GiB
ストレージ SSD (500GB)
OS CentOS 7.2

バージョン

以下はソフトウェアのバージョンです。

PostgreSQL PGroonga
9.6.1 1.1.9

データ

以下は対象データの統計情報です。

サイズ 約33GiB
レコード数 約530万件
タイトルの平均バイト数 約19.6B
タイトルの最大バイト数 211B
本文の平均バイト数 約6.4KiB
本文の最大バイト数 約1MiB(1047190B)

本文の最大バイト数が1MiB未満なのはtextsearchには重要なポイントです。もし、1MiB - 1B以上なら以下のエラーが発生してtextsearchのインデックスを作成できないからです。

string is too long for tsvector (1618908 bytes, max 1048575 bytes)

データロード

以下はデータロードのベンチマーク結果です。全文検索モジュールには依存しません。なぜならどのインデックスもまだ作られていないからです。

経過時間 データベースサイズ
約26分 約21GB

以下はデータをロードするSQLです。

COPY wikipedia FROM 'en-all-pages.csv' WITH CSV ENCODING 'utf8';

このCSVデータはen-all-pages.csv.xzからダウンロードできます。

以下はwikipediaテーブルを定義するSQLです。

CREATE TABLE wikipedia (
  id integer PRIMARY KEY,
  title text,
  text text
);

インデックス作成

以下は全文検索インデックス作成のベンチマーク結果です。

モジュール 経過時間 インデックスのサイズ 備考
PGroonga 約1時間24分 約39GB PGroongaはデータをコピーしてそれに対してインデックスを作成します。データはzlibで圧縮しています。インデックスだけのサイズは約27GBです。
textsearch 約2時間53分 約12GB maintenance_work_mem2GBです。インデックスに登録できなかった単語が3923あります。(*)
pg_trgm 約1時間50分 約7.6GB maintenance_work_mem2GBです。

(*) このケースが発生したときのエラーメッセージは以下の通りです。

NOTICE:  word is too long to be indexed
DETAIL:  Words longer than 2047 characters are ignored.

PGroongaのインデックス定義は以下の通りです。

CREATE INDEX wikipedia_index_pgroonga ON wikipedia
 USING pgroonga (title, text);

textsearchのインデックス定義は以下の通りです。

CREATE INDEX wikipedia_index_textsearch ON wikipedia
 USING GIN (to_tsvector('english', title),
            to_tsvector('english', text));

pg_trgmのインデックス定義は以下の通りです。

CREATE INDEX wikipedia_index_pg_trgm ON wikipedia
 USING GIN (title gin_trgm_ops, text gin_trgm_ops);

全文検索

全文検索のベンチマーク結果は以下の通りです。

クエリー:「animation」

モジュール 経過時間 ヒット数 相対経過時間 備考
PGroonga 約173ミリ秒 約4万件 約29  
Groonga 約6ミリ秒 約4万件 1  
textsearch 約1秒 約42万件 約167 他のケースよりもヒット数が10倍多いです。これはステミングのためです。「animation」はステミングされると「anim」になり、「anim」で検索しています。
pg_trgm 約44秒 約3万件 約7333  

クエリー:「database」

モジュール 経過時間 ヒット数 相対経過時間
PGroonga 約698ミリ秒 約21万件 約37
Groonga 約19ミリ秒 約21万件 1
textsearch 約602ミリ秒 約19万件 約32
pg_trgm 約33秒 約13万件 約1736

クエリー:「PostgreSQL OR MySQL」

モジュール 経過時間 ヒット数 相対経過時間
PGroonga 約6ミリ秒 1636件 約2
Groonga 約3ミリ秒 1636件 1
textsearch 約3ミリ秒 1506件 1
pg_trgm 約241ミリ秒 1484件 約80

クエリー:「America」

モジュール 経過時間 ヒット件数 相対経過時間
PGroonga 約1.3秒 約47万件 約29
Groonga 約45ミリ秒 約47万件 1
textsearch 約1.2秒 約48万件 約26
pg_trgm 約1分32秒 約140万件 約2044