エンリッチされた出力を Azure AI Search の検索インデックス内のフィールドにマッピングする

インデクサーのステージ

スキルセットの処理中に作成されるメモリ内のデータ構造と検索インデックス内のターゲット フィールドとの間のデータ パスは、"出力フィールドのマッピング" によって定義されます。この記事では、このマッピングを設定する方法について説明します。 出力フィールド マッピングはインデクサーで定義され、次の要素を含んでいます。

"outputFieldMappings": [
  {
    "sourceFieldName": "document/path-to-a-node-in-an-enriched-document",
    "targetFieldName": "some-search-field-in-an-index",
    "mappingFunction": null
  }
],

2 つの物理データ構造間のパスをマッピングする fieldMappings 定義とは対照的に、outputFieldMappings 定義はメモリ内エンリッチメントを検索インデックス内のフィールドにマッピングするものです。

出力フィールド マッピングが必要になるのは、テキスト翻訳やキー フレーズ抽出など、新しい情報を作成するスキルセットがインデクサーに関連付けられている場合です。 インデクサーの実行中、AI によって生成された情報はメモリ内にしか存在しません。 この情報を検索インデックスに保持するには、データの送信先をインデクサーに指示する必要があります。

出力フィールド マッピングは、ソース ドキュメントの複合型から特定のノードを取得する際に使用することもできます。 たとえば、マルチパートの "FullName" プロパティに "FullName/LastName" だけを含める場合があります。 複合構造全体が不要であれば、入れ子になったデータ構造内の個々のノードをフラット化し、出力フィールド マッピングを使用して、出力を検索インデックス内の文字列コレクションに送信できます。

出力フィールド マッピングの適用先は次のとおりです。

  • スキルによって作成された、またはインデクサーによって抽出されたメモリ内コンテンツ。 ソース フィールドは、エンリッチ済みドキュメント内のノードです。

  • 検索インデックス。 データの送信先がナレッジ ストアである場合は、データ パスの構成にプロジェクションを使用します。 ベクトル フィールドを設定する場合、出力フィールド マッピングは使用されません。

出力フィールド マッピングは、スキルセットの実行後、または関連するスキルセットがない場合はドキュメント解析後に適用されます。

出力フィールド マッピングを定義する

出力フィールド マッピングは、インデクサーの定義の中の outputFieldMappings 配列に追加され、通常は fieldMappings 配列の後に配置されます。 出力フィールド マッピングは、3 つの部分で構成されます。

"fieldMappings": []
"outputFieldMappings": [
  {
    "sourceFieldName": "/document/path-to-a-node-in-an-enriched-document",
    "targetFieldName": "some-search-field-in-an-index",
    "mappingFunction": null
  }
],
プロパティ 説明
sourceFieldName 必須。 エンリッチされたコンテンツへのパスを指定します。 たとえば、/document/content などです。 パスの構文と例については、Azure AI Search スキルセットでのエンリッチメントの参照に関する記事を参照してください。
targetFieldName 省略可能。 エンリッチされたコンテンツの送信先となる検索フィールドを指定します。 ターゲット フィールドは、最上位の単純なフィールドまたはコレクションである必要があります。 複合型のサブフィールドへのパスにすることはできません。 複雑な構造から特定のノードを取得したい場合は、メモリ内で個々のノードをフラット化してから、その出力をインデックス内の文字列コレクションに送信してください。
mappingFunction 省略可能。 インデクサーでサポートされるマッピング関数によって提供される処理を別途追加します。 エンリッチメント ノードの場合、エンコードとデコードが最も一般的に使用される関数です。

出力フィールド マッピングは、REST API または Azure SDK を使用して定義できます。

ヒント

データ インポート ウィザードによって作成されたインデクサーには、ウィザードによって生成された出力フィールド マッピングが含まれています。 例が必要な場合は、データ ソースに対してウィザードを実行して、レンダリングされた定義を確認してください。

API のバージョンにかかわらず、インデクサーの作成 (REST) またはインデクサーの更新 (REST) を使用します。

この例では、BLOB のコンテンツ プロパティから抽出したエンティティ ラベルとセンチメント ラベルを検索インデックス内のフィールドに追加しています。

PUT https://[service name].search.windows.net/indexers/myindexer?api-version=[api-version]
Content-Type: application/json
api-key: [admin key]
{
    "name": "myIndexer",
    "dataSourceName": "myDataSource",
    "targetIndexName": "myIndex",
    "skillsetName": "myFirstSkillSet",
    "fieldMappings": [],
    "outputFieldMappings": [
        {
            "sourceFieldName": "/document/content/organizations/*/description",
            "targetFieldName": "descriptions",
            "mappingFunction": {
                "name": "base64Decode"
            }
        },
        {
            "sourceFieldName": "/document/content/organizations",
            "targetFieldName": "orgNames"
        },
        {
            "sourceFieldName": "/document/content/sentiment",
            "targetFieldName": "sentiment"
        }
    ]
}

出力フィールド マッピングごとに、強化されたドキュメント ツリー内のデータの場所 (sourceFieldName) の名前を設定してから、インデックスで参照されるフィールド (targetFieldName) の名前を設定します。 フィールドの内容をインデックスに格納する前に、これ変換するために必要なマッピング関数を割り当てます。

複雑な構造を文字列コレクションにフラット化する

ソース データが入れ子や階層構造の JSON で構成されている場合、フィールド マッピングを使用してデータ パスを設定することはできません。 完全にインポートするためには、各レベルのソース データ構造が検索インデックスに正確に反映されている必要があります。

このセクションでは、ソース側とターゲット側の両方で複雑なドキュメントの 1 対 1 のリフレクションを生成するインポート プロセスについて説明します。 次に、同じソース ドキュメントを使用して個々のノードを取得し、文字列コレクションにフラット化する方法を紹介します。

入れ子になった JSON を含む Azure Cosmos DB のドキュメントの例がこちらです。

{
   "palette":"primary colors",
   "colors":[
      {
         "name":"blue",
         "medium":[
            "acrylic",
            "oil",
            "pastel"
         ]
      },
      {
         "name":"red",
         "medium":[
            "acrylic",
            "pastel",
            "watercolor"
         ]
      },
      {
         "name":"yellow",
         "medium":[
            "acrylic",
            "watercolor"
         ]
      }
   ]
}

前出のソース ドキュメントの完全なインデックスを作成したい場合、フィールド名、レベル、型が複合型として反映されたインデックス定義を作成することになります。 検索インデックスでは、複合型のフィールド マッピングはサポートされないため、インデックス定義に対してソース ドキュメントを正確に反映する必要があります。

{
  "name": "my-test-index",
  "defaultScoringProfile": "",
  "fields": [
    { "name": "id", "type": "Edm.String", "searchable": false, "retrievable": true, "key": true},
    { "name": "palette", "type": "Edm.String", "searchable": true, "retrievable": true },
    { "name": "colors", "type": "Collection(Edm.ComplexType)",
      "fields": [
        {
          "name": "name",
          "type": "Edm.String",
          "searchable": true,
          "retrievable": true
        },
        {
          "name": "medium",
          "type": "Collection(Edm.String)",
          "searchable": true,
          "retrievable": true,
        }
      ]
    }
  ]
}

インポートを実行するインデクサー定義の例を次に示します (フィールド マッピングとスキルセットがないことに注目してください)。

{
  "name": "my-test-indexer",
  "dataSourceName": "my-test-ds",
  "skillsetName": null,
  "targetIndexName": "my-test-index",

  "fieldMappings": [],
  "outputFieldMappings": []
}

その結果を示したのが、次のサンプル検索ドキュメントです。Azure Cosmos DB 側の元の内容と似ています。

{
  "value": [
    {
      "@search.score": 1,
      "id": "240a98f5-90c9-406b-a8c8-f50ff86f116c",
      "palette": "primary colors",
      "colors": [
        {
          "name": "blue",
          "medium": [
            "acrylic",
            "oil",
            "pastel"
          ]
        },
        {
          "name": "red",
          "medium": [
            "acrylic",
            "pastel",
            "watercolor"
          ]
        },
        {
          "name": "yellow",
          "medium": [
            "acrylic",
            "watercolor"
          ]
        }
      ]
    }
  ]
}

検索インデックスにレンダリングする方法はもう 1 つあります。ソース側の入れ子構造に含まれる個々のノードを、検索インデックス側の文字列コレクションにフラット化する方法です。

このタスクを実行するためには、メモリ内のノードをインデックス内の文字列コレクションにマッピングする outputFieldMappings が必要です。 出力フィールド マッピングは主にスキル出力に適用されますが、"ドキュメント解析" で、インデクサーがソース ドキュメントを開いてメモリに読み取った後に、それらを使用してノードを解決することもできます。

以下に示したのは、文字列コレクションを使用して、フラット化された出力を受け取るインデックス定義の例です。

{
  "name": "my-new-flattened-index",
  "defaultScoringProfile": "",
  "fields": [
    { "name": "id", "type": "Edm.String", "searchable": false, "retrievable": true, "key": true },
    { "name": "palette", "type": "Edm.String", "searchable": true, "retrievable": true },
    { "name": "color_names", "type": "Collection(Edm.String)", "searchable": true, "retrievable": true },
    { "name": "color_mediums", "type": "Collection(Edm.String)", "searchable": true, "retrievable": true}
  ]
}

以下に示したのは、入れ子になった JSON を、outputFieldMappings を使用して文字列コレクション フィールドに関連付けるインデクサー定義の例です。 スキルセットはありませんが、ソース フィールドで、エンリッチメント ノードにパス構文が使用されていることに注目してください。 エンリッチされたドキュメントは、システム内でドキュメント解析中に作成されます。つまり、ドキュメントの解析時に各ドキュメント ツリーのノードが存在する限り、それらのノードにアクセスすることができます。

{
  "name": "my-test-indexer",
  "dataSourceName": "my-test-ds",
  "skillsetName": null,
  "targetIndexName": "my-new-flattened-index",
  "parameters": {  },
  "fieldMappings": [   ],
  "outputFieldMappings": [
    {
       "sourceFieldName": "/document/colors/*/name",
       "targetFieldName": "color_names"
    },
    {
       "sourceFieldName": "/document/colors/*/medium",
       "targetFieldName": "color_mediums"
    }
  ]
}

上記の定義の結果は次のとおりです。 このケースでは、構造を簡略化した結果、コンテキストが失われています。 特定の色 (colors) とそれを利用できる表現手段 (medium) との関連付けはなくなりました。 ただし、シナリオによっては、次に示すような結果がちょうど目的に適う場合もあるでしょう。

{
  "value": [
    {
      "@search.score": 1,
      "id": "240a98f5-90c9-406b-a8c8-f50ff86f116c",
      "palette": "primary colors",
      "color_names": [
        "blue",
        "red",
        "yellow"
      ],
      "color_mediums": [
        "[\"acrylic\",\"oil\",\"pastel\"]",
        "[\"acrylic\",\"pastel\",\"watercolor\"]",
        "[\"acrylic\",\"watercolor\"]"
      ]
    }
  ]
}

関連項目