本シリーズのパート1から5では、商品カタログへのクエリ実行前に、意図の分類、制約の適用、ポリシーの競合の解決、適切な検索戦略へのルーティングを行う、ガバナンスを備えた制御プレーンについて説明します。これまでに説明したすべてのメカニズムは、すべての購入者を同じように扱います。「chocolate」の検索では、購入者がビーガンであろうと、子供の誕生日用に購入している親であろうと、ハラールを遵守する消費者であろうと、同じ制御された結果セットが生成されます。
この記事では、アーキテクチャを変更することなく、ガバナンスを備えた制御プレーンを拡張する2つのパーソナライゼーションメカニズムを紹介します。両方のメカニズムは、パート1から5までのガバナンスレイヤーと乗算的に積み重なります。ポリシーは引き続き起動し、制約は引き続き適用され、競合は引き続き解決され、パーソナライゼーションシグナルは同じガバナンスされたクエリに統合されます。これにより、Elasticsearchが返す結果はすでにパーソナライズされていることが保証されます。
最初の仕組みは、個々の購入者が以前に購入した商品を優先的に販売促進するものです。2つ目は、購入者のプロフィールに基づいてコホート固有のポリシーを有効化します。これらは、パーソナライゼーションが検索の横にボルトで固定された別個のシステムでも、検索後の処理として適用されるものでもないことを示しています。それは、ポリシー駆動の制御プレーンの自然な延長です。
パーソナライゼーション技術に関する数学的な詳細については、ElasticsearchでMLの事後処理を行わずに検索をパーソナライズするとElasticsearchにおけるコホート対応ランキングをご覧ください。
購入履歴を使用してリピーターの検索結果を向上させる方法を実際にご覧になりたい場合は、ビデオ説明可能なパーソナライゼーション:購入履歴による検索結果の向上をご覧ください。
個人の購入履歴を活用したブースト
最もシンプルなパーソナライゼーションは、同時に最も効果的な方法の一つでもあります。それは、顧客が以前に商品を購入したことがある場合、その顧客が関連商品を検索した際にその商品を優先的に表示するというものです。特定のブランドのチョコレートチップクッキーを定期的に購入する購入者が「クッキー」と検索した際、そのクッキーが上位に表示されるべきです。これは、モデルが好みを予測したからではなく、直接的な行動証拠が存在するからです。
プログラム概要
ユーザー識別子を含む検索リクエスト(オープンセッションを持つユーザーの場合など)では、制御プレーンはスレッドプールを使用して2つのElasticsearchクエリを並行して実行します。
- ポリシーインデックスに対するパーコレータークエリ(パート3およびパート4で説明したガバナンスルックアップと同じもの)。
user_purchasesインデックスに対する購入履歴クエリは、term(user_id)によって特定のユーザーにフィルタリングされ、そのユーザーの商品タイトルに現在の検索文字列をクエリします。
これらは並行して実行されるため(どちらも他方を待つことはない)、パーソナライゼーションの検索によってガバナンスパイプラインに意味のある遅延が発生することはありません。
購入履歴のクエリは、現在の検索文字列を保存されている商品タイトルと照合する際に、Elasticsearchのテキスト分析(ステミング、トークン化)を使用します。これはつまり、「クッキー」という検索語は、厳密な文字列一致を必要とせず、標準的なテキスト分析によって過去に購入した「ブラウニークッキー」と一致するということです。
ブーストの重み付けの計算
すべての過去の購入が同じように評価されるわけではありません。この重み付けは、購入者がその商品を購入した頻度と、最近購入した頻度という2つの直感的な要素を考慮したものです。先週15回購入された商品は、半年前に1回購入された商品よりもはるかに強いシグナルです。重み付けは、頻度に対して対数スケーリング(単一の頻繁に購入される商品が他のすべてを圧倒しないように)と、最近性に対して指数減衰(古い購入が時間とともに自然に薄れていくように)を使用します。
ブースト式の数学的な詳細については、ElasticsearchでMLの事後処理を行わずに検索をパーソナライズするをご覧ください。
これがクエリとなる方法
購入履歴のブーストは、クエリの最外レイヤーのスコアリングレイヤーとして構成され、パート3およびパート4のガバナンスポリシーフィルターとブースト、さらにビジネスシグナルのブースト(マージンや人気など)(パート7で詳しく説明します)を含みます。これは、ガバナンスポリシーによって削除された商品が、購入履歴のブースト効果によって再び表示されることはないことを意味します。ガバナンスは結果セットを制御し、パーソナライゼーションはその中の順序を調整します。購入履歴のない商品はペナルティを受けません。それらの商品のランキングは維持されますが、他の条件がすべて同じであれば、関連する購入履歴を持つ商品がそれらよりも上位にランク付けされます。

検索のたびにElasticsearchにクエリを実行する必要があるのはなぜですか?
購入履歴は、アプリケーションレイヤーにキャッシュされるのではなく、検索のたびにElasticsearchからクエリされます。これは意図的な設計上の選択です。クエリがElasticsearchのテキスト分析パイプラインを使用して商品タイトルと照合されるため、システムは商品検索自体を強化するステミング、トークン化、言語処理の恩恵を受けます。キャッシュされたメモリ内ルックアップは、その分析を再実装するか、より粗雑なマッチングを受け入れる必要があります。
この注文がなぜ重要なのかを理解するには、以前にオレンジジュースを購入した購入者が、今は「オレンジ」を検索しているとします。購入履歴クエリは、テキスト分析によって「オレンジジュース」という検索語と「オレンジ」を照合し、その商品のブーストを計算します。しかし、ガバナンスレイヤーはすでに「オレンジ」を農産物カテゴリーに限定しており、オレンジジュースは完全に除外しています。オレンジジュースの購入履歴ブーストはクエリに存在しますが、作用する対象となるガバナンスされた結果セットに一致するドキュメントがないため、効果がありません。購入者には、関連性とパーソナライズに基づいてランク付けされた果物のオレンジを目にします。ガバナンスのガードレールが維持されています。
パフォーマンスコストは最小限です。購入履歴インデックスは小さく(ユーザーの購入履歴は通常数十から数百のドキュメントであり、何百万というものではありません)、クエリはパーコレータールックアップと並行して実行されるため、クリティカルパスを延長しません。
ユーザー履歴なしの「spring water」のクエリ例
ログインしていないユーザーや「spring water」を購入したことがないユーザーが検索すると、次のような結果が表示されることがあります。

ユーザーの購入履歴の例
一方、Carolというユーザーのショッピング履歴には、以下の商品が含まれています。

上記の購入履歴で「spring water」を検索する例
Carolが「spring water」を検索すると、過去に購入した内容を反映したパーソナライズされた結果が表示されます。上記の購入履歴を見ると、彼女は「Carbonated Spring Water」(緑色のボトル)を約40回購入しており、最近では2日前に購入しています。彼女が「spring water」を検索した場合、彼女がそれを好んでいることがわかっているので、その商品が上位に表示されるようになります。パーソナライズされていない検索結果では、Rubiconのミネラルウォーターが最初に表示されたことに注目してください。

コホート認識ポリシーの有効化
個別の購入履歴は、確立された行動を持つリピーターにとって有効です。しかし、多くの購入者は新規顧客であったり、匿名であったり、普段とは異なるパターンで商品を探していたりします。こうした購入者にとって、コホートメンバーシップは、購入者の過去の行動ではなく、購入者自身がどのような人物であるかに基づいた、従来とは異なる種類のパーソナライゼーションを提供します。
「チョコレート」を検索するビーガンの購入者には、ビーガンチョコレートが上位に表示されるべきです。「スナック」を探すハラール遵守の購入者には、ハラール認証の選択肢が目立つように表示されるべきです。健康志向の購入者が「ヨーグルト」を探す際には、プロバイオティクスの選択肢が優先的に表示されるべきです。
商品タグではなくポリシーとしてのコホート
商品にはすでに通常の属性があり、dietary_restrictions: ["vegan"]やdietary_restrictions: ["halal"]などのフィールドが含まれます。問題は、購買者のコホートを商品の属性に関連付けるロジックがどこに存在するかという点です。
単純な方法は、アプリケーションレイヤーまたは検索テンプレートでそのマッピングをハードコードすることです。ユーザーがビーガンの場合は、dietary_restrictions: "vegan"にブーストを追加します。しかし、これはパート1で説明されたアプリケーションレイヤーのスパゲッティと同じであり、同じ運用上の摩擦を生み出します。新しいコホートの追加やコホートの意味の変更にはコードの変更が必要です。
ガバナンスを備えた制御プレーンは、代わりにコホートロジックをポリシーエンジンに保持します。コホートポリシーは、購入者のコホートメンバーシップ(例:「ビーガン」)と商品属性(例:dietary_restrictions: “vegan”)の2つを橋渡しします。このポリシーでは、次のような関連性を定義します。ビーガンの購入者が検索したとき、 dietary_restrictionsに「ビーガン」が含まれる商品をブーストします。

コホートロジックはアプリケーションコードではなくポリシーエンジンに存在するため、次のようになります。
- 新しいコホートは新しいポリシーを作成することで追加できます。プロダクトの再インデックスは不要です。
- コホートポリシーは、ルールエンジンを完全に活用します。フィルターの追加、ソフトブーストの適用、同義語の拡張、検索戦略の変更など、ポリシーが実行できるあらゆるアクションを実行できます。
- コホートの動作は、他のすべてのポリシーと同じ管理UIを通じて管理されます。マーチャンダイザーはパート2で説明されている「作成 → テスト → 昇格」ワークフローを通じて、コホートポリシーを作成、テスト、昇格できます。
ビーガンコホートポリシーの例
マーチャンダイザーは、以下の特徴を持つコホートポリシーを作成します。
- コホート:
["vegan"]。 - 一致条件:任意のクエリ(または特定の商品カテゴリー)に一致します。
アクション:dietary_restrictions: "vegan"に対してブーストウェイト2でソフトブーストを行います。

コホートのアクティベーションの仕組み
各ポリシードキュメントには cohorts フィールドがあります。ユニバーサルポリシーは、コホートに関係なくすべての購入者に適用されます。このフィールドを空白のままにすることができます。制御プレーンによって内部的に"_all"の値が割り当てられます。コホート固有のポリシーは、["vegan", "kosher", “sweet_tooth”]などのターゲットコホート名を保存します。
検索リクエストにユーザープロファイルが含まれる場合、制御プレーンはパーコレータークエリに対して単純なtermsフィルタを構築します。
この単一のフィルターには、すべてのユニバーサルポリシーに加え、ユーザーのコホート固有のポリシーも含まれます。_all センチネルにより、これはクリーンな包含フィルターになります:ポリシーにコホートの制限がない場合を処理するために must_not または exists のクエリは必要ありません。
その後、パーコレーターは通常どおりポリシーの一致を評価します。唯一の違いは、候補となるポリシーが、この購入者のグループに関連するものに絞り込まれている点です。下流のすべての処理(カスケード変換、フィールドごとの競合解決、消費フレーズの追跡)は、パート3およびパート4で説明した非パーソナライズフローとまったく同じように動作します。
「chocolate」を検索した非ヴィーガン(標準)ユーザーの検索結果
非ビーガンのユーザーがチョコレートを検索しても、ビーガンコホートのブーストは結果に適用されません。検索結果の上位には、以下のような非ビーガンチョコレートがよく表示されていました。

「chocolate」で検索したヴィーガンコホートポリシーの結果
ヴィーガンコホートの購入者が「チョコレート」を検索すると、このポリシーはパーコレーター候補セットに含まれます。一致しており、制御プレーンはヴィーガン認証チョコレートに穏やかなブーストを適用します。このブースト効果は乗算的です。ヴィーガンチョコレートは上位にランクインしますが、上記のフィルターはソフトブーストとして定義されているため、非ヴィーガンチョコレートが完全に除外されるわけではありません。ソフトブーストについては、このシリーズのパート3で詳しく説明しました。

しかし、購入者が明示的に「ハーシーミルクチョコレート」を検索する場合、ヴィーガンブーストは依然として適用されますが、「ハーシーミルクチョコレート」商品のより強いテキスト関連性によって影響を受ける可能性があります。

ビーガンコホートの外にいる購入者が同じクエリを検索しても、「ビーガンコホート」ポリシーは表示されません。それは候補セットに含まれていないためです。ガバナンスレイヤーは同一であり、異なるのは有効なポリシーセットのみです。
購入履歴のあるコホート
豊富な購入履歴を持つヴィーガンの購入者は、ビーガンコホート特有のポリシーの有効化や購入履歴の向上といった恩恵を受けられます。新規の購入者や匿名の購入者の場合、行動データを必要とせずに、暗黙のコホートメンバーシップだけで意味のあるパーソナライゼーションを提供します(例えば、匿名のユーザーはビーガン商品しか検索することがないので、ビーガンコホートのメンバーとして分類します)。アカウント作成時にハラール遵守として自己申告した購入者については、最初の検索ですぐにハラールに合わせた結果が表示されます。

パーソナライズレイヤーの構成方法
function_score層の入れ子順序が重要です。最も内側から最も外側へ:
- ベースクエリ:キーワードまたは名前付きクエリ(
fulltext_match、title_phrase_match)とのセマンティック一致。 - ガバナンスポリシーレイヤー:ハードフィルターは
bool.filter節、ソフトブーストはfunction_score関数として定義されます(パート3と4)。 - ビジネスシグナルの強化:マージンと人気度の向上(パート7で詳しく説明します)。
- 購入履歴のブースト:一番外側の
function_scoreレイヤー。
この順序付けにより、ガバナンスが結果セット(表示されるもの)を管理し、ビジネスシグナルがそのセット内でランキングを調整し(小売業者の視点で最初に表示されるもの)、購買履歴が個人の行動に基づいてさらにランキングを調整します(購入者の視点で最初に表示されるもの)。各レイヤーは前のレイヤーを乗法的に重ね合わせるため、効果は衝突するのではなく、相乗的に増幅されます。レイヤー
これが運用上で意味すること
パーソナライゼーションを通じたガバナンスを備えた制御プレーンは、パート1とパート2で説明されているすべての運用プロパティを保持します。
- デプロイの変更なし。コホートポリシーは管理者UIを通じて作成、テスト、推進されます。新しい食事コホートの追加やブーストの重みの調整には、コードの変更やエンジニアリングの関与は不要です。
- 監査可能性。すべてのコホートポリシーは、離散的でバージョン管理されたドキュメントです。マーチャンダイザーが「なぜこのユーザーに対してビーガン商品がより高いランキングを示しているのか?」と尋ねた場合、その答えは特定のポリシーとその特定の優先順位にあり、それはデバッグパネルで、そのクエリに対して起動した他のすべてのポリシーと共に表示されます。
- 競合解決。コホートポリシーは、第3部で説明したフィールドごとの競合解決と同じ処理に参加します。コホートポリシーのカテゴリブーストがキャンペーンポリシーのカテゴリーオーバーライドと競合する場合、競合は同じ優先順位と戦略のフレームワークによって決定論的に解決され、特別な処理は必要ありません。
- 測定可能性。コホートポリシーは個別に設定可能で、それぞれ独立しているため、システム内の他のポリシーと同様に、コンバージョン率、クリック率、カート追加率への影響を個別に測定できます。
このシリーズの次回作
次の投稿では、ガバナンスを備えた制御プレーンの別の側面を探ります。クエリごとにマージンと人気ブーストをポリシーを通じて調整し、経済的最適化を静的な設定ではなくガバナンス決定へと変える方法です。
パート7:クエリ制御型経済最適化:クエリごとのマージンと人気度向上を見る
ガバナンスを備えたeコマース検索を実践
この投稿で説明されているパーソナライゼーションパターン(個別の購入履歴ブーストとコホート対応ポリシーのアクティベーション)は、Elastic Services Engineeringによって、当社の繰り返し利用可能なeコマース検索アクセラレーターの一部として設計および構築されました。これらのメカニズムはどちらも、本シリーズ全体を通して説明してきたガバナンスを備えた制御プレーンアーキテクチャと統合されています。Elastic Professional Servicesにお問い合わせください。
議論に参加
検索ガバナンス、検索戦略、またはeコマース検索アーキテクチャについてご質問がありますか?より広範なElasticコミュニティの議論に参加しましょう。




