※本稿で扱うデータや検索ロジックの例は、クライアント事例を一般化したものです。
説明のわかりやすさを優先し、Airbnb公開データを用いて再現しています。実際の顧客データやシステム構成とは異なります。
まとめ
| 観点 | 内容 |
|---|---|
| 課題 | 完全一致検索により、条件が少しずれただけで「0件」になりやすく、ユーザーが再検索を繰り返して離脱につながっていた。 |
| 対応 | 検索候補に点数をつけて、より「条件に近いもの」から順に表示する仕組みを導入。距離や一致度が少し違っても、なだらかに点数が下がるようなスコア調整(function_score + gauss)を適用。 |
| 運用 | 緩和ステップ/重み/閾値をダッシュボードで継続モニタリングし、A/Bテストによる副作用の検証と調整を継続。 |
| 結果・成果 | 「0件検索」を大幅に減らし、再検索回数の減少と滞在時間の向上を達成。 代替提案の受容率向上により、検索体験が分断されずスムーズに。 |
| 効果 | 手応えのある検索体験が実現し、在庫消化率・予約率の改善に寄与。今後のML化 / ベクトル検索への拡張余地も確保。 |
背景
事業文脈
宿泊施設の予約検索では、期間・人数・価格帯・位置情報・設備・即時予約可など、多くの条件が設定できる。
しかし、条件が厳しい場合に「該当 0 件」となるケースが一定数あり、ユーザーは細かく条件を変えながら再検索を繰り返していた。結果として、離脱率が高くなっていた。
現状の課題
- 検索条件が 完全一致型 で、少し条件を外すだけで 0 件になりやすい。
- 「条件を少し緩めた候補」や「代替提案(近隣日程・周辺エリア)」を自然に提示できず、体験が分断されていた。
ビジネス・非機能要件
- ゼロ件検索の発生を継続的に減らし、検索結果の「手応え」を高める。
- ノード負荷やコストを抑えつつ、正確な価格・在庫情報を維持する。
- 検索改善が離脱や通報などの副作用を生まないか、定期的に検証する。
対応方針
基本方針
ゼロ件を減らしつつ、ユーザーの意図を外さない。
そのために、検索条件を段階的にゆるめていく多層ロジックと、近さを保つスコアリング、理由の可視化を組み合わせる。
ロジック設計
-
多段階の緩和ステップ
完全一致 → 日付の微緩和 → エリア拡大 → 価格帯拡大 → 代替(人気・評価など)。
上位で結果が出なければ次段へ進め、各ステップで「何をどれだけ緩めたか」をメタデータとして保持する。 -
近さを保つスコアリング
Elasticsearch のscript_scoreとgaussを用い、距離・価格差・希望日に対する近接度などを重み付け。
「条件に近い候補」から自然に並ぶよう順位付けする。 -
理由の可視化(説明可能性)
UI 上で「日付を±1日緩和」「価格を+10%拡大」など、緩和の内容を明示。
ユーザー自身がトグルやスライダーで緩和幅を調整できるようにする。 -
性能と運用を両立
緩和ステップはクエリを分離しつつキャッシュ再利用を設計。
地図移動や絞り込み変更によるバーストにも耐えられるよう、クエリパターンと ES 負荷を継続的に最適化する。
検証フェーズ
検証の目的
検索ロジックの変更によって「ゼロ件を減らしつつ、ユーザーの意図に沿った結果が提示できているか」を確認する。
在庫や価格の正確性を前提としたうえで、UX・性能・副作用 の3点を評価対象とした。
検証観点
-
有効性
各緩和ステップがどれだけ「ゼロ件検索」を回避できたかを測定。
緩和タイプ別ヒット率と代替案クリック率をトラッキングし、ユーザーが代替提案を自然に受け入れているかを分析した。 -
性能
検索頻度の高い操作(地図の移動や拡大縮小、日付変更など)の応答時間を計測。
クエリ構造・キャッシュヒット率・Elasticsearch ノード負荷を可視化し、UXを損なわない範囲でレスポンスを安定化させた。 -
副作用
緩和のしすぎで「期待外れな結果」が増えていないかを監視。
離脱率・問い合わせ件数などの指標をA/Bテストで比較し、緩和幅やスコア設計のバランスを調整した。
改善サイクル
- ダッシュボードで主要指標(ゼロ件率・クリック率・遅延・負荷)を常時モニタリング。
- 月次で緩和ロジックとスコア関数を見直し、閾値やウェイトを微調整。
- 検証結果を次回リリース計画に反映し、検索体験の連続改善を継続的に行った。
結果・成果
定量的成果
- ゼロ件検索率を大幅に削減し、検索結果が常に何らかの候補を返せる状態を実現。
- 緩和ステップの導入により、再検索回数が減少し、1セッションあたりの滞在時間が向上。
- 緩和タイプ別ヒット率の分布から、日付・エリアの微調整が特に有効であることを確認。
- 検索結果ページの応答速度も安定し、負荷増加に対してもスループットを維持。
定性的成果
- 「少し条件を変えるとすぐ 0 件になる」という不満が解消され、検索体験の連続性が向上。
- 条件を緩めた理由を明示することで、ユーザーの納得感と信頼感を確保。
- 検索の手応えが増した結果、ブックマークや再訪問などのアクション率が向上。
- ビジネス側でも、在庫消化率・予約率の改善に波及し、検索導線の価値が高まった。
内省・学び
- ゼロ件を単純に減らすのではなく、「どの緩和が受け入れられるか」をデータで測る重要性を確認。
- スコアリング設計とUX表現(理由の見せ方)が表裏一体であることを再認識。
工夫した点・苦労した点
性能と柔軟性の両立(バックエンド × フロントエンド協調)
緩和クエリを段階的に実行する構成は柔軟だが、処理数が増える分だけ ES ノード負荷やネットワーク往復が増えやすい。
バックエンド最適化(クエリ再利用・短期キャッシュ)に加え、フロントエンド側でも次の工夫で無駄なリクエストを抑制した。
-
デバウンス/スロットリング
- 「地図の移動や拡大縮小」「スライダー調整」などの連続操作は、短い遅延でデバウンスし、ドラッグ中はスロットリングで送信頻度を制御。
- 中間状態の連投を避け、ユーザーが意図した操作の“落ち着き”を待ってから検索を投げる。
-
重複クエリの折りたたみ(コアレス)
- 同一の正規化クエリ(例:丸めたビューポート、ソート/ページング除く主要条件)には結果を再利用。
- ビューポートや条件をグリッド/バケット化して、ほぼ同じ問い合わせをまとめる。
副作用の把握と調整
緩和を強めた結果として離脱や通報が増えるケースも初期には見られた。
A/B テストの結果を定常的に分析し、「どこまで緩めると不満が出るか」を段階的に計測しながら設計を更新した。
データを見ながらチーム全体で意思決定する体制を整えたことが、長期的な安定改善につながった。
参考
Elasticsearchの検索クエリ
gauss- 中心から離れるほどなめらかに減点。距離・日付・数値の“近さ”に最適。
script_score- ビジネスルールを数式化(例:目標価格からの差、レビュー数/評価の加点、滞在可能人数の減点)。
function_score- クエリでヒットしたドキュメントに「追加スコア」を与える枠。複数関数を合成して“総合点”を作れる。
weightとscore_modeで、“距離×価格×レビュー”のバランスを取る。
例
{
"function_score": {
"query": { "bool": { "filter": [ /* 基本条件 */ ] } },
"functions": [
{
"gauss": {
"location": {
"origin": { "lat": 35.7058, "lon": 139.7514 },
"scale": "1500m",
"offset": "200m",
"decay": 0.7
}
},
"weight": 2.0
},
{
"script_score": {
"script": {
"source": """
double p = (doc.containsKey('price') && !doc['price'].empty) ? doc['price'].value : 0;
double diff = Math.abs(p - params.target);
// ±1万円ごとに 0.2 減点(調整可)
return Math.max(0, 1.0 - (diff / 10000.0) * 0.2);
""",
"params": { "target": 15000 }
}
},
"weight": 1.0
},
{
"script_score": {
"script": {
"source": """
// レビュー信頼度:件数と評価を合わせて0〜1へ
double n = (doc.containsKey('number_of_reviews') && !doc['number_of_reviews'].empty) ? doc['number_of_reviews'].value : 0;
double r = (doc.containsKey('review_scores_rating') && !doc['review_scores_rating'].empty) ? doc['review_scores_rating'].value : 0;
// 件数は100件で頭打ち、評価は100点満点を想定
double nScore = Math.min(n, 100) / 100.0;
double rScore = r / 100.0;
return 0.5 * nScore + 0.5 * rScore; // 係数は調整可
"""
}
},
"weight": 0.8
}
],
"score_mode": "sum",
"boost_mode": "sum"
}
}
weight:各要素の比重(例:距離2.0、価格1.0、レビュー0.8)。score_mode:関数同士の合成(sumは直感的、multiplyは一要素が低いと全体が落ちる)。boost_mode:base_score(テキスト一致)との合成。テキストを重視したければmultiplyやsum+boostを検討。
パフォーマンス改善
データベースや配信経路の最適化によって、システム全体の応答速度と安定性を向上。
開発生産性向上
品質保証の自動化とビルドパイプラインの改善により、継続的な開発速度を維持。
プロダクト改善
検索体験や予約システムなど、ユーザー視点での操作性と信頼性を向上。