eコマース検索を管理するための制御プレーンの構築

コード変更なしで、競合する検索ポリシーを単一の実行計画にまとめるeコマースのガバナンスを備えた制御プレーンを構築する方法。

本シリーズのパート1パート2では、eコマース検索にガバナンスレイヤー、つまりユーザーのクエリと検索エンジンの間の意思決定レイヤーが必要な理由を明らかにしました。このレイヤーは、意図を分類し、制約を適用し、適切な検索戦略(例えば、BM25、セマンティック、ハイブリッド)にルーティングします。この記事では、クエリ解釈ポリシーをドキュメントとして保存し、クエリ実行時に高速な逆マッチングによって取得する、シンプルなアーキテクチャプリミティブを使用してそのレイヤーを構築する方法を示します。新しい検索ポリシー(「ブランドXを優先」や「カテゴリYのみを表示」など)はコードの変更を必要としないため、結果として、ポリシーが進化してもルーティングレイヤーは安定性を保ち、リスクの高い環境でも検索エンジンを安全に保つことができます。このアーキテクチャの最終的な成果を先に知りたい方は、動画「Fixing Search Relevance in Seconds: Introducing PRISM」をご覧ください。

クエリの解釈が難しい理由

ポリシーをコードとして保存する(アプリケーション層のif/elseブロックとして保存する)と、クエリ時に効率的にポリシーを取得するためのインデックスが一切ない、何万行にも及ぶ脆弱なロジックが生成されます。反復処理が遅く(単一のクエリの動作変更に6週間の導入サイクルが必要になる場合も)、責任の所在が不明確(結果が変更された理由は?)、そしてビジネスユーザーはエンジニアリングの関与なしに検索動作を変更できません。これは次の画像の左側に表示されています。

ポリシーをデータとしてElasticsearchインデックスに格納する方法は上の画像の右側に示されています。このアプローチにより、ハードコードされたクエリ解決ロジックに伴う問題をすべて解消できます。ただし、これを機能させるには、どのポリシーがユーザーのクエリに一致するかを素早く判断し、競合をどのように解決するかを決定する方法が必要です。ここで、ガバナンスを備えた制御プレーンが役立ちます。

制御プレーンのパターン

ガバナンスを備えた制御プレーンは、生のユーザークエリとElasticsearchの検索の間に位置します。ユーザーテキストを入力として受け取り、出力にフィルター、ブースト、検索ルーティングの決定を含む実行計画です。

制御プレーンパイプラインは以下で構成されます:

  1. ユーザークエリ:ユーザーは探しているものの文字列を入力します。例えば「オレンジ」や「おじいちゃんへのプレゼント」など。
  2. ポリシー検索:ユーザーのクエリをポリシーインデックスと照合します。
  3. 一致するポリシーを返す:ユーザークエリに一致するポリシーがポリシーインデックスから返されます。
  4. ポリシーの適用:制御プレーンは、返されたこれらのポリシーを分析し、一致するポリシーを、フィルター、ブースト、オーバーライド、ガードレールを含む単一の一貫性のある実行計画に構成し、適切な検索方法(語彙的、意味的、ハイブリッドなど)を適用します。
  5. 実行:変更された意図認識型のElasticsearchクエリがアプリケーションに渡され、商品カタログインデックスに対して実行されます。
  6. 説明(オプション):ビジネスと意図に沿った結果を提供するクエリの作成に加えて、制御プレーンは、どのポリシーがトリガーされ、それらがどのように組み合わせられたかを示すオプションの説明ペイロードを提供します。

ユーザーの検索文字列にどのポリシーを適用すべきかを判断するには高速な逆マッチングプリミティブが必要であり、私たちはそれをpercolator(パーコレーター)クエリで解決します。関連するポリシーを取得した後、一致する複数のポリシーを統合された実行計画に組み合わせるには、判断フレームワークが必要です。これには、優先順位、競合戦略、使用済みフレーズの追跡、ポリシーを個別にではなく順番に適用するカスケード変換が含まれます。さらに、最も適切な検索技術を選択する必要があります(例えば、「オレンジ」にはBM25 、一方「おじいちゃんへのプレゼント」にはセマンティック検索など)。

ポリシー検索:商品検索前にクエリを確認

購入者がクエリを入力しても、ガバナンス付きの制御プレーンを備えた検索システムは、そのクエリを直接商品カタログに対して実行することはありません。まず、クエリは保存されたポリシーのセットと照合され、クエリの意図やビジネスの優先順位を反映するように修正されます。

ポリシー構造

各ポリシーは、以下の2つの事項を定義するシンプルな文書です。

  • 一致基準:このポリシーをトリガーするクエリテキスト。正確なフレーズ、単語、パターン、またはそれらの組み合わせです。
  • アクション:ポリシーが発動した際に何をすべきか。これは、カテゴリーフィルターの適用、商品の除外、価格制約の抽出、または検索戦略の変更などが考えられます。

システムは、一致するすべてのポリシーを検出し、それらを実行計画にまとめ、その後で初めて商品検索を実行します。これらのポリシーを総合的に見ると、まるであなたが探しているものを理解し、適切な通路まで案内してくれる知識豊富な店員のような役割を果たします。

ポリシーパターン

本シリーズの最初の記事では、実際に運用されているポリシーの例を紹介しました。「オレンジ」を農産物カテゴリーに限定すること、「ピーナッツなし」を除外対象として扱うこと、「おじいちゃんへのプレゼント」をセマンティック検索にルーティングすることなどです。重要なアーキテクチャー上のポイントは、いずれの場合も、商品検索を開始する前に、クエリが保存されているポリシーと照合されるという点です。これらのポリシーは、適用する制約、変更するテキスト、使用する検索戦略を決定します。商品カタログに対するクエリは、ポリシーが適用され、新たに書き換えられたクエリが作成された後に行われます。

これが高速である理由

企業向けeコマースシステムには数百万の商品が存在しても、ポリシーは数百から数千件しかないかもしれません。ポリシー検索のステップでは、商品カタログ全体ではなく、厳選された小規模なインデックスに対して検索を行うため、高速です。また、ポリシーは独自のインデックスにデータとして保存されるため、マーチャンダイザーが新しいポリシーを追加する際にアプリケーションコードを変更する必要はなく、商品検索を最適化するエンジニアもポリシーインデックスを変更する必要がありません。この2つの懸念は独立して発展していきます。

上記の例では、概念的に何が起こるかを説明しています。内部的には、ポリシー検索はElasticsearchのパーコレータークエリタイプを使用して実装されています。これは、受信テキストを保存済みのクエリセットと照合するという、この種のパターンに特化して設計されたものです。パート4では、このシリーズのパーコレーター実装について、インデックスマッピング、境界マーカー、ハイライトベースのフレーズ追跡を含めてハンズオン形式で詳しく解説しています。パート4でルックアップメカニズムについて詳しく解説したので、ここではポリシードキュメントに実際に何が含まれているのか、そして制御プレーンが複数のポリシーをどのように組み合わせて単一の実行計画を作成するのかを見ていきましょう。

ポリシーの例

ポリシーが概念的にどのような役割を果たすのかを見てきたところで、次に政策が実際にどのような内容を含んでいるのかを見ていきましょう。以下の2つのポリシーは、意図的に対立するように設計されており、次のセクションで説明する競合解決システムの実例となります。

安いチョコレート

以下に示すポリシーは、ユーザーが「安いチョコレート」というフレーズを含む検索を送信したかどうかを検出します。その場合、結果は「チョコレート」と「ミルクチョコレート」のカテゴリーに限定されます。このポリシーには2ドルの価格フィルターも適用されます。また、このポリシーの優先度は210であることにも注意してください。これについては、競合解決についてより詳しく説明する際に改めて触れます。

ここに示されているフィルターモードと競合戦略の設定(hard_filter、soft_boost、restrict、override)については、以下の競合解決セクションで詳しく説明します。

上記のポリシーが有効になっている場合、「安いチョコレート」を検索すると、2ドルの価格フィルターが適用され、検索結果は「チョコレート」と「ミルクチョコレート」のカテゴリーに制限されます。結果の例を以下に示します。

クリスマスチョコレート

以下に示すポリシーは、クリスマスの時期に適用すると想定できるポリシーの例です。この例では、検索結果を「クリスマスの食べ物と飲み物」と「クリスマスのお菓子」に限定し、「アドベントカレンダー」カテゴリーに含まれる商品をブーストし、手頃な価格の季節商品にフォーカスするために7ドル未満の価格フィルターを適用しています。さらに、このポリシーの優先度は300であることにも注意してください。これについては、競合解決をさらに詳しく説明する際に改めて取り上げます。

上記のポリシーが有効で、競合するポリシーがない場合、「チョコレート」の検索では7ドルの価格フィルターが適用され、「クリスマスの食べ物と飲み物」および「クリスマスのお菓子」のカテゴリに結果が限定され、「アドベントカレンダー」としてタグ付けされた商品の表示がブーストされます。結果の例を以下に示します。

一致するポリシーの組み合わせ

上記のポリシー検索は話の半分に過ぎません。もう半分は、複数のポリシーが同じクエリに一致した場合に起こることです。

複雑なシステム展開においては、単一のクエリによって複数のポリシーが同時に実行されることが一般的です。「安いチョコレート」は、上記で示した2つのポリシーの両方に合致します。それぞれのポリシーは単独で見れば正しいものです。課題は、それらを矛盾なく、二重計算せずに、そして一つのポリシーが他のポリシーの作業を静かに無効にすることなく、単一の一貫した実行計画にまとめることです。

これは検索の問題ではなく、判断の問題です。システムは以下を決定しなければなりません。

  • 適用順序:否定ポリシーにより「ピーナッツなし」がクエリから削除された場合、価格ポリシーは元のテキストと変更後のテキストのどちらを参照するか?
  • フィルターの競合:2つのポリシーで異なる価格上限が設定されている場合、どちらを優先するか?敗者はひっそりと切り捨てられるのか、それとも穏やかに順位を落とし、ソフトブーストにつなげるのか?
  • フレーズの所有権:2つのポリシーが同じ単語に一致し、最初のポリシーがすでにその単語を消費している場合、2番目のポリシーは実行されるべきか?

単純な実装(一致するポリシーをすべて個別に適用し、結果をマージ)では、ポリシー同士が相互作用するとすぐに問題が発生します。アーキテクチャーにはポリシーの構成方法に関する明示的なモデルが必要です。次の2つのセクションでは、そのモデルについて説明します。すなわち、優先順位付けと競合解決の枠組み、そしてポリシー間の相互作用を決定論的にするカスケード変換モデルです。

重要な点は、ポリシーの適用は独立した一連の操作ではなく、カスケード的な変換であるということです。各ポリシーは、すべての上位ポリシーによって生成された書き換え状態を受け取り、それをさらに変換します。

初期状態 → [ポリシーA] → 状態' → [ポリシーB] → 状態'' → ... → 実行計画

状態は書き換えられたクエリテキスト、累積されたフィルター、現在の意図、そしてすべての同義語展開を保持します。優先度の高いポリシーはクエリからテキストを削除することができ、それ以降のすべてのポリシーは元のクエリではなく、変更されたクエリを参照します。コンテキストが蓄積されます。順序が重要です。

優先順位と競合の解決:決定論が重要

具体的な競合戦略は設計上の選択です。組織によって競合解決の方法は異なり、それぞれのビジネス上の要件によって左右されます。以下のアプローチは、制御プレーンに必要な判断フレームワークの種類を示しています。重要なのはこれらの具体的な戦略そのものではなく、システムが予測不可能な相互作用によって競合を解決するのではなく、明確で決定論的な戦略を持つことです。

優先度による順序付け

ポリシーは優先度の高い順に並べ替えられます(最も優先度の高いものから)。複数のポリシーが同じクエリに一致する場合、それらは優先順位に従って適用されます。2つのポリシーが同じフィルターフィールドを設定しようとすると、そのフィールドに対して優先順位の高いポリシーが宣言した戦略が優先されます。同じ優先度を持つポリシーが複数トリガーされた場合、IDが最も高いポリシーが優先されます(より高い優先度が割り当てられているかのように)。この選択により、競合が発生した場合でも決定的な動作が保証されます。

ポリシー単位ではなく、フィールド単位の解決

重要な設計原則:競合解決はフィールドごと(例えば、ブランド、カテゴリー、または説明)で動作し、ポリシーごとではありません。2つのポリシーが特定のフィールドで重複するフィルターを生成する場合、その特定のフィールドのみが競合解決戦略の影響を受け、解決戦略は最も優先度の高いマッチングポリシーによって定義されます。両ポリシーの競合しないフィールドはそのまま残ります。

これは重要です。なぜなら、ポリシーごとのアプローチの代替案では、フィールドの1つだけが競合する場合でも、システムはポリシー全体を受け入れるか拒否しなければならないからです。

フィールドごとの解決により、有用な制約情報を最大限保持できます。

フィルターフィールドごとに3つの設定

ポリシー内の各フィルターフィールドには、3つの独立した設定があります。

フィルターモード:競合がない場合にフィルターがどのように適用されるか。

  • hard_filter (デフォルト):Elasticsearchのbool.filter句として適用されます。これは無関係な商品を完全に除外するのに役立ちます。例えば、「オレンジ」という検索語を農産物カテゴリーに限定すると、オレンジジュースやオレンジマーマレードなどの検索結果は除外されます。一致しない文書は検索結果から完全に除外されます。
  • soft_boostElasticsearch function_score の重みとして適用され、boost_weight を設定可能です。一致する文書はランキングが上がりますが、一致しない文書も除外されるわけではありません。これは、他のブランドを排除することなく、自社ブランドの認知度を高めるといった場合に役立ちます。

競合戦略

低優先度のポリシーが同じフィールドを設定した場合、何が起こるのでしょうか。

  • override:この優先度の高いポリシーの値が優先され、優先度の低いポリシーの値は完全に無視されます。すべてのフィールドタイプに有効です。
  • restrict:より制限的な数値(例えば、価格__max, the higher floor for price__分の下限)を取ります。数値範囲フィールドでのみ有効です。
  • merge:両方の値を結合して和集合にします。数値以外のフィールドにのみ有効です。
  • soft_boost:競合するフィルターを、ハードフィルターではなく、設定可能なboost_weightを持つfunction_score重みに変換します。function_scoreブーストの詳細については、Elasticsearchの乗算ブーストによるBM25ランキングへの影響をご覧ください。これは非否定フィールドにのみ有効です。

値:実際のフィルター値(例:カテゴリーリスト、価格しきい値)。

フィールド別戦略:すべての戦略がすべてのフィールドに有効とは限りません。例えば、除外は本質的に二項的であるため、ソフトブーストはできません。以下の表は各フィールドタイプで利用可能な戦略を示しています。

フィールドタイプ利用可能な戦略デフォルト
否定フィールド(__not, __match__not)オーバーライド、マージオーバーライド
数値範囲フィールド(__max, __min、__gt, __lt)制限、オーバーライド、soft_boost制限
その他すべてのフィールド(keyword、text)soft_boost、override、mergeソフトブースト

否定フィールドは、除外が二値であるため、ソフトブーストすることはできません。「缶詰食品を一切表示しない」を「缶詰以外の食品をやや優先する」に変更すると、意味が根本的に変わってしまいます。「缶詰食品」の商品は依然として表示され、順位が少し下がるだけなので、除外する目的が損なわれてしまいます。

具体的な例:クリスマスキャンペーン中に「安いチョコレート」を検索

あるマーチャンダイザーが、先に説明した2つのチョコレートに関するポリシーを作成したとします。1つは安価なチョコレート向けの優先度の低いポリシー、もう1つはクリスマス期間中に有効になる優先度の高いチョコレート関連のポリシーです。これらのポリシーが両方とも有効になっている場合、それらがどのように組み合わせられるかは、優先順位の高いポリシーのフィルターモードと競合戦略によって決まります。前述の2つのポリシーが両方とも有効になっている場合、それらは以下のように組み合わせられます。

これは、カテゴリーに関する競合と価格に関する競合という2つの対立を示しています。この変換後に実行されるクエリは以下の特徴を持つことに注意してください:

  • 「クリスマスの食べ物と飲み物」および「クリスマスのお菓子」のカテゴリーに属する商品のみが表示されます。
  • これらのカテゴリーの中で、商品に「アドベントカレンダー」カテゴリーのタグが付けられている場合は、3倍ブーストされます。
  • 2ドルの価格フィルターが適用されます。これは優先度の低いポリシーから取得されたものです(優先度の高いポリシーでは、競合が発生した場合に「制限」するように指定されているため)。
  • 「安い」という単語が削除され、「チョコレート」に一致する商品のみが表示されます。

これら2つのポリシーを有効にすると、「安いチョコレート」という検索語は、以下の画像のような結果を返します。

制約の緩和

おそらく、その小売業者はクリスマス期間中に「チョコレート」や「ミルクチョコレート」といったカテゴリーの商品を除外したくないのでしょう。クリスマスポリシーの設定が行き過ぎて、「安いチョコレート」ポリシーで適用されているカテゴリが誤って削除された可能性があります。これは、優先度の低いポリシーと相反する優先度の高いポリシーを組み合わせる方が望ましい場合がある理由を示す一例です。例えば、クリスマスチョコレートのプロモーションを修正して、競合が発生した場合に「オーバーライド」するのではなく、優先度を少し高めるようにすることができます。そのポリシーの変更は以下の通りです。

この修正後、「安いチョコレート」のクエリ書き換え変換パイプラインの実行は次のようになります。

競合時のソフトブーストでは、競合するフィルターは削除されるのではなく、ソフトブーストに変換されます。この変換後に商品カタログに対して実行されるクエリは、以下の特徴を持ちます。

  • 優先度の高いポリシーでは「競合発生時」が「ソフトブースト」として指定されているため、競合は以下のようにブーストに変換されます。
    • 「クリスマスの食べ物と飲み物」および「クリスマスのお菓子」のカテゴリーの商品には、1倍のブーストが適用されます。
    • 「チョコレート」および「ミルクチョコレート」カテゴリーの製品には、3倍のブーストが適用されます。
  • 前の例と同様に、商品が「アドベントカレンダー」カテゴリーに分類されている場合、それらは3倍ブーストされます。
  • 前述の例と同様に、2ドルの価格フィルターが適用されます。
  • 「安い」という単語が削除され、「チョコレート」に一致する商品のみが表示されます。

フィルタリング条件を緩めると、結果は以下のようになります。

優先順位の高いポリシーによる価格のオーバーライド

あるいは、小売業者はクリスマス期間中に少し高めのチョコレートを表示できるように、価格の上限を7ドルに引き上げたいと考えているかもしれません。誰かが「安いチョコレート」を検索した場合でも、クリスマスチョコレートポリシーの最大価格がオーバーライドされないようにするには、価格の競合モードを「制限」ではなく「上書き」に設定できます。設定方法は以下のとおりです。

このオーバーライドでは、「安いチョコレート」のクエリは、「安いチョコレートポリシー」で定義されている最高価格を無視し、次のように「クリスマスチョコレート」ポリシーで指定された価格のみを適用します。

これは前の例と似ていますが、違いは、優先順位の高いポリシーで競合時に「オーバーライド」が指定されているため、最大価格が7ドルの値に設定されている点です。クリスマス価格フィルターを優先すると、結果は次のようになります。

これら3つのバリエーション(override、soft_boost、価格のoverride)は、システムの重要なプロパティを示しています。マーチャンダイザーは、コードをデプロイせずに、1つのポリシー内の1つのフィールド設定を変更するだけで2つのポリシーの相互作用を変更できます。競合戦略は、ビジネスの行動を制御する手段となります。

消費されたフレーズの追跡

より微妙な形の対立もあります。同じ言葉で一致する2つのポリシーです。優先度の高いポリシーがクエリから「ピーナッツなし」を削除した場合、「なし」に一致した優先度の低いポリシーは処理すべき対象がなくなります。システムは、一致したフレーズが書き換えられたクエリに存在しないことを検出すると、優先度の低いポリシーをスキップします。

インテントポリシーは、消費されたフレーズの追跡の対象外です。優先度の高いポリシーによって削除されたテキストに関係なく、元のクエリの一致に基づいて検索戦略を設定します。

優先順位付け、フィールドごとの競合解決、消費されたフレーズの追跡を組み合わせることで、制御プレーンは決定論的な構成モデルを実現できます。その基盤が整えば、システムはリスクのあるルーティング決定を行うことができます。

ガバナンスにより検索戦略が安全に

適切な検索方法(テキスト、セマンティック、またはハイブリッド)へのルーティングに関する重要な洞察は、それがガバナンスの後に実行されるということです。ポリシーですでに「農産物カテゴリー」が規定されている場合、候補セットが制限されるため、セマンティック検索のリスクは大幅に軽減されます。500点の商品アイテムに対するセマンティック検索は、50万点のSKUに対するセマンティック検索とは全く異なるものです。ガバナンスにより、検索が始まる前に影響範囲が狭められます。

例えば、ガバナンスがない場合、「4ドル以下のビタミンCを多く含む果物」というセマンティッククエリは、果物に加えて、ビタミン剤、ニンジン、ピーマンを返す可能性があります。制御プレーンは、これらの望ましくない結果が意味展開の一部として考慮されないことを保証します。

この制約が設定されると、制御プレーンは実用的なルーティングロジックを適用します。

  • ナビゲーションクエリやヘッドクエリなど、決定論的な精度が重要な場面における語彙
  • 概念マッチングが役立つ、記述的なディスカバリークエリのためのセマンティクス
  • 制約がすでに実施されており、企業がより広範なリコールを受け入れる場合には、選択的にハイブリッドを採用。

アーキテクチャーから実装へ

ガバナンスを備えた制御プレーンは、アプリケーションコードにそのロジックを組み込むことなく、ビジネスの意図を決定論的で構成可能な実行計画に変換します。ポリシーはデータであり、クエリ時に照合され、フィールドごとの明示的な競合戦略によって解決され、説明可能な結果を生み出すカスケード変換として適用されます。Elastic Services Engineeringは、企業のeコマースチーム向けに、コンセプトから本番環境までの道のりを短縮する反復可能なパターンとアクセラレーターを使用してこのアーキテクチャーを構築しデプロイしました。制御プレーンの実装デモは、YouTubeの「Fixing Search Relevance in Seconds: Introducing PRISM」でご覧いただけます。

このシリーズの次回作

次回の投稿では実装をハンズオンで解説し、Elasticsearchパーコレーターがポリシーのルックアップをどのように支えているかを取り上げます。インデックスのマッピング、境界マーカー、ハイライトに基づくフレーズ追跡、具体的なクエリ例も紹介します。

ガバナンスを備えたeコマース検索を実践

この投稿で説明されている制御プレーンアーキテクチャー(フィールドごとの競合解決、カスケードポリシー変換、ガバナンス制約付き検索ルーティング)は、Elastic Services Engineeringによって設計および構築されました。このシリーズで紹介するパターン、スクリーンショット、トランスフォーメーションパイプラインはすべて、Elastic Services Engineeringによって構築され、エンタープライズスケールの商品カタログと照合された実際のシステムからのものです。

Elasticsearch上にガバナンスを備えたポリシー駆動型の制御プレーンを実装したい場合、Elastic Servicesを利用すれば、より迅速に実現できます。

議論に参加

検索ガバナンス、検索戦略、またはeコマース検索アーキテクチャについてご質問がありますか?より広範なElasticコミュニティの議論に参加しましょう。

このコンテンツはどれほど役に立ちましたか?

役に立たない

やや役に立つ

非常に役に立つ

関連記事

最先端の検索体験を構築する準備はできましたか?

十分に高度な検索は 1 人の努力だけでは実現できません。Elasticsearch は、データ サイエンティスト、ML オペレーター、エンジニアなど、あなたと同じように検索に情熱を傾ける多くの人々によって支えられています。ぜひつながり、協力して、希望する結果が得られる魔法の検索エクスペリエンスを構築しましょう。

はじめましょう