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

出力フィールド マッピングが強調されているインデクサー ステージの図。

この記事では、出力フィールドのマッピングを設定することで、スキルセットの処理中に生成されたメモリ内のデータと、検索インデックス内のターゲット フィールド間のデータ パスを定義する方法を説明します。 インデクサーの実行中、スキルによって生成された情報はメモリ内のみにあります。 この情報を検索インデックスに保持するには、データの送信先をインデクサーに指示する必要があります。

出力フィールド マッピングはインデクサーで定義され、次の要素を含んでいます。

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

逐語的なソース フィールドとインデックス フィールドの間のパスをマップする fieldMappings 定義とは対照的に、outputFieldMappings 定義はメモリ内のエンリッチメントを検索インデックス内のフィールドにマップします。

前提条件

  • インデクサー、インデックス、データ ソース、スキルセット。

  • インデックス フィールドは、シンプルなフィールドまたは最上位レベルのフィールドである必要があります。 複合型に出力することはできません。 ただし、複合型がある場合は、出力フィールド定義を使って複合型の部分をフラット化すると、検索インデックス内のコレクションに送信できます。

出力フィールド マッピングを使用するタイミング

インデックスに必要な新しい情報を作成するスキルセットがインデクサ-にアタッチされている場合は、出力フィールド マッピングが必要です。 以下に例を示します。

  • 埋め込みスキルのベクター
  • 画像スキルからの光学式文字認識 (OCR) テキスト
  • エンティティ認識スキルの場所、組織、またはユーザー

出力フィールドのマッピングは、次の場合にも使用できます。

  • 生成されたコンテンツの複数のコピー作成 (1 対多の出力フィールド マッピング)。

  • ソース ドキュメントの複合型をフラット化します。 たとえば、ソース ドキュメントに複合型 (複数パートの住所など) があり、市区町村名のみが必要な場合を考えます。 出力フィールド マッピングを使用して入れ子になったデータ構造をフラット化した後、出力フィールド マッピングを使用すると、検索インデックス内の文字列コレクションに出力を送信できます。

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

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

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

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

ヒント

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

  1. インデクサーの作成またはインデクサーの作成または更新、または Azure SDK の同等のメソッドを参照してください。 インデクサー定義の例を次に示します。

    {
       "name": "myindexer",
       "description": null,
       "dataSourceName": "mydatasource",
       "targetIndexName": "myindex",
       "schedule": { },
       "parameters": { },
       "fieldMappings": [],
       "outputFieldMappings": [],
       "disabled": false,
       "encryptionKey": { }
     }
    
  2. outputFieldMappings 配列に値を入力してマッピングを指定します。 フィールド マッピングは、3 つの部分で構成されます。

    "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 省略可能。 インデクサーでサポートされるマッピング関数によって提供される処理を別途追加します。 エンリッチメント ノードの場合、エンコードとデコードが最も一般的に使用される関数です。
  3. targetFieldName は、常に検索インデックス内のフィールドの名前です。

  4. sourceFieldName は、エンリッチメントされたドキュメント内のノードへのパスです。 スキルの出力です。 パスは常に /document で始まり、BLOB からインデックスを作成する場合、パスの 2 番目の要素は /content になります。 3 番目の要素は、スキルによって生成される値です。 詳細と例については、「Azure AI Search スキルセットでのエンリッチメントの参照」を参照してください。

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

    {
        "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"
            }
        ]
    }
    
  5. フィールドの内容をインデックスに格納する前に、これ変換するために必要なマッピング関数を割り当てます。 エンリッチメント ノードの場合、エンコードとデコードが最も一般的に使用される関数です。

一対多出力フィールドのマッピング

出力フィールド マッピングを使用して、単一のソース フィールドを検索インデックス内の複数のフィールドにルーティングできます。 これは、比較テストのために、または異なる属性を持つフィールドが必要な場合に行うことができます。

ベクター フィールドの埋め込みを生成するスキルセットと、アルゴリズムと圧縮設定によって異なる複数のベクター フィールドを持つインデックスがあると考えてください。 インデクサー内で、埋め込みスキルの出力を検索インデックス内の複数のベクター フィールドにマップします。

"outputFieldMappings": [
    { "sourceFieldName" : "/document/content/text_vector", "targetFieldName" : "vector_hnsw" }, 
    { "sourceFieldName" : "/document/content/text_vector", "targetFieldName" : "vector_eknn" },
    { "sourceFieldName" : "/document/content/text_vector", "targetFieldName" : "vector_narrow" }, 
    { "sourceFieldName" : "/document/content/text_vector", "targetFieldName" : "vector_no_stored" },
    { "sourceFieldName" : "/document/content/text_vector", "targetFieldName" : "vector_scalar" }       
  ]

ソース フィールドのパスはスキル出力です。 この例では、出力は text_vector です。 ターゲット名は省略可能なプロパティです。 出力マッピングにターゲット名を指定しない場合、パスは embedding になります (より正確には /document/content/embedding)。

{
  "name": "test-vector-size-ss",  
  "description": "Generate embeddings using AOAI",
  "skills": [
    {
      "@odata.type": "#Microsoft.Skills.Text.AzureOpenAIEmbeddingSkill",
      "name": "#1",
      "description": null,
      "context": "/document/content",
      "resourceUri": "https://my-demo-eastus.openai.azure.com",
      "apiKey": null,
      "deploymentId": "text-embedding-ada-002",
      "dimensions": 1536,
      "modelName": "text-embedding-ada-002",
      "inputs": [
        {
          "name": "text",
          "source": "/document/content"
        }
      ],
      "outputs": [
        {
          "name": "embedding",
          "targetName": "text_vector"
        }
      ],
      "authIdentity": null
    }
  ]
}

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

ソース データが入れ子や階層構造の 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": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
      "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": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
      "palette": "primary colors",
      "color_names": [
        "blue",
        "red",
        "yellow"
      ],
      "color_mediums": [
        "[\"acrylic\",\"oil\",\"pastel\"]",
        "[\"acrylic\",\"pastel\",\"watercolor\"]",
        "[\"acrylic\",\"watercolor\"]"
      ]
    }
  ]
}