LoginSignup
7
2

More than 1 year has passed since last update.

RDSで全文検索プラグインpg_bigmを試してみる手順のご紹介

Last updated at Posted at 2021-12-19

postgresqlで、多くのデータの中から候補となる選択肢を入力都度返すなどする場合、そのレスポンス速度が重要になってきます。10万件程度であれば、インデックスがなくとも都度全ての全部のデータをチェックして返す方法でも1秒以内に処理は完結すると思いますが、1000万件くらいになると、処理時間が10秒弱かかるようになり、ユーザビリティに影響を与えます。そのような場合、インデックスを作成することで、これまでインデックスが使えなかった日本語のlike検索も高速に結果を返すことができることが確認できたので、その手順と結果をここに紹介します。

作業環境

データベースは検証にはRDSのPostgres最新バージョンを利用しました(13.1)
クライアントからDBへの接続する際の環境(ツール)は、DBeaverを利用する前提としますが、特にこのツールでなくてはならないわけではありません。

シングルカラムのインデックス作成&検索

プラグインの有効化

まず、dbeaverでデータベースに接続し、Extentions > Create new Extension を選択します。
image.png

でてきた一覧からpg_bigmを選択します。
image.png

成功したら、Extensionsの下にpg_bigmが出てきます。この状態になれば、対象のデータベース内でpg_bigmを使ったインデックスが作成できます。

image.png

プラグインの追加は以下のSQLでもOKです。(こちらの方が簡単??)

-- Excentionを有効化
CREATE EXTENSION pg_bigm;
-- 確認
SELECT * FROM pg_extension;

テーブルの作成

CREATE TABLE sample_pg_tools (tool text, description text);

検証用データ(5000万件)のデータを作成

CREATE TABLE sample_data2 AS
SELECT num id, to_char(num,'FMAAA0000000000') textdata1,to_char(num2,'FMBBB00000000000') textdata2
FROM   generate_series(1,10000000) num, generate_series(1,5) num2
;
INSERT INTO sample_data2 VALUES (9000087, 'けいりのわな','東京のグループ');
INSERT INTO sample_data2 VALUES (9000087, 'ああああ','英単語を覚える必要がある');
INSERT INTO sample_data2 VALUES (9000086, 'こののりはいくつかの単純な単語が単語があるためpg_trgmでは検索にヒットしないワードがでてしまいます','東京のグループ');
INSERT INTO sample_data2 VALUES (9000087, '日本語は数多くの二文字の単語があるためpg_trgmでは検索にヒットしないワードがでてしまいます','東京のグループ');
INSERT INTO sample_data2 VALUES (9000088, '文中のどこかでりんごが含まれるデー','PostgreSQLで2-gramの全文検索を使えるようにするツール');
INSERT INTO sample_data2 VALUES (9000089, 'PostgreSQLでHINT句を使えるようにするツール','PostgreSQLでHINT句を使えるようにするツール');
INSERT INTO sample_data2 VALUES (9000090, 'PostgreDatabase ','aaax');

INSERT INTO sample_data2 VALUES (9000091, 'PostgreDaDatase ','aaaaaa');

データを検索(インデックスなし)

select * from sample_data2 where textdata1 like '%りんご%';

上記のSQLでも、2回目の実行時は20秒程度で実行が完了しました。

select * from sample_data2 where textdata2 like '%HINT%';

上記のSQLでは24秒かかりました。

image.png

インデックス追加

以下のSQLを実行し、textdata1カラムに対してbigmのインデックスを作成します。

CREATE INDEX sample_data2_idx1 ON sample_data2 USING gin (textdata1 gin_bigm_ops);

インデックスが作成を確認するために、以下のSQLを実行します。

SELECT indexname, indexdef
  FROM pg_indexes
 WHERE tablename = 'sample_data2';

インデックスが作成されたかどうかは画面からでも確認できます。

データを検索(インデックスありカラム)

先ほどと同じSQLでtextdata1を検索してみる。

select * from sample_data2 where textdata1 like '%りんご%';

50ms くらい。インデックスが効いてる。

データを検索(インデックスなしカラム)

select * from sample_data2 where textdata2 like '%HINT%';

先ほどど同じ、22秒くらい

複数カラムのインデックス作成と効果確認

複数カラム検索(インデックスなし)

textdata1とtextdata2をORで検索

select * from sample_data2 where textdata1 like '%りんご%' or textdata2 like '%HINT%';

22秒くらい。インデックス効いていない

複数カラムのインデックス作成

両方統合したインデックスを作成

-- 複数カラムインデックス作成
CREATE INDEX sample_data2_idx_multi ON sample_data2 USING gin (textdata1 gin_bigm_ops,textdata2 gin_bigm_ops);

作成に4分かかった

複数カラム検索

textdata1とtextdata2をORで検索

select * from sample_data2 where textdata1 like '%りんご%' or textdata2 like '%HINT%';

今度は80msで結果が返ってくるようになった。

image.png

一文字含むデータを検索した場合でも早い

select * from sample_data2 where textdata1 like '%り%' or textdata2 like '%単語%';

インデックス使われていると実行計画こんな感じになる

image.png

類似検索機能(多分英語のみ)

こうやって検索すると類似のものを抽出してくれる。でも日本語はうまく動かなさそう

select * from sample_data2 where textdata1 =% 'Boss cool' or textdata2 =% 'siulary';

結論

pg_bigram使うと、大きなテーブルであっても高速にlike検索ができるため素晴らしいと思います。

ただし、インデックスを作ることにより、データサイズが倍程度になります。五十万件程度のデータであれば、インデックス使わなくても早いので、データが百万件以上になるようなテーブルに絞って適用するのが良さそうです。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2