Azure AI Search でハイブリッド クエリを作成する

ハイブリッド検索は、単一の検索要求内でテキスト (キーワード) クエリとベクトル クエリを組み合わせたものです。 要求内のすべてのサブクエリが並列実行されます。 結果は Reciprocal Rank Fusion (RRF) を使ってマージされ、新しい検索スコアによって並べ替えられて、統合された結果セットが返されます。 多くの場合、ベンチマーク テストに従い、セマンティック ランク付けを使用したハイブリッド クエリからは最も関連性の高い結果が返されます。

この記事では、次のことについて説明します:

  • 基本的な要求を設定する
  • より多くのパラメーターとフィルターを使用してハイブリッド クエリを作成する
  • セマンティックのランク付けまたはベクトルの重みを使用して関連性を向上させる
  • テキストとベクトルの入力を制御してクエリの動作を最適化する

Note

2024-09-01-preview には、ハイブリッド要求のベクトル サブクエリだけをフィルターのターゲットにする機能が新しく追加されました。 これにより、フィルターの適用方法をより細かく制御できます。 詳細については、こちら記事のベクトル サブクエリへのフィルターのターゲット設定に関する説明を参照してください。

前提条件

API またはツールを選択する

  • Azure portal の Search Explorer (安定版とプレビュー版の両方の API 検索構文をサポート) には、ハイブリッド要求を貼り付けることができる JSON ビューがあります。

  • 2024-07-01 安定版または最新のプレビュー API バージョン (maxTextRecallSize や countAndFacetMode (プレビュー) などのプレビュー機能を使用している場合)。

    読みやすくするため、REST の例を使用して、API のしくみを説明します。 Visual Studio Code などの REST クライアントと REST 拡張機能を使用して、ハイブリッド クエリを作成できます。 詳細については、クイック スタート: REST API を使用したベクトル検索に関するページを参照してください。

  • Azure SDK の新しい安定版またはベータ版パッケージ (SDK 機能サポートの変更ログを参照)。

Search Explorer でハイブリッド クエリを設定する

  1. Search Explorer で、API バージョンが 2024-07-01 以降のプレビュー API バージョンであることを確認します。

  2. [ビュー] で、ベクトル クエリ 貼り付けることができるように [JSON ビュー] を選択します。

  3. 既定のクエリ テンプレートを、ベクトル クイックスタートの 539 行目から始まる "ハイブリッド クエリの実行" 例などのハイブリッド クエリに置き換えます。 簡潔にするために、この記事ではベクトルは切り詰められています。

    ハイブリッド クエリには、search で指定されたテキスト クエリと、vectorQueries.vector で指定されたベクトル クエリがあります。

    テキスト クエリとベクトル クエリは同等の場合も異なる場合もありますが、通常は同じ意図を共有します。

    {
        "count": true,
        "search": "historic hotel walk to restaurants and shopping",
        "select": "HotelId, HotelName, Category, Tags, Description",
        "top": 7,
        "vectorQueries": [
            {
                "vector": [0.01944167, 0.0040178085, -0.007816401 ... <remaining values omitted> ], 
                "k": 7,
                "fields": "DescriptionVector",
                "kind": "vector",
                "exhaustive": true
            }
        ]
    }
    
  4. [Search] を選択します。

ヒント

ベクトルを非表示にすると、検索結果が読みやすくなります。 [クエリ オプション] で、検索結果のベクトル値の非表示の設定を有効にします。

ハイブリッド クエリ要求 (REST API)

ハイブリッド クエリは、テキスト検索とベクトル検索を組み合わせたものであり、search パラメータはクエリ文字列を、vectorQueries.vector パラメータはベクトル クエリを受け取ります。 検索エンジンは、フルテキストとベクトル クエリを同時に実行します。 すべての一致の和集合は、Reciprocal Rank Fusion (RRF) を使用して関連性が評価され、応答で単一の結果セットが返されます。

結果は、retrievable とマークされたフィールドのベクトルを含む、プレーンテキストで返されます。 数値ベクトルは検索結果では役に立たないため、インデックス内の他のフィールドをベクトル一致のプロキシとして選択します。 たとえば、インデックスに "descriptionVector" フィールドと "descriptionText" フィールドがある場合、クエリは "descriptionVector" で一致しますが、検索結果には "descriptionText" と表示されます。 この select パラメータを使用して、結果に人間が判読できるフィールドのみを指定します。

次の例は、ハイブリッド クエリ構成を示しています。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "exhaustive": true,
            "k": 10
        },
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "exhaustive": true,
            "k": 10
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Address/City",
    "top": 10
}

重要なポイント:

  • ベクトル クエリ文字列は、vectorQueries.vector プロパティを使用して指定されます。 クエリは "DescriptionVector" フィールドに対して実行されます。 クエリの種類を示すには、kind を "vector" に設定します。 必要に応じて、exhaustive を true に設定し、ベクトル フィールドのすべての内容に対してクエリを実行します。

  • キーワード検索は、search プロパティを使用して指定されます。 ベクトル クエリと並行して実行されます。

  • k は、ベクトル クエリから返され、RRF ランカーに提供される最も近い近隣の一致の数を決定します。

  • top は、応答全体で返される一致の数を決定します。 この例では、マージされた結果に少なくとも 10 個の一致があると仮定して、応答に 10 個の結果が含まれています。

フィルターを使用したハイブリッド検索

この例では、検索インデックスの非ベクトル フィールド filterable に適用されるフィルターを追加します。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "k": 10
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "vectorFilterMode": "postFilter",
    "filter": "ParkingIncluded",
    "top": "10"
}

重要なポイント:

  • フィルターは、フィルター可能なフィールドの内容に適用されます。 この例では、ParkingIncluded フィールドはブール値であり、インデックス スキーマで filterable としてマークされています。

  • ハイブリッド クエリでは、クエリ サーフェスを減らすためにクエリの実行前に、または結果をトリミングするためにクエリの実行後にフィルターを適用することができます。 "preFilter" は既定値です。 postFilter を使用するには、この例に示すように、フィルター処理モードを設定します。

  • クエリ結果を事後フィルター処理すると、結果の数が上位 N 未満になる可能性があります。

ベクトル サブクエリを対象とするフィルターを使用したハイブリッド検索 (プレビュー)

2024-09-01-preview を使用すると、ハイブリッド要求のベクトル サブクエリのみを対象とするセカンダリ フィルターを適用することで、検索要求のグローバル フィルターをオーバーライドできます。

この機能は、フィルターがベクトル検索結果にのみ影響を与え、キーワードベースの検索結果には影響を与えないようにすることで、細かな制御を実現します。

ターゲット フィルターは、セキュリティによるトリミングや地理空間の検索に使用されるフィルターなど、グローバル フィルターを完全にオーバーライドします。 セキュリティによるトリミングなどのグローバル フィルターが必要な場合は、これらのフィルターを、最上位レベルのフィルターと各ベクトル レベルのフィルターの両方に明示的に含め、セキュリティやその他の制約が一貫して適用されるようにする必要があります。

対象となるベクトル フィルターを適用するには:

フィルターのオーバーライドを追加するハイブリッド クエリの例を次に示します。 グローバル フィルター "Rating gt 3" は実行時に filterOvrride に置き換えられます。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-09-01=preview

{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "exhaustive": true,
            "filterOverride": "Address/City eq 'Seattle'",
            "k": 10
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Address/City, Rating",
    "filter": "Rating gt 3"
    "debug": "vector",
    "top": 10
}

セマンティック ランカーを有効にし、インデックス定義にセマンティック構成が含まれていると仮定すると、ベクトル検索とキーワード検索 (マージされた結果セットに対するセマンティック ランカーを使用) を含むクエリを作成できます。 必要に応じて、キャプションと回答を追加できます。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "k": 50
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Tags",
    "queryType": "semantic",
    "semanticConfiguration": "my-semantic-config",
    "captions": "extractive",
    "answers": "extractive",
    "top": "50"
}

重要なポイント:

  • セマンティック ランカーでは、マージされた応答から最大 50 個の結果が受け入れられます。

  • "queryType" と "semanticConfiguration" は必須です。

  • "captions" と "answers" は省略可能です。 値は、結果内の逐語的なテキストから抽出されます。 回答は、クエリに対する回答の特性を持つ内容が結果に含まれている場合にのみ返されます。

フィルターを使用したセマンティック ハイブリッド検索

ここでは、コレクションでの最後のクエリを示します。 これは、前の例と同じセマンティック ハイブリッド クエリですが、フィルターを使用します。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "k": 50
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Tags",
    "queryType": "semantic",
    "semanticConfiguration": "my-semantic-config",
    "captions": "extractive",
    "answers": "extractive",
    "filter": "ParkingIsIncluded'",
    "vectorFilterMode": "postFilter",
    "top": "50"
}

重要なポイント:

  • フィルター モードは、セマンティック リランカーで使用できる結果の数に影響を与える可能性があります。 ベスト プラクティスとして、セマンティック ランカーにドキュメントの最大数 (50) を指定するのが賢明です。 事前フィルターまたは事後フィルターの選択性が高すぎる場合、操作するドキュメントを 50 未満にすることでセマンティック ランカーを過小評価している可能性があります。

  • 事前フィルターは、クエリの実行前に適用されます。 事前フィルターによって検索領域が 100 ドキュメントに縮小された場合、ベクトル クエリはこれらの 100 ドキュメントの "DescriptionVector" フィールドに対して実行され、k=50 の最適な一致が返されます。 その後、これらの一致する 50 ドキュメントが RRF に渡されてマージされた結果が得られ、セマンティック ランカーに渡されます。

  • 事後フィルターは、クエリの実行後に適用されます。 k=50 でベクトル クエリ側の 50 の一致が返された場合、事後フィルターはその 50 の一致に適用され、フィルター条件を満たす結果が減り、セマンティック ランカーに渡すドキュメントは 50 未満になります。

maxTextRecallSize と countAndFacetMode を設定する (プレビュー)

このセクションでは、ハイブリッド ランク付けモデルに送られる BM25 ランク付け結果の量を制御して、ハイブリッド クエリへの入力を調整する方法について説明します。 BM25 ランク付け入力を制御すると、ハイブリッド シナリオでの関連性チューニングのオプションが増えます。

プレビュー バージョンの REST API 2024-05-01-preview を使うことをおすすめします。

ヒント

考慮すべきもう 1 つのオプションは、補助または代替の手法のベクトル重み付けであり、要求でのベクトル クエリの重要性が高くなります。

  1. これらのパラメーターを指定するには、2024-05-01-preview で Search - POST または Search - GET を使います。

  2. ハイブリッド クエリの BM25 ランク付け結果によって呼び戻されるドキュメントの最大数を設定するには、hybridSearch クエリ パラメーター オブジェクトを追加します。 2 つのプロパティがあります。

    • maxTextRecallSize は、ハイブリッド クエリで使われる Reciprocal Rank Fusion (RRF) ランカーに提供する BM25 ランク付け結果の数を指定します。 既定値は 1,000 です。 最大値は 10,000 です。

    • countAndFacetMode は、BM25 ランク付け結果 (およびファセットを使用している場合はファセット) の数を報告します。 既定値は、クエリに一致するすべてのドキュメントです。 必要に応じて、"カウント" のスコープを maxTextRecallSize に設定できます。

  3. ベクトル類似性検索のパフォーマンスが一般にハイブリッド クエリのテキスト側より高い場合は、maxTextRecallSize を減らします。

  4. 大きなインデックスがあり、既定値で十分な数の結果がキャプチャされない場合は、maxTextRecallSize を増やします。 BM25 ランク付け結果セットが大きいときは、topskipnext を設定して、それらの結果の一部を取得することもできます。

次の REST の例では、maxTextRecallSize の設定に関する 2 つのユース ケースを示します。

最初の例では、maxTextRecallSize を 100 に減らして、ハイブリッド クエリのテキスト側を 100 ドキュメントのみに制限しています。 また、maxTextRecallSize からの結果のみを含むように、countAndFacetMode を設定しています。

POST https://[service-name].search.windows.net/indexes/[index-name]/docs/search?api-version=2024-05-01-Preview 

    { 
      "vectorQueries": [ 
        { 
          "kind": "vector", 
          "vector": [1.0, 2.0, 3.0], 
          "fields": "my_vector_field", 
          "k": 10 
        } 
      ], 
      "search": "hello world", 
      "hybridSearch": { 
        "maxTextRecallSize": 100, 
        "countAndFacetMode": "countRetrievableResults" 
      } 
    } 

2 番目の例では、maxTextRecallSize を 5,000 に増やしています。 また、top、skip、next を使って、大きな結果セットから結果をプルしています。 この場合の要求では、RRF 複合結果セットへのテキスト クエリの寄与として、位置 1,500 から始まって 2,000 までの BM25 ランク付け結果がプルされます。

POST https://[service-name].search.windows.net/indexes/[index-name]/docs/search?api-version=2024-05-01-Preview 

    { 
      "vectorQueries": [ 
        { 
          "kind": "vector", 
          "vector": [1.0, 2.0, 3.0], 
          "fields": "my_vector_field", 
          "k": 10 
        } 
      ], 
      "search": "hello world",
      "top": 500,
      "skip": 1500,
      "next": 500,
      "hybridSearch": { 
        "maxTextRecallSize": 5000, 
        "countAndFacetMode": "countRetrievableResults" 
      } 
    } 

クエリ応答を構成する

ハイブリッド クエリを設定するときは、応答構造について考えてください。 応答はフラット化行セットです。 クエリのパラメータによって、各行に含まれるフィールドと、応答内の行数が決まります。 検索エンジンは、一致するドキュメントをランク付けし、最も関連性の高い結果を返します。

応答のフィールド

検索結果は、検索インデックスの retrievable フィールドで構成されます。 結果は次のいずれかになります:

  • すべての retrievable フィールド (REST API の既定値)。
  • クエリの "select" パラメータに明示的に一覧表示されているフィールド。

この記事の例では、"select" ステートメントを使用して、応答のテキスト (非ベクトル) フィールドを指定しました。

Note

ベクトルは人間が判読できるテキストにリバース エンジニアリングされないため、応答で返されないようにします。 代わりに、検索ドキュメントを代表する非ベクトル フィールドを選択します。 たとえば、クエリが "DescriptionVector" フィールドを対象とする場合、応答に 1 つの ("Description") がある場合は、同等のテキスト フィールドを返します。

結果の件数

検索条件が弱い場合は、クエリが任意の数のドキュメントと一致する場合があります (たとえば、null クエリの場合は "search=*")。 無制限の結果を返すことが実用的であることは滅多にないので、"応答全体" の最大値を指定する必要があります:

  • "top": n キーワードのみのクエリの結果 (ベクターなし)
  • ベクトルのみのクエリの結果として "k": n
  • "top": n "search" パラメーターを含むハイブリッド クエリ (セマンティックあり、または、なし) の結果

"k" と "top" はどちらも省略可能です。 指定しない場合、応答の結果の既定の数は 50 です。 "top" と "skip" を設定して、より多くの結果をページングしたり、既定値を変更したりできます。

Note

2024-05-01-preview API でハイブリッド検索を使用する場合は、maxTextRecallSize を使用してキーワード クエリから返される結果の数を制御できます。 これを "k" の設定と組み合わせれば、各検索サブシステムからの表現 (キーワードとベクター) を制御できます。

セマンティック ランカーの結果

Note

セマンティック ランカーでは最大 50 件の結果を受け取ることができます。

2024-05-01-preview API でセマンティック ランカーを使用する場合は、"k" と "maxTextRecallSize" の合計が少なくとも 50 になるように設定することがベスト プラクティスです。 次に、"top" パラメーターを使用することで、ユーザーに返される結果を制限できます。

前の API でセマンティック ランカーを使用する場合は、次の操作を行います。

  • キーワードのみの検索 (ベクトルなし) を実行する場合は、"top" を 50 に設定します
  • ハイブリッド検索を実行する場合は、セマンティック ランカーに少なくとも 50 件の結果が確実に返されるように、"k" を 50 に設定します。

ランク付け

オプションの セマンティック再ランク付けの有無にかかわらず、ハイブリッド クエリでは複数のセットが作成されます。 結果のランク付けは、Reciprocal Rank Fusion (RRF) によって計算されます。

このセクションでは、単一ベクトル検索と単純ハイブリッド検索の応答を比較して、上位の結果を確認します。 異なるランク付けアルゴリズムである HNSW の類似性メトリックと RRF の場合では、異なる大きさのスコアが生成されます。 この動作は仕様によるものです。 RRF スコアは、類似性の一致が高い場合でも、非常に低くなる場合があります。 スコアの低さは、RRF アルゴリズムの特性です。 RRF を使用するハイブリッド クエリの場合、純粋なベクトル検索とは対照的に、RRF でランク付けされたドキュメントのスコアは比較的小さいため、ランク付けされたドキュメントの逆数がより多く結果に含まれます。

単一ベクトル検索: コサイン類似度で並べ替えられた結果の @search.score (既定のベクトル類似距離関数)。

{
    "@search.score": 0.8399121,
    "HotelId": "49",
    "HotelName": "Swirling Currents Hotel",
    "Description": "Spacious rooms, glamorous suites and residences, rooftop pool, walking access to shopping, dining, entertainment and the city center.",
    "Category": "Luxury",
    "Address": {
    "City": "Arlington"
    }
}

ハイブリッド検索: Reciprocal Rank Fusion を使用してランク付けされたハイブリッド結果の @search.score。

{
    "@search.score": 0.032786883413791656,
    "HotelId": "49",
    "HotelName": "Swirling Currents Hotel",
    "Description": "Spacious rooms, glamorous suites and residences, rooftop pool, walking access to shopping, dining, entertainment and the city center.",
    "Category": "Luxury",
    "Address": {
    "City": "Arlington"
    }
}

次のステップ

次のステップとして、PythonC#、または JavaScript のデモ コードを確認することをお勧めします。