Azure Cognitive Search での検索結果の操作方法

この記事では、Azure Cognitive Search でクエリの応答を使用する方法について説明します。 応答の構造は、クエリ自体のパラメーターによって決まります。ドキュメントの検索 (REST) またはSearchResults クラス (Azure for .NET) に関するページをご覧ください。

クエリのパラメーターによって、次のことが決まります。

  • 結果内のフィールドの選択
  • クエリのインデックスで見つかった一致の数
  • 応答に含まれる結果の数 (既定では最大 50)
  • 並べ替え順序
  • 結果内の用語を強調表示し、本文内の用語の全体または一部に一致します

結果の構成

結果は表形式で、すべての「取得可能」フィールドのフィールドで構成されるか、$select パラメーターで指定されたフィールドのみに制限されます。 行は一致するドキュメントです。

検索ドキュメントは多数のフィールドで構成される可能性がありますが、一般に、結果セット内の各ドキュメントを表すために必要なものは数個しかありません。 クエリ要求では、$select=<field list> を追加して、応答に含めるフィールドを指定します。 あるフィールドを結果に含めるには、そのフィールドのインデックスに「取得可能」の属性が付けられている必要があります。

最適に機能するフィールドには、各ドキュメントを比較対照して区別することにより、ユーザーの側にクリックスルー応答を誘うための十分な情報を提供するフィールドが含まれます。 eコマース サイトでは、それは製品名、説明、ブランド、色、サイズ、価格、評価などである場合があります。 組み込みの hotels-sample インデックスの場合、次の例の "select" フィールドのようになります。

POST /indexes/hotels-sample-index/docs/search?api-version=2020-06-30 
    {  
      "search": "sandy beaches",
      "select": "HotelId, HotelName, Description, Rating, Address/City"
      "count": true
    }

Note

結果に画像ファイル (製品の写真やロゴなど) を含める場合、それらは Azure Cognitive Search の外部に格納しますが、画像の URL を参照するためのインデックス内のフィールドを検索ドキュメントに含めます。 結果内の画像をサポートするサンプル インデックスには、realestate-sample-us のデモ (データのインポート ウィザードで簡単に構築できる組み込みのサンプル データセット) や、ニューヨーク市のジョブのデモ アプリが含まれます。

予期しない結果が生じた場合のヒント

結果の実質 (構造ではなく実質的な中身) が、予期しない内容になっている場合も少なくありません。 たとえば、一部の結果が重複しているように見える場合や、上部の近くに表示され "なければならない" 結果が下の方に配置される場合があります。 クエリの結果が予期しないものである場合は、こちらのクエリ変更を試して、結果が改善されるかどうかを確認できます。

  • searchMode=any (既定) を searchMode=all に変更し、いずれかの条件への一致ではなく、すべての条件への一致を強制します。 これは特に、ブール演算子がクエリに含まれているときに当てはまります。

  • さまざまな字句アナライザーやカスタム アナライザーを試して、クエリ結果が変わるかどうかを確認します。 既定のアナライザーは、ハイフンでつながれた単語を分割し、単語を原形に変換します。通常はこれにより、クエリ応答の堅牢性が向上します。 ただし、ハイフンを保持する必要がある場合、または文字列に特殊文字が含まれている場合は、インデックスに適切な形式のトークンが含まれるようにカスタム アナライザーを構成することが必要になる場合があります。 詳細については、「部分的な用語検索と特殊文字を含むパターン (ハイフン、ワイルドカード、正規表現、パターン)」を参照してください。

一致のカウント

count パラメーターは、クエリの一致と見なされるインデックス内のドキュメントの数を返します。 カウントを返すには、クエリ要求に $count=true を追加します。 検索サービスによって課される最大値はありません。 クエリおよびドキュメントの内容によっては、カウントがインデックス内のすべてのドキュメントと同じ大きさになる場合があります。

インデックスが安定している場合、カウントは正確です。 システムがドキュメントをアクティブに追加、更新、または削除している場合、インデックスが完全に作成されていないドキュメントを除き、カウントは概算値になります。

Count は、定期的なメンテナンスや検索サービスのその他のワークロードの影響を受けません。 ただし、複数のパーティションと 1 つのレプリカがある場合は、パーティションの再起動時にドキュメント数 (数分) に短期的な変動が発生する可能性があります。

ヒント

インデックス作成操作をチェックするには、空の検索 search=* クエリに $count=true を追加することで、インデックスに予想される数のドキュメントが含まれているかどうかを確認できます。 結果は、インデックス内のドキュメントの完全な数になります。

クエリ構文をテストするとき、$count=true は、変更によって返される結果が多いか少ないかをすばやく判断できるため、有用なフィードバックになります。

ページングの結果

既定では、検索エンジンからは最初の最大 50 件の一致が返されます。 上位 50 は、クエリが全文検索またはセマンティック検索であると仮定して、検索スコアによって決定されます。 それ以外の場合、上位 50 は完全一致クエリの任意の順序です ("@searchScore=1.0")。

結果セットで返されるすべてのドキュメントのページングを制御するには、$top および $skip パラメーターをクエリ要求に追加します。 このロジックを説明する一覧を次に示します。

  • 15 個の一致するドキュメントの最初のセットに加え、合計の一致の数を返します: GET /indexes/<INDEX-NAME>/docs?search=<QUERY STRING>&$top=15&$skip=0&$count=true

  • 2 番目のセットを返し、次の 15 個を取得するために最初の 15 個をスキップします: $top=15&$skip=15。 3 番目の 15 個セットに対して繰り返します: $top=15&$skip=30

基になるインデックスが変更されている場合、ページ分割されたクエリの結果の安定性は保証されません。 ページングによって各ページの $skip の値が変更されますが、各クエリは独立しており、クエリ時にインデックス内に存在する (つまり、汎用データベースで見られるような結果のキャッシュやスナップショットは存在しない) ため、データの現在のビューに対して動作します。

次の例は、重複がどのように発生するかを示しています。 4 つのドキュメントを含む次のインデックスがあるとします。

{ "id": "1", "rating": 5 }
{ "id": "2", "rating": 3 }
{ "id": "3", "rating": 2 }
{ "id": "4", "rating": 1 }

ここでは、結果を一度に 2 つ、評価の順序で返してもらいたいとします。 結果の最初のページを取得するために $top=2&$skip=0&$orderby=rating desc というクエリを実行すると、次の結果が生成されます。

{ "id": "1", "rating": 5 }
{ "id": "2", "rating": 3 }

このサービスでは、クエリ呼び出しの間に { "id": "5", "rating": 4 } という 5 番目のドキュメントがインデックスに追加されたとします。 その後すぐに、2 ページ目をフェッチするために $top=2&$skip=2&$orderby=rating desc というクエリを実行すると、次の結果が得られます。

{ "id": "2", "rating": 3 }
{ "id": "3", "rating": 2 }

ドキュメント 2 が 2 回フェッチされることに注意してください。 これは、新しいドキュメント 5 の方が評価の値が大きいため、ドキュメント 2 の前に並べ替えられ、最初のページに割り当てられるためです。 この動作は予期されない可能性がありますが、検索エンジンの動作としては一般的なものです。

結果の並べ替え

フルテキスト検索クエリでは、検索スコア、セマンティック再ランカー スコア (セマンティック検索を使用している場合)、または明示的な並べ替え順序を指定するクエリ要求の $orderby 式によって、結果をランク付けできます。

並べ替え方法は、併用できるようには設計されていません。 たとえば、主の並べ替え方法として $orderby を使用し、検索スコアに基づく二次的な並べ替えを適用する、といったことはできません (検索スコアは一様になるため)。

検索スコアによる並べ替え

フルテキスト検索クエリの場合、結果は、(TF-IDF から導出された) ドキュメント内の用語頻度と近接性に基づいて計算された検索スコアによって自動的にランク付けされます。ここで、検索用語に対するより多くの、またはより強力な一致を含むドキュメントにより高いスコアが割り当てられます。

"@search.score" の範囲は、0 から 1.00 まで (この値は含みません) です。 "@search.score" が 1.00 の場合は、スコア付けまたはランク付けされていない結果セットを示し、すべての結果に対してスコアは一様に 1.0 になります。 スコア付けされていない結果が発生するのは、クエリ フォームがあいまい検索、ワイルドカードまたは正規表現のクエリ、または空の検索 (search=*) である場合です。 スコア付けされていない結果に対してランク付け構造を設定する必要がある場合は、$orderby 式がその目標を達成するのに役立ちます。

検索スコアは、一般的な意味での関連性を示すものであり、同じ結果セット内の他のドキュメントと比べた場合の一致の強さが反映されています。 ただし、スコアは、あるクエリと次のものとの間で必ずしも一貫しているとは限らないため、クエリを操作していると、検索ドキュメントの順序付け方法における小さな不一致に気付くことがあります。 これが発生する理由については、次のいくつかの説明があります。

原因 説明
データのボラティリティ ドキュメントを追加、変更、または削除すると、インデックス コンテンツは変動します。 インデックスの更新が徐々に処理されるに従って用語頻度は変化し、一致するドキュメントの検索スコアに影響を与えます。
複数のレプリカ 複数のレプリカを使用するサービスの場合、クエリは、各レプリカに対して並列に発行されます。 検索スコアを計算するために使用されるインデックス統計はレプリカごとに計算され、クエリ応答の中で結果がマージされ、順序付けられます。 レプリカのほとんどは互いのミラーですが、状態の小さな違いのために統計は異なる場合があります。 たとえば、あるレプリカで、他のレプリカからマージされた、その統計に寄与しているドキュメントが削除されることがあります。 通常、レプリカごとの統計の違いは、小さなインデックスの方がより顕著です。 この条件について詳しくは、容量計画のドキュメントの「概念: 検索単位、レプリカ、パーティション、シャード」をご覧ください。
同一のスコア 複数のドキュメントのスコアが同じである場合、それらはいずれも最初に表示される可能性があります。

セマンティック再ランカーによる並べ替え

セマンティック検索を使用している場合は、結果の並べ替え順序は "@search.rerankerScore" によって決まります。

"@search.rerankerScore" の範囲は 1 から 4.00 で、スコアが高いほどセマンティック一致が強いことを示します。

$orderby を使用した並べ替え

一貫した順序付けがアプリケーションの要件である場合は、フィールドに対して $orderbyを明示的に定義できます。 「並べ替え可能」としてインデックス付けされたフィールドのみを使用して、結果を並べ替えることができます。

$orderby でよく使用されるフィールドとしては、評価、日付、場所などがあります。 場所によるフィルター処理では、フィールド名に加えて、フィルター式で geo.distance() 関数を呼び出す必要があります。

数値フィールド (Edm.Double、Edm.Int32、Edm.Int64) は、数値順 (1、2、10、11、20 など) で並べ替えられます。

文字列フィールド (Edm.String、Edm.ComplexType サブフィールド) は、言語に応じて、ASCII 並べ替え順序または Unicode 並べ替え順序で並べ替えられます。 任意の型のコレクションを並べ替えることはできません。

  • 文字列フィールドの数値の内容は、アルファベット順に並べ替えられます (1、10、11、2、20)。

  • 大文字の文字列の方が小文字より前になります (APPLE、Apple、BANANA、Banana、apple、banana)。 テキスト ノーマライザーを割り当てて並べ替えの前にテキストを前処理し、この動作を変更することができます。 Cognitive Search の並べ替えはフィールドの分析されていないコピーに対して行われるため、フィールドで小文字トークナイザーを使用しても、並べ替え動作には影響しません。

  • 分音記号が前にある文字列は最後に表示されます (Äpfel、Öffnen、Üben)

スコアリング プロファイルを使用して関連性に影響を与える

順序の一貫性を高める別の方法として、カスタム スコアリング プロファイルを使用する方法があります。 スコアリング プロファイルを使用すると、検索結果内の項目のランク付けをより細かく制御できるため、特定のフィールドで見つかる一致を向上させることができます。 追加のスコアリング ロジックにより、各ドキュメントの検索スコアがさらに離れるため、レプリカ間のわずかな違いのオーバーライドに役立ちます。 このアプローチにはランク付けアルゴリズムをお勧めします。

検索結果の強調表示

検索結果の強調表示とは、結果内の一致する用語に適用され、一致が容易に見つかるようにするテキストの書式設定 (太字や黄色の強調表示など) を指します。 強調表示は、説明フィールドなど、一致が一目ではわかりにくい、長いコンテンツ フィールドに対して便利です。

強調表示は個々の用語に適用されることに注意してください。 フィールド全体の内容を強調表示する機能はありません。 フレーズを強調する場合は、引用符で囲まれたクエリ文字列で一致する用語 (またはフレーズ) を指定する必要があります。 この手法については、このセクションで詳しく説明します。

検索結果の強調表示の手順については、クエリ要求に関する記事で説明しています。 エンジンのクエリ拡張をトリガーするクエリ (あいまい検索やワイルドカード検索など) では、検索結果の強調表示のサポートが制限されています。

ヒットの強調表示の要件

  • フィールドは、Edm.String または Collection(Edm.String) である必要があります
  • フィールドは、検索可能である必要があります

要求で強調表示を指定する

強調表示された用語を返すには、クエリ要求に "highlight" パラメーターを含めます。 このパラメーターには、コンマ区切りのフィールド リストを設定します。

既定では、形式のマークアップは <em> ですが、highlightPreTaghighlightPostTag パラメーターを使用してタグをオーバーライドできます。 クライアントのコードで応答を処理します (たとえば、太字のフォントや黄色の背景の適用)。

POST /indexes/good-books/docs/search?api-version=2020-06-30 
    {  
      "search": "divine secrets",  
      "highlight": "title, original_title",
      "highlightPreTag": "<b>",
      "highlightPostTag": "</b>"
    }

既定では、Azure Cognitive Search によって、フィールドごとに最大 5 つの強調表示が返されます。 ダッシュとそれに続く整数を追加することで、この値を調整できます。 たとえば、"highlight": "description-10" とすると、"description" フィールドの一致するコンテンツで最大 10 個の強調表示された用語が返されます。

強調表示された結果

強調表示がクエリに追加されると、アプリケーションのコードでその構造をターゲットにできるように、応答の結果ごとに "@search.highlights" が含まれます。 "highlight" で指定されたフィールドのリストが応答に含まれます。

キーワード検索では、各用語が個別にスキャンされます。 "divine secrets" のクエリからは、いずれかの用語を含むすべてのドキュメントでの一致が返されます。

語句クエリに対する強調表示のスクリーンショット。

キーワード検索の強調表示

強調表示されたフィールド内では、すべての用語に書式が適用されます。 たとえば、"The Divine Secrets of the Ya-Ya Sisterhood" に対する一致では、それらが連続している場合でも、各用語に個別に書式設定が適用されます。

"@odata.count": 39,
"value": [
    {
        "@search.score": 19.593246,
        "@search.highlights": {
            "original_title": [
                "<em>Divine</em> <em>Secrets</em> of the Ya-Ya Sisterhood"
            ],
            "title": [
                "<em>Divine</em> <em>Secrets</em> of the Ya-Ya Sisterhood"
            ]
        },
        "original_title": "Divine Secrets of the Ya-Ya Sisterhood",
        "title": "Divine Secrets of the Ya-Ya Sisterhood"
    },
    {
        "@search.score": 12.779835,
        "@search.highlights": {
            "original_title": [
                "<em>Divine</em> Madness"
            ],
            "title": [
                "<em>Divine</em> Madness (Cherub, #5)"
            ]
        },
        "original_title": "Divine Madness",
        "title": "Divine Madness (Cherub, #5)"
    },
    {
        "@search.score": 12.62534,
        "@search.highlights": {
            "original_title": [
                "Grave <em>Secrets</em>"
            ],
            "title": [
                "Grave <em>Secrets</em> (Temperance Brennan, #5)"
            ]
        },
        "original_title": "Grave Secrets",
        "title": "Grave Secrets (Temperance Brennan, #5)"
    }

語句検索の強調表示

複数の用語が二重引用符で囲まれている語句検索であっても、語句全体の書式設定が適用されます。 次の例は同じクエリですが、"divine search" が引用符で囲まれた語句として送信されている点が異なります (Postman などの一部のクライアントでは、内部の引用符を円記号 \" でエスケープする必要があります)。

POST /indexes/good-books/docs/search?api-version=2020-06-30 
    {  
      "search": "\"divine secrets\"",,
      "select": "title,original_title",
      "highlight": "title",
      "highlightPreTag": "<b>",
      "highlightPostTag": "</b>",
      "count": true
    }

条件で両方の用語が指定されているため、検索インデックスで一致するのは 1 つだけです。 上記のクエリに対する応答は次のようになります。

{
    "@odata.count": 1,
    "value": [
        {
            "@search.score": 19.593246,
            "@search.highlights": {
                "title": [
                    "<b>Divine</b> <b>Secrets</b> of the Ya-Ya Sisterhood"
                ]
            },
            "original_title": "Divine Secrets of the Ya-Ya Sisterhood",
            "title": "Divine Secrets of the Ya-Ya Sisterhood"
        }
    ]
}

古いサービスでの語句の強調表示

2020 年 7 月 15 日より前に作成された検索サービスでは、語句クエリに対して異なる強調表示エクスペリエンスが実装されています。

次の例では、引用符で囲まれた語句 "super bowl" を含むクエリ文字列が想定されています。 2020 年 7 月より前は、語句内のすべての用語が強調表示されます。

"@search.highlights": {
    "sentence": [
        "The <em>super</em> <em>bowl</em> is <em>super</em> awesome with a <em>bowl</em> of chips"
   ]

2020 年 7 月以降に作成された検索サービスの場合、完全な語句のクエリに一致する語句だけが "@search.highlights" で返されます。

"@search.highlights": {
    "sentence": [
        "The <em>super</em> <em>bowl</em> is super awesome with a bowl of chips"
   ]

次のステップ

クライアントの検索ページをすばやく生成するには、次のオプションを検討してください。

  • アプリケーション ジェネレーター。ポータルで、検索バー、ファセット ナビゲーション、画像を含む結果領域を備えた HTML ページを作成します。

  • C# での最初のアプリの作成に関するページは、機能するクライアントを構築するチュートリアルとコード サンプルです。 サンプル コードは、ページ分割されたクエリ、検索結果の強調表示、並べ替えを示しています。

  • Web アプリに検索を追加する」は、ユーザー エクスペリエンスに React JavaScript ライブラリを使用するチュートリアルとコード サンプルです。 アプリは、Azure Static Web Apps を使用してデプロイされます。