はじめに
最近、Web系のエンジニアに転職して、Railsをよく触っています。 Rails界隈では、HerokuかActiveRecordの関係かよくわかりませんがPostgreSQLが利用されていることが多いような気がします。
これまで個人的に全文検索のWebサービスを開発するためにGroongaとよく戯れていたのですが、最近はなかなか戯れることができていません。
最近になってRailsとPostgreSQLを触りはじめたという状況ですが、先日、PostgreSQLでGroongaが使えるPGroonga 0.20がリリースされたようです。
PostgreSQLで簡単に日本語対応で高速な全文検索が使えるようになるなんて素晴らしいじゃないですか。
最近はRailsの使い方ばっかり調べていて、若干知識欲が満たされない感があったので、PostgreSQLの知識向上がてら、PGroongaと、PGroongaと同じく日本語対応の全文検索モジュールであるpg_bigmの性能を検証してみました。
検証環境
- ハードウェア
CPU | メモリ | ディスク |
---|---|---|
Intel(R) Xeon(R) CPU E5620 @ 2.40GHz 1CPU 4Core | 32GB | HDD 2TB |
* ソフトウェア
ソフトウェア | バージョン |
---|---|
PostgreSQL | 9.4.0 |
PGroonga | 0.3.0(2015/2/1時点最新マスター) |
Groonga | 4.0.8 |
pg_bigm | 1.1 |
CentOS | 6.5 |
テーブル定義
- PGroonga
CREATE TABLE text ( id integer, title text, text text ); CREATE INDEX pgroonga_index ON text USING pgroonga (text);
- pg_bigm
CREATE TABLE text ( id integer, title text, text text ); CREATE INDEX pg_bigm_index ON text USING gin (text gin_bigm_ops);
更新手順
- Wikipedia(ja)のデータ1万件(XMLの状態で169MiB)を1件ずつスクリプトでシーケンシャルにinsert(バルクインサートはしない)
データ挿入中にWALログの
checkpoint
が走らないようにpostgresql.conf
に以下の設定を行うpostgresql.conf
checkpoint_segments = 64 checkpoint_timeout = 1h
- 更新SQL
INSERT INTO text VALUES (1, "title", "text");
- 最後に1回だけ
checkpoint
コマンド実行
checkpoint;
検索手順
- Wikipedia(ja)の日本語のみのカテゴリのうち、上記のデータで1件以上ヒットするものをランダムに500件抽出したものを1件ずつSELECTで全文検索を実行
- 純粋なindexscanの速度を比較するため、pg_bigmとPGroongaではSELECTを発行する前に以下のようにしてシーケンシャルスキャンを無効
SET enable_seqscan TO off;
- 以下のコマンドでキャッシュをクリアし、プロセスを再起動してから検索実行
echo 3 > /proc/sys/vm/drop_caches
- 検索SQL(pg_bigm,indexなし)
SELECT COUNT(*) as cnt FROM text WHERE text LIKE '%カテゴリー%';
- 検索SQL(PGroonga)
SELECT COUNT(*) as cnt FROM text WHERE text %% 'カテゴリー';
更新時間
indexなし | pg_bigm | pgroonga | |
---|---|---|---|
1万件トータル | 102.618sec | 238.485 sec | 191.193 sec |
平均 | 0.0102 sec | 0.0238 sec | 0.0191 sec |
更新時間はわずかにpg_bigm
よりもPGroonga
の方がやや速かったです。
検索時間
indexなし | pg_bigm | pgroonga | |
---|---|---|---|
500件トータル | 664.393 sec | 38.764 sec | 11.604 sec |
平均 | 1.328 sec | 0.0775 sec | 0.0232 sec |
検索時間はpg_bigm
よりもPGroonga
の方が3倍以上速かったです。indexなしに比べれば、pg_bigm
もかなり速いことがわかります。
- EXPLAIN例
pgroonga=# EXPLAIN ANALYZE SELECT COUNT(*) as cnt FROM text WHERE text %% 'テレビアニメ'; QUERY PLAN --------------------------------------------------------------------------------------------------------------- ------------------------ Aggregate (cost=487.81..487.82 rows=1 width=0) (actual time=532.997..532.997 rows=1 loops=1) -> Bitmap Heap Scan on text (cost=43.21..475.21 rows=5040 width=0) (actual time=454.347..532.810 rows=359 loops=1) Recheck Cond: (text %% 'テレビアニメ'::text) Heap Blocks: exact=173 -> Bitmap Index Scan on pgroonga_index (cost=0.00..41.95 rows=5040 width=0) (actual time=454.102..45 4.102 rows=359 loops=1) Index Cond: (text %% 'テレビアニメ'::text) Planning time: 415.373 ms Execution time: 538.047 ms (8 rows)
pg_bigm=# EXPLAIN ANALYZE SELECT COUNT(*) as cnt FROM text WHERE text LIKE '%テレビアニメ%'; QUERY PLAN --------------------------------------------------------------------------------------------------------------- --------------------- Aggregate (cost=108.02..108.03 rows=1 width=0) (actual time=1036.064..1036.065 rows=1 loops=1) -> Bitmap Heap Scan on text (cost=104.01..108.02 rows=1 width=0) (actual time=165.421..1035.735 rows=359 l oops=1) Recheck Cond: (text ~~ '%テレビアニメ%'::text) Rows Removed by Index Recheck: 321 Heap Blocks: exact=214 -> Bitmap Index Scan on pg_bigm_index (cost=0.00..104.01 rows=1 width=0) (actual time=121.101..121.1 01 rows=680 loops=1) Index Cond: (text ~~ '%テレビアニメ%'::text) Planning time: 115.805 ms Execution time: 1048.345 ms (9 rows)
この検索クエリの例ではPGroonga
の方がpg_bigm
よりも2倍ぐらい速いですね。
- 開発者のコメント
@naoa_y ありがとうございます!pg_bigmの方が遅い検索は「Rows Removed by Index Recheck」が影響している気がするので、狙い通りな気がします!
— す (@ktou) 2015, 2月 3
サイズ
indexなし | pg_bigm | pgroonga |
---|---|---|
92MiB | 650MiB | 672MiB*1 |
サイズは、PGroonga
の方がpg_bigm
よりも少しだけ大きくなっています。
現状のPGroongaでは、全文インデックス以外にデータがPostgreSQLだけでなくGroongaのストレージにも格納されており、サイズがやや大きくなっています。
現在の実装では、Groonga側のデータは利用されていません。これについては今後、圧縮等によりいくらか改善されるかもしれません。
おわりに
上記のように、PGroongaは高速な日本語全文検索機能を簡単に追加することができて非常に便利です。 もし、PGroongaのExtensionがHerokuのPostgreSQLアドオンに配備されるなんてことになれば、Herokuで簡単に 日本語対応の高速な全文検索ができるようになって素敵ですね!
期待しています!