【実務・中級編】 RUMインデックス拡張 – PostgreSQL

全文検索の「最後の砦」:PostgreSQLのRUMインデックスで検索速度を極限まで引き出す

やあ。最近、PostgreSQLで複雑な全文検索を実装していて、「GINインデックスだとランキング計算が重い……」なんて壁にぶつかっていないかな?

PostgreSQLの標準的な全文検索(tsvector + GIN)は確かに強力だ。でも、検索結果の並び替え(ランキング)で `ts_rank` を使い始めると、途端にパフォーマンスが頭打ちになることがあるよね。

そんな時、僕が「最終兵器」として取り出すのが、この RUMインデックス だ。今日は、なぜこれが現場で重宝されるのか、実務的な視点で深掘りしていこう。

—

そもそも、なぜGINじゃダメなのか?

まず、GINインデックスが何をしているかおさらいしよう。GINは「単語がどの行にあるか」を記録する転置インデックスだ。検索語が含まれる行を探すのは爆速だけど、「どの単語がどの位置にあるか」や「いつ作成されたか」といったメタ情報は持っていない。

だから、ランキング計算をするためには、どうしても「インデックスで候補を絞り込む」→「テーブル本体からデータを読み出す」→「メモリ上で計算する」というステップが必要になる。データ量が数百万行を超えてくると、この「テーブルアクセス」と「計算コスト」がボトルネックになるんだよね。

RUMインデックスの何が凄いの?

RUMはGINの拡張版だ。最大の特徴は、インデックスの中に「追加情報」を詰め込めること。

具体的には、単語の位置情報(Lexeme Position)や、タイムスタンプなどのカラムをインデックス構造内に保持できる。これにより、クエリ実行時にわざわざテーブルまで行かなくても、インデックス内だけでランキング計算を完結させられるんだ。

「インデックスを読み込むだけで検索結果がほぼ完成している」状態。これがRUMの正体だよ。

—

実践:RUMインデックスを導入してみる

まずは拡張機能を有効にするところから。PostgreSQLのcontribに入っているから簡単だ。

CREATE EXTENSION rum;

例えば、「ブログ記事の全文検索を、公開日時が新しい順にランキングしたい」というケースを考えてみよう。

1. インデックスの作成

通常のGINなら `gin` と書くところを `rum` に変えるだけだ。重要なのは `rum_ts_vector_addon_ops` を指定し、ランキングに使いたいカラムを `rum_ts_order_addon_ops` で追加すること。

CREATE INDEX idx_rum_posts_body ON posts
USING rum (
to_tsvector(‘japanese’, body) rum_ts_vector_addon_ops,
created_at
);

2. 検索クエリの書き方

ここがポイントだ。RUM専用の関数である `rum_ts_rank` を使う。

SELECT id, title
FROM posts
WHERE to_tsvector(‘japanese’, body) @@ to_tsquery(‘japanese’, ‘データベース & パフォーマンス’)
ORDER BY rum_ts_rank(
to_tsvector(‘japanese’, body),
to_tsquery(‘japanese’, ‘データベース & パフォーマンス’)
) DESC
LIMIT 10;

これだけで、内部的にはインデックスの中にある情報だけを使ってスコアリングが行われる。数万件、数十万件のオーダーで検索結果のレスポンスが劇的に改善するはずだよ。

—

現場で使う時の「注意点」

ここまで聞くと魔法のように聞こえるかもしれないけれど、エンジニアとして注意すべき点もいくつかある。

  • 書き込み速度は落ちる: インデックスに付加情報をたくさん詰め込む分、`INSERT` や `UPDATE` のコストはGINよりも重くなる。頻繁に更新されるカラムに貼るのは避けたほうがいい。
  • ストレージ消費量: 当然だけど、インデックスサイズは大きくなる。ディスク容量には少し余裕を見ておこう。
  • メンテナンス性: RUMは標準機能ではないので、RDSなどのマネージドサービスを使う場合は、その環境がRUMをサポートしているか必ず確認すること。(AWS RDSなら最近は標準で入っていることが多いけどね)

まとめ:いつ使うべきか?

僕がRUMを検討するのは、「検索のレスポンスタイムがUXに直結するアプリケーション」で、かつ「テーブルスキャンが発生してランキング計算に時間がかかっている」ときだけだ。

まずは `EXPLAIN ANALYZE` を叩いて、どこで時間がかかっているかを見極めてほしい。もし「Sort」や「Heap Fetch」が重い原因なら、RUMは君のプロジェクトを救う強力な武器になるはずだ。

データベース設計は、理論を知っているだけじゃなく「どのトレードオフを選ぶか」が腕の見せ所だよ。ぜひ試してみて、結果を教えてほしい。

それじゃ、また現場で!

コメント

タイトルとURLをコピーしました