Azure AI Search でインデックスを更新または再構築する

この記事では、増分インデックス作成によるスキーマの変更またはコンテンツの変更を使用して Azure AI Search の既存のインデックスを更新する方法について説明します。 再構築が必要な状況について説明し、進行中のクエリ要求に対する再構築の影響を軽減するための推奨事項を提供します。

アクティブな開発中は、インデックス デザインを反復処理するときにインデックスを削除して再構築するのが一般的です。 ほとんどの開発者は、小規模の代表的なデータ サンプルを使用して、インデックスの再作成が迅速に行われるようにします。

既に運用環境で使用されているアプリケーションのスキーマを変更する場合は、既存のインデックスと並行して実行する新しいインデックスを作成してテストすることをお勧めします。 index エイリアスを使用して、アプリケーション コードの変更を回避しながら新しいインデックスを入れ替えます。

コンテンツを更新する

ソース データの変更に対する増分インデックス作成とインデックスの同期は、ほとんどの検索アプリケーションの基礎となります。 このセクションでは、検索インデックス内のフィールドの内容を更新するワークフローについて説明します。

  1. ドキュメントの読み込みには、Documents - Index (REST) または Azure SDK 内の同等の API と同じ手法を使用します。 インデックス作成手法の詳細については、「ドキュメントを読み込む」をご覧ください。

  2. @search.action パラメーターを設定して、既存のドキュメントへの影響を判断します。

    アクション 効果
    delete インデックスから全体のドキュメントを削除します。 個々のフィールドを削除する場合は、代わりに merge を使い、問題のフィールドを null に設定します。 削除されたドキュメントとフィールドは、インデックス内の領域をすぐに解放しません。 数分ごとに、バックグラウンド プロセスによって物理的な削除が実行されます。 ポータルまたは API を使用してインデックス統計を返す場合でも、削除がポータルと API に反映されるまでに少しの遅延が発生する可能性があります。
    merge 既に存在するドキュメントを更新し、ドキュメントが見つからない場合は失敗します。 マージは既存の値を置き換えます。 そのため、Collection(Edm.String) 型のフィールドなど、複数の値を含むコレクション フィールドは必ず確認してください。 たとえば、tags フィールドの値が ["budget"] で始まり、値 ["economy", "pool"] でマージを実行した場合、tags フィールドの最終値は ["economy", "pool"] になります。 ["budget", "economy", "pool"] にはなりません。
    mergeOrUpload ドキュメントが存在する場合は merge、ドキュメントが新しい場合は upload と同じように動作します。 これは、増分更新の最も一般的なアクションです。
    upload "upsert" と同様に、ドキュメントが新しい場合は挿入され、存在する場合は更新または置換されます。 インデックスに必要な値がドキュメントにない場合、ドキュメント フィールドの値は null に設定されます。
  3. 更新をポストします。

クエリは引き続き実行されますが、既存のフィールドを更新または削除する場合は、結果の混合とスロットリングの発生率が高くなる可能性があります。

増分インデックス作成のヒント

  • インデクサーは増分インデックス作成を自動化します。 インデクサーが利用可能でデータ ソースが変更の追跡をサポートしている場合は、インデクサーを定期的なスケジュールで実行して、検索可能なコンテンツを追加、更新、または上書きし、外部データと同期させることができます。

  • プッシュ API を使ってインデックス呼び出しを直接行う場合は、検索アクションとして mergeOrUpload を使います。

  • ペイロードには、追加、更新、または削除するすべてのドキュメントのキーまたは識別子が含まれている必要があります。

  • インデックスにベクトル フィールドが含まれていて、stored プロパティを false に設定する場合は、値が変更されていない場合でも、部分ドキュメント更新でベクトルを必ず提供してください。 stored を false に設定すると、インデックス再作成操作でベクトルが削除されるという副作用があります。 ドキュメント ペイロードでベクトルを提供すると、このようなことが起きなくなります。

  • 複合型の簡易フィールドとサブフィールドの内容を更新するには、変更するフィールドのみを一覧表示します。 たとえば、説明フィールドのみを更新しなければならない場合、ペイロードはドキュメント キーと変更された説明で構成されている必要があります。 他のフィールドを省略することで、既存の値が保持されます。

  • インライン変更を文字列コレクションにマージするには、値全体を指定します。 前のセクションの tags フィールドの例を思い出してください。 新しい値によってフィールド全体の古い値が上書きされ、フィールドの内容内でマージは行われません。

次の REST API の例でこれらのヒントを示します。

### Get Secret Point Hotel by ID
GET  {{baseUrl}}/indexes/hotels-vector-quickstart/docs('1')?api-version=2024-07-01  HTTP/1.1
    Content-Type: application/json
    api-key: {{apiKey}}

### Change the description, city, and tags for Secret Point Hotel
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/search.index?api-version=2024-07-01  HTTP/1.1
  Content-Type: application/json
  api-key: {{apiKey}}

    {
        "value": [
            {
            "@search.action": "mergeOrUpload",
            "HotelId": "1",
            "Description": "I'm overwriting the description for Secret Point Hotel.",
            "Tags": ["my old item", "my new item"],
            "Address": {
                "City": "Gotham City"
                }
            }
        ]
    }
       
### Retrieve the same document, confirm the overwrites and retention of all other values
GET  {{baseUrl}}/indexes/hotels-vector-quickstart/docs('1')?api-version=2024-07-01  HTTP/1.1
    Content-Type: application/json
    api-key: {{apiKey}}

インデックス スキーマを変更する

インデックス スキーマは、検索サービスで作成された物理データ構造を定義するため、完全な再構築を行わずに行うことができるスキーマの変更はあまりありません。 次の一覧は、既存のインデックスにシームレスに導入できるスキーマの変更を列挙したものです。 一般に、一覧には、クエリの実行中に使用される新しいフィールドと機能が含まれています。

  • 新しいフィールドの追加
  • 既存のフィールドに retrievable 属性を設定する
  • 既存の indexAnalyzer を持つフィールドの searchAnalyzer を更新する
  • 新しいアナライザー定義をインデックスに追加する (新しいフィールドに適用可能)
  • スコアリング プロファイルを追加、更新、削除する
  • CORS の設定を追加、更新、削除する
  • synonymMap を追加、更新、削除する
  • セマンティック構成を追加、更新、削除する

操作の順序は次のとおりです。

  1. インデックスの定義を取得します

  2. 以前の一覧からの更新を使用してスキーマを変更します。

  3. 検索サービスで、インデックス スキーマを更新します。

  4. 新しいフィールドを追加した場合、変更したスキーマと一致するようにインデックスの内容を更新します。 その他の変更については、インデックスが作成された既存の内容がそのまま使用されます。

新しいフィールドを含めるようにインデックス スキーマを更新すると、インデックス内の既存のドキュメントにはそのフィールドに null 値が割り当てられます。 次のインデックス作成ジョブでは、外部ソース データからの値が、Azure AI 検索によって追加された null に置き換えられます。

更新中にクエリが中断されることはありませんが、更新が反映されるとクエリ結果は変わります。

インデックスの削除と再構築

一部の変更では、インデックスをドロップして再構築し、現在のインデックスを新しいインデックスに置き換える必要があります。

アクション 説明
フィールドの削除 フィールドのすべてのトレースを物理的に削除するには、インデックスを再構築する必要があります。 実務上すぐに再構築しない場合は、古いフィールドからアクセスをリダイレクトするようにアプリケーション コードを変更することも、searchFieldsselect クエリ パラメータを使用して、検索されて返されるフィールドを選択することもできます。 物理的には、そのフィールドを無視するスキーマを適用すると、次に再構築が行われるまでフィールドの定義と内容はインデックスに維持されます。
フィールド定義を変更する フィールドの名前、データ型、または特定のインデックス属性 (検索可能、フィルター可能、ソート可能、ファセット可能) を変更する場合は、完全な再構築が必要です。
アナライザーをフィールドに割り当てる アナライザー はインデックスで定義され、フィールドに割り当てられ、インデックス作成中に呼び出されて、トークンがどのように作成されるかを通知します。 新しいアナライザー定義はいつでもインデックスに追加できますが、アナライザーを "割り当てる" ことができるのはフィールドの作成時のみです。 これは analyzerindexAnalyzer の両方のプロパティに当てはまります。 searchAnalyzer プロパティは例外です (このプロパティは既存のフィールドに割り当てることができます)。
インデックス内のアナライザー定義を更新または削除する インデックス全体を再構築しない限り、インデックス内にある既存のアナライザー構成 (アナライザー、トークナイザー、トークン フィルター、または文字フィルター) を削除または変更することはできません。
サジェスタにフィールドを追加する フィールドが既に存在していて、それを Suggesters コンストラクトに追加する場合は、インデックスを再構築します。
階層を切り替える インプレース アップグレードはサポートされていません。 容量を増やす必要がある場合は、新しいサービスを作成し、インデックスを最初から再構築します。 このプロセスを自動化するために、index-backup-restoreのサンプル コード を使用します、この Azure AI Search .NET サンプル リポジトリ内にあります。 このアプリでは、インデックスを一連の JSON ファイルにバックアップし、指定した検索サービスでインデックスを再作成します。

操作の順序は次のとおりです。

  1. 将来参照する必要が出てきた場合に備えて、または新しいバージョンの基礎として使用するために、インデックス定義を取得します

  2. バックアップと復元のソリューションを使用して、インデックス内容のコピーを保持することを検討してください。 C#Python にはソリューションがあります。 Python バージョンは最新の状態であるため、お勧めします。

    検索サービスの容量がある場合は、新しいインデックスを作成してテストする間、既存のインデックスを残しておきます。

  3. 既存のインデックスを削除します。 そのインデックスを対象とするすべてのクエリがすぐに削除されます。 インデックスの削除は元に戻すことができません。フィールド コレクションやその他の構造の物理ストレージが破壊されます。

  4. 要求の本文に変更または修正されたフィールド定義と構成を含む、変更されたインデックスをポストします。

  5. 外部ソースからドキュメントでインデックスを読み込みます。 ドキュメントは、新しいスキーマのフィールド定義と構成を使用してインデックスが作成されます。

インデックスを作成すると、インデックス スキーマのフィールドごとに物理ストレージが割り当てられ、検索可能なフィールドごとの逆インデックスと、ベクター フィールドごとのベクター インデックスが作成されます。 検索できないフィールドは、フィルターまたは式で使用できますが、逆インデックスを持たないため、フルテキスト検索やあいまい検索はできません。 インデックスの再構築では、これらの逆インデックスとベクター フィールドが削除されて、指定したインデックス スキーマに基づいて再作成されます。

ワークロードの分散

インデックス作成はバックグラウンドでは実行されませんが、インデックス作成ジョブと進行中のクエリのバランスは、検索サービスによって調整されます。 インデックス作成中、クエリがタイムリーに完了するようポータルでクエリ要求を監視できます。

インデックス作成のワークロードにより、許容できないレベルのクエリ待機時間が発生する場合は、パフォーマンス分析を実施し、潜在的な軽減策についてこれらのパフォーマンスに関するヒントを確認してください。

更新プログラムの確認

最初のドキュメントが読み込まれたらすぐに、インデックスのクエリを始めることができます。 ドキュメントの ID がわかっている場合、Lookup Document REST API では特定のドキュメントが返されます。 さらに範囲の広いテストでは、インデックスが完全に読み込まれるまで待ってから、クエリを使用して表示されるはずのコンテキストを確認する必要があります。

Search エクスプローラーまたは REST クライアントを使用して、更新されたコンテンツをチェックできます。

フィールドを追加、または名前変更した場合は、$select を使用してこのフィールド search=*&$select=document-id,my-new-field,some-old-field&$count=true を返します。

Azure portal には、インデックス サイズとベクター インデックス サイズが用意されています。 これらの値はインデックスの更新後に確認できます。ただし、サービスが変更を処理する際に若干の遅延が発生すること、およびポータルの更新速度を考慮することを忘れないでください。これは数分です。

孤立したドキュメントの削除

Azure AI Search では、ドキュメント レベルの操作がサポートされているため、特定のドキュメントを別個に検索、更新、削除できます。 次の例は、ドキュメントを削除する方法を示しています。

ドキュメントを削除しても、インデックス内の領域はすぐには解放されません。 数分ごとに、バックグラウンド プロセスによって物理的な削除が実行されます。 ポータルまたは API を使用してインデックス統計を返す場合でも、削除がポータルと API メトリックに反映されるまでに少しの遅延が予想されます。

  1. ドキュメント キーであるフィールドを特定します。 ポータルで、各インデックスのフィールドを表示できます。 ドキュメント キーは文字列フィールドであり、見つけやすくするためにキー アイコンで示されます。

  2. ドキュメント キー フィールドの値 search=*&$select=HotelId を確認します。 単純な文字列は分かりやすいですが、インデックスで base-64 でエンコードされたフィールドが使用されている場合、または検索ドキュメントが parsingMode 設定から生成されている場合は、馴染みのない値を操作する可能性があります。

  3. ドキュメントを参照して、ドキュメント ID の値を確認し、そのコンテンツを確認してから削除します。 要求でキーまたはドキュメント ID を指定します。 次の例は、Hotels サンプル インデックスの単純な文字列と、cog-search-demo インデックスの metadata_storage_path キーの base-64 でエンコードされた文字列を示しています。

    GET https://[service name].search.windows.net/indexes/hotel-sample-index/docs/1111?api-version=2024-07-01
    
    GET https://[service name].search.windows.net/indexes/cog-search-demo/docs/aHR0cHM6Ly9oZWlkaWJsb2JzdG9yYWdlMi5ibG9iLmNvcmUud2luZG93cy5uZXQvY29nLXNlYXJjaC1kZW1vL2d1dGhyaWUuanBn0?api-version=2024-07-01
    
  4. 削除 @search.action を使用してドキュメントを削除し、検索インデックスから削除します。

    POST https://[service name].search.windows.net/indexes/hotels-sample-index/docs/index?api-version=2024-07-01
    Content-Type: application/json   
    api-key: [admin key] 
    {  
      "value": [  
        {  
          "@search.action": "delete",  
          "id": "1111"  
        }  
      ]  
    }
    

関連項目