検索体験を改善し「0件」を減らす(クエリ緩和+ランキング調整)

  • elasticsearch
    elasticsearch
2023/11/21に公開

まとめ

観点 内容
課題 完全一致検索により、条件が少しずれただけで「0件」になりやすく、ユーザーが再検索を繰り返して離脱につながっていた。
対応 検索条件を段階的に緩める多層ロジックを導入し、近さに応じてfunction_score / gauss decay でスコアリング。
緩和内容をメタデータとして保持し、UIに理由を明示。
運用 緩和ステップ/重み/閾値をダッシュボードで継続モニタリングし、A/Bテストによる副作用の検証と調整を継続。
結果・成果 「0件検索」を大幅に減らし、再検索回数の減少と滞在時間の向上を達成。
代替提案の受容率向上により、検索体験が分断されずスムーズに。
効果 手応えのある検索体験が実現し、在庫消化率・予約率の改善に寄与。今後のML化 / ベクトル検索への拡張余地も確保。

背景

事業文脈

宿泊施設の予約検索では、期間・人数・価格帯・位置情報・設備・即時予約可など、多くの条件が設定できる。
しかし、条件が厳しい場合に「該当 0 件」となるケースが一定数あり、ユーザーは細かく条件を変えながら再検索を繰り返していた。結果として、離脱率が高くなっていた。

現状の課題

  • 検索条件が 完全一致型 で、少し条件を外すだけで 0 件になりやすい。
  • 「条件を少し緩めた候補」や「代替提案(近隣日程・周辺エリア)」を自然に提示できず、体験が分断されていた。

ビジネス・非機能要件

  • ゼロ件検索の発生を継続的に減らし、検索結果の「手応え」を高める。
  • ノード負荷やコストを抑えつつ、正確な価格・在庫情報を維持する。
  • 検索改善が離脱や通報などの副作用を生まないか、定期的に検証する。

対応方針

基本方針

ゼロ件を減らしつつ、ユーザーの意図を外さない。
そのために、検索条件を段階的にゆるめていく多層ロジックと、近さを保つスコアリング、理由の可視化を組み合わせる。

ロジック設計

  1. 多段階の緩和ステップ
    完全一致 → 日付の微緩和 → エリア拡大 → 価格帯拡大 → 代替(人気・評価など)。
    上位で結果が出なければ次段へ進め、各ステップで「何をどれだけ緩めたか」をメタデータとして保持する。

  2. 近さを保つスコアリング
    Elasticsearch の function_scoregauss decay を用い、距離・価格差・希望日に対する近接度などを重み付け。
    「条件に近い候補」から自然に並ぶよう順位付けする。

  3. 理由の可視化(説明可能性)
    UI 上で「日付を±1日緩和」「価格を+10%拡大」など、緩和の内容を明示。
    ユーザー自身がトグルやスライダーで緩和幅を調整できるようにする。

  4. 性能と運用を両立
    緩和ステップはクエリを分離しつつキャッシュ再利用を設計。
    地図移動や絞り込み変更によるバーストにも耐えられるよう、クエリパターンと ES 負荷を継続的に最適化する。

検証フェーズ

検証の目的

検索ロジックの変更によって「ゼロ件を減らしつつ、ユーザーの意図に沿った結果が提示できているか」を確認する。
在庫や価格の正確性を前提としたうえで、UX・性能・副作用 の3点を評価対象とした。

検証観点

  1. 有効性(Effectiveness)
    各緩和ステップがどれだけ「ゼロ件検索」を回避できたかを測定。
    緩和タイプ別ヒット率と代替案クリック率をトラッキングし、
    ユーザーが代替提案を自然に受け入れているかを分析した。

  2. 性能(Performance)
    検索頻度の高い操作(地図の移動や拡大縮小、日付変更など)の応答時間を計測。
    クエリ構造・キャッシュヒット率・Elasticsearch ノード負荷を可視化し、
    UXを損なわない範囲でレスポンスを安定化させた。

  3. 副作用(Side Effects)
    緩和のしすぎで「期待外れな結果」が増えていないかを監視。
    離脱率・問い合わせ件数などの指標をA/Bテストで比較し、
    緩和幅やスコア設計のバランスを調整した。

改善サイクル

  • ダッシュボードで主要指標(ゼロ件率・クリック率・遅延・負荷)を常時モニタリング。
  • 月次で緩和ロジックとスコア関数を見直し、閾値やウェイトを微調整。
  • 検証結果を次回リリース計画に反映し、検索体験の連続改善を継続的に行った。

結果・成果

定量的成果

  • ゼロ件検索率を大幅に削減し、検索結果が常に何らかの候補を返せる状態を実現。
  • 緩和ステップの導入により、再検索回数が減少し、1セッションあたりの滞在時間が向上。
  • 緩和タイプ別ヒット率の分布から、日付・エリアの微調整が特に有効であることを確認。
  • 検索結果ページの応答速度も安定し、負荷増加に対してもスループットを維持。

定性的成果

  • 「少し条件を変えるとすぐ 0 件になる」という不満が解消され、検索体験の連続性が向上。
  • 条件を緩めた理由を明示することで、ユーザーの納得感と信頼感を確保。
  • 検索の手応えが増した結果、ブックマークや再訪問などのアクション率が向上。
  • ビジネス側でも、在庫消化率・予約率の改善に波及し、検索導線の価値が高まった。

内省・学び

  • ゼロ件を単純に減らすのではなく、「どの緩和が受け入れられるか」をデータで測る重要性を確認。
  • スコアリング設計とUX表現(理由の見せ方)が表裏一体であることを再認識。
  • 緩和ロジックを段階化することで、今後の機械学習モデルやベクトル検索への移行にも拡張性を残せた。

工夫した点・苦労した点

性能と柔軟性の両立(バックエンド × フロントエンド協調)

緩和クエリを段階的に実行する構成は柔軟だが、処理数が増える分だけ ES ノード負荷やネットワーク往復が増えやすい。
バックエンド最適化(クエリ再利用・短期キャッシュ)に加え、フロントエンド側でも次の工夫で無駄なリクエストを抑制した。

  • デバウンス/スロットリング

    • 「地図の移動や拡大縮小」「スライダー調整」などの連続操作は、短い遅延でデバウンスし、ドラッグ中はスロットリングで送信頻度を制御。
    • 中間状態の連投を避け、ユーザーが意図した操作の“落ち着き”を待ってから検索を投げる。
  • 重複クエリの折りたたみ(コアレス)

    • 同一の正規化クエリ(例:丸めたビューポート、ソート/ページング除く主要条件)には結果を再利用。
    • ビューポートや条件をグリッド/バケット化して、ほぼ同じ問い合わせをまとめる。

副作用の把握と調整

緩和を強めた結果として離脱や通報が増えるケースも初期には見られた。
A/B テストの結果を定常的に分析し、
「どこまで緩めると不満が出るか」を段階的に計測しながら設計を更新した。
データを見ながらチーム全体で意思決定する体制を整えたことが、長期的な安定改善につながった。

参考

① Elasticsearch のインデックス例

実際に登録されている宿泊施設データの一例。
検索ではこれらの項目をもとに、日付・価格・距離・人気度などを複合的にスコアリングする。

{
  "listing_id": "listing_2031",
  "title": "河口湖畔の一軒家コテージ(最大4名・駐車場付き)",
  "price": 16800,
  "location": { "lat": 35.5172, "lon": 138.7576 },
  "availability": [
    { "date": "2025-10-23", "available": true },
    { "date": "2025-10-24", "available": true },
    { "date": "2025-10-25", "available": false }
  ],
  "amenities": ["Wi-Fi", "キッチン", "バーベキュー設備", "無料駐車場"],
  "rating": 4.8,
  "review_count": 126,
  "is_instant_bookable": true,
  "popularity_score": 0.92,
  "area_name": "山梨県・富士河口湖町",
  "updated_at": "2025-10-22T09:15:00Z"
}
  • availability で日単位の空室を表現し、日付検索と連動。
  • popularity_score はレビュー数や閲覧数をもとに定期更新。
  • 検索時には function_score で距離・価格差・人気度を総合スコア化して並び替える。

② ユーザー行動ログの記録形式例

検索体験を継続的に改善するための行動ログ。
検索条件の変更や緩和操作を時系列で追えるようにしている。

{
  "session_id": "abcd1234",
  "user_id": "u5678",
  "timestamp": "2025-10-23T12:34:56Z",
  "query": {
    "original": "河口湖 2名 10月23日〜25日",
    "relaxation_applied": ["date+1", "area+3km"],
    "hit_count": 24,
    "clicked_listing_id": "listing_2031",
    "click_rank": 2
  },
  "actions": [
    { "type": "click", "target": "listing_2031" },
    { "type": "map_move", "delta": "+3km" },
    { "type": "toggle_relaxation", "param": "price+10%" }
  ],
  "metrics": {
    "response_time_ms": 142,
    "is_zero_result": false
  }
}
  • relaxation_applied でどの緩和ステップが使われたかを記録。
  • actions により検索中のユーザー行動(クリック・地図操作・緩和操作)を追跡。
  • metrics はパフォーマンス計測を兼ね、改善効果を定量評価する基礎データとして活用。