グラフとチャートが表示されたデスクの2台のモニター
技術解説

検索改善でPostgreSQL負荷が急増する落とし穴とSLO設計の対策

目次を見る

社内検索や採用サイトの検索機能を、キーワード一致からハイブリッド検索(単語一致と意味的な類似度検索を組み合わせる方式)に置き換えようとしているインフラ担当者に向けた内容です。検索精度の改善は歓迎される一方、既存のPostgreSQLインスタンスにレイテンシとコストの新しい負荷をもたらします。設計段階でSLO(サービスレベル目標。可用性やレイテンシの許容範囲を数値で定義したもの)を見落とすと、リリース後に本番障害として跳ね返ってくる典型的な落とし穴を整理しました。

何が起きるか

ある採用サイトの事例では、キーワード一致検索を廃止し、埋め込みベクトル(文章の意味を数値の配列に変換したデータ)による意味検索を導入しました。導入初期のNDCG@10(検索結果の並び順の良さを測る指標。10件中で理想順位にどれだけ近いかを示す)は0.9944と高い数値でした。

ところがprecision@5(上位5件のうち実際に関連する件数の割合)は意味検索クエリに限ると55%にとどまりました。半分近くが弱い関連度の結果だったということです。

この状態を放置すると、検索APIのレイテンシが不安定になり、DBサーバーへの負荷が読めなくなります。埋め込みベクトルとの類似度計算はキーワードのLIKE検索より重い処理だからです。SREの視点で見ると、これは機能追加ではなくアーキテクチャ変更であり、可用性リスクの再評価が必要な変更です。

なぜ起きるか

原因は段階的に分解すると見えてきます。

第一に、既存のキーワード一致は文字列の部分一致で判定していました。「kubernets」は「kubernetes」という文字列を含まないため、typo(打ち間違い)に弱いという弱点があります。逆に「Java」と「JavaScript」は部分一致してしまい、精度が粗いという特性もありました。この単純さゆえに、負荷特性も単純で予測しやすいものでした。

第二に、ハイブリッド検索は「語彙的な検索」と「意味的な検索」を並行して実行し、結果を統合する設計です。採用サイトの事例では、既存のNext.jsとPostgreSQL、そしてOpenAIの埋め込みAPIを組み合わせる構成を選びました。専用の検索エンジンやマネージドサービスを避け、PostgreSQL単体で完結させる判断をしています。

この判断自体は妥当ですが、代償としてPostgreSQLに新しい役割が増えます。従来はジョブデータの保存とフィルタリングだけを担っていたのが、ベクトル類似度計算という計算負荷の高い処理も引き受けることになるからです。

第三に、precision@5が55%という数字が示すのは、「関連度の低い結果をどこまで許容するか」という設計判断が最初から曖昧だったことです。この閾値を決めずに本番投入すると、外部APIのレイテンシ悪化や埋め込み生成の失敗時に、フォールバック(代替処理)の挙動が定義されないまま障害につながります。

原因を一言でまとめると、検索精度の改善プロジェクトが、可用性設計の議論を経ずに進んでしまったことです。

自分のプロジェクトが該当するか確認する方法

以下の観点で、現在の検索基盤が同じ落とし穴に近づいていないか確認できます。

  • PostgreSQLに「pgvector」拡張を導入している場合、pg_extensionテーブルでバージョンと有効化状況を確認する
  • 埋め込み生成をリクエストごとに外部API呼び出しで行っているか、コード中のembeddings.create呼び出し箇所を洗い出す
  • 検索クエリのレイテンシをp50/p95/p99で計測しているか、既存のオブザーバビリティツール(DatadogやGrafana等)のダッシュボード設定を確認する
  • 検索APIにタイムアウトとフォールバック処理が実装されているか、try/catchやPromise.raceの有無をコードレビューで確認する
  • ハイブリッド検索導入前後でPostgreSQLのCPU使用率とコネクション数の変化を、pg_stat_activityビューやRDS/Cloud SQLのメトリクスで比較する

これらのどれか1つでも「未計測」「未実装」であれば、本番導入前に対策を検討する余地があります。

対策の手順

落とし穴を避けるための具体的な手順です。

1. SLOを検索機能単位で定義する

検索APIのレイテンシSLOを、既存のAPI全体のSLOとは別に切り出します。たとえば「意味検索を含むクエリはp95で800ms以内」のように、処理経路ごとに数値目標を分けます。ハイブリッド検索は語彙検索単体より重いため、同じSLOを流用すると必ず超過します。

2. 検索経路を分離し、段階的に切り替える

採用サイトの事例では、lexical-preview(語彙検索のみの軽量版)、lexical-only、hybridという3つの経路を用意していました。これは単なる機能設計ではなく、障害時の縮退運転(システムの一部機能を落として全体を維持する運用)の選択肢を増やす設計でもあります。

Terraformなどのインフラコード管理ツールを使っている場合は、フィーチャーフラグやルーティング設定をコード化し、経路の切り替えをデプロイと切り離せるようにしておくと安全です。

# 例: 環境変数でハイブリッド検索の有効/無効を切り替える
export SEARCH_MODE=lexical_only  # 障害時はここをlexical_onlyに戻す

3. 外部API依存のタイムアウトを明示的に設定する

埋め込み生成をOpenAI等の外部APIに依存している場合、そのAPIの遅延や障害がそのまま検索機能全体に波及します。タイムアウト値を明示し、超過時は語彙検索のみの結果を返すフォールバックを実装します。

4. precision/recallの閾値を運用の合格基準に組み込む

precision@5やNDCG@10のような指標は、リリース判定の一部として継続的に計測します。CI/CDパイプラインにオフライン評価用のテストデータセットを組み込み、デプロイ前に指標が閾値を下回っていないか確認するのが望ましい形です。

5. コストとレイテンシのトレードオフを可視化する

pgvectorのインデックス(IVFFlatやHNSW)を使う場合、インデックスの種類によって検索速度とメモリ使用量のバランスが変わります。オブザーバビリティツールでクエリ実行計画を定期的に確認し、インデックスが実際に使われているかを検証します。

検索精度の改善は機能要件だけでなく、レイテンシSLOとフォールバック設計をセットで扱う可用性設計の課題です。

導入前に確認すること

検索基盤の刷新を検討する際は、次の3点を最低限確認しておくと安心です。

  • 経路ごとのレイテンシSLOを定義し、既存のダッシュボードで計測できる状態にあるか
  • 外部API依存箇所にタイムアウトとフォールバックが実装されているか
  • precision/recallの評価をCI/CDに組み込み、リリース判定の基準にしているか

これらが未整備であれば、まずはpg_stat_activityやAPMツールでの現状計測から始めるのが現実的な一歩になります。数値がないまま設計を進めると、精度の改善が可用性の低下と引き換えになりかねません。

参考

Why we built recall-first search on PostgreSQL

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。