やあ。今日もデータベースと格闘してるかい?
PostgreSQLで全文検索を実装するとき、「検索結果のリストで、該当箇所をチラ見せしたい」って要望、必ずと言っていいほど出てくるよね。そんなとき、自前で文字列操作をして `substring` を切り出したり、フロントエンド側で頑張ってハイライト処理をしたり……なんて遠回りをしていないかな?
実はPostgreSQLには、まさにそのための便利な武器があるんだ。それが `ts_headline` 関数。
今回は、この「検索結果のプレビュー職人」とも言える関数の使い方と、現場でハマりがちなポイントを共有するよ。
—
なぜ「ts_headline」が必要なのか
全文検索エンジンを入れるほどじゃないけど、`tsvector` と `tsquery` で頑張って検索機能を作ったとき、検索結果のタイトルだけじゃユーザーはどこに何があるか分からないよね。
`ts_headline` を使えば、「検索語句がヒットした周辺の文脈を抽出し、さらにヒットした単語を任意のタグ(`` など)で囲んでくれる」という、検索体験を爆上げする機能をクエリ一発で実装できるんだ。
基本的な使い方:まずは動かしてみる
使い方はシンプル。第一引数に対象テキスト、第二引数に検索クエリを渡すだけだ。
SELECT ts_headline(
‘PostgreSQLは非常に強力なオブジェクト関係データベース管理システムです。’,
to_tsquery(‘english’, ‘PostgreSQL’)
);
これだけで、`PostgreSQLは非常に強力な…` という結果が返ってくる。簡単だろう?
実務で意識すべき「設定オプション」
デフォルトのままでも動くけど、実務だと「抜粋する文字数が短すぎる」「もっと長い文章から抽出したい」といった調整が必要になるはずだ。ここで第三引数の `options` が活躍する。
よく使う設定をまとめておくよ。
SELECT ts_headline(
body_text,
to_tsquery(‘simple’, ‘検索ワード’),
‘StartSel=, StopSel=, MaxWords=35, MinWords=15, HighlightAll=FALSE’
);
- StartSel / StopSel: ハイライトするタグを指定できる。フロントエンドに合わせて `` や `` に変えるのが一般的だね。
- MaxWords: 抜粋する最大単語数。ここをケチると文脈が途切れるし、多すぎると検索結果の画面が重くなる。30〜50くらいがバランスいいよ。
- MinWords: 最小単語数。短すぎると意味が通じないから、最低限の文脈を確保するために使う。
- HighlightAll: `TRUE` にすると、ヒットした箇所をすべてハイライトする。デフォルトは `FALSE` で、最初の数箇所だけになるよ。
現場で気をつけてほしい「落とし穴」
ここまで読むと「最強じゃん!」と思うかもしれないけど、エンジニアとしていくつか注意してほしい点がある。
1. パフォーマンスへの影響
`ts_headline` は、実行のたびにテキストのパースと検索語句のマッチングを行う。データ量が多いテーブルで、検索結果一覧(リスト)に対して毎回これを適用すると、CPUをガッツリ食う可能性がある。
「リスト画面では `ts_headline` を使わず、詳細画面でだけ使う」とか、「検索結果の件数が多すぎる場合は計算を制限する」といった設計思想を持っておくのが賢いね。
2. 言語設定の罠
`to_tsquery` に渡す言語設定(辞書)が、カラムの検索に使ったものとズレていると、当然ながらうまくヒットしない。特に日本語の場合、`pg_bigm` や `mecab` との組み合わせでインデックスを貼っているなら、そこらへんの整合性には細心の注意を払おう。
3. 「どこから抽出するか」の不確実性
`ts_headline` は、あくまで「検索語句が含まれる場所」を優先的に探す。もし検索語句が文書のあちこちにあると、どれが選ばれるか制御しにくいこともある。プレビューとして見栄えが悪い場合は、そもそも保存しているデータそのものの構成を見直す勇気も必要だよ。
—
まとめ:UXは「一手間」で作れる
PostgreSQLの標準機能だけで、ここまでリッチな検索結果表示ができる。わざわざアプリケーション層で複雑なロジックを書く必要はないんだ。
「検索機能を作ったけど、結果画面が寂しいな」と思ったら、まずは `ts_headline` を試してみてくれ。ユーザーはきっと、「あ、この検索結果には自分の欲しい情報が含まれてるな」と直感的に気づいてくれるはずだ。
データベースは、ただデータを貯めるだけの箱じゃない。こうやってユーザーに情報を届けるための「知的なインターフェース」にもなるんだ。
また何か詰まったら、いつでも聞いてくれよな。ハッピー・クエリイング!
コメント