Compartilhar via


Mapear a saída enriquecida para campos em um índice de pesquisa no Azure AI Search

Diagrama dos estágios do indexador com mapeamentos de campo de saída realçados.

Este artigo explica como configurar mapeamentos de campo de saída, definindo um caminho de dados entre os dados na memória gerados durante o processamento de conjunto de habilidades e os campos de destino em um índice de pesquisa. Durante a execução do indexador, as informações geradas pelas habilidades existem apenas na memória. Para manter essas informações em um índice de pesquisa, é necessário informar ao indexador para onde enviar os dados.

Um mapeamento de campo de saída é definido em um indexador e tem os seguintes elementos:

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

Em contraste com uma definição de fieldMappings que mapeia um caminho entre campos de origem verbatim e campos de índice, uma definição de outputFieldMappings mapeia enriquecimentos na memória para campos em um índice de pesquisa.

Pré-requisitos

  • Indexador, índice, fonte de dados e conjunto de habilidades.

  • Os campos de índice devem ser campos simples ou de nível superior. Não é possível gerar saída para um tipo complexo. No entanto, se você tiver um tipo complexo, poderá usar uma definição de campo de saída para nivelar partes do tipo complexo e enviá-las para uma coleção em um índice de pesquisa.

Quando usar um mapeamento de campo de saída

Mapeamentos de campos de saída são necessários se seu indexador tiver um conjunto de habilidades anexado que crie as informações que você deseja no seu índice. Os exemplos incluem:

  • Vetores de habilidades de inserção
  • Texto de OCR (reconhecimento óptico de caracteres) das habilidades de imagem
  • Locais, organizações ou pessoas das habilidades de reconhecimento de entidades

Os mapeamentos de campos de saída também podem ser usados para:

  • Criar várias cópias do conteúdo gerado (mapeamentos de campo de saída de um para muitos).

  • Nivelar o tipo complexo de um documento de origem. Por exemplo, suponha que os documentos de origem tenham um tipo complexo, como um endereço com várias partes, e você queira apenas a cidade. Você pode usar um mapeamento de campo de saída para nivelar uma estrutura de dados aninhada e, em seguida, usar um mapeamento de campo de saída para enviar a saída para uma coleção de cadeias de caracteres em seu índice de pesquisa.

Os mapeamentos de campo de saída se aplicam somente a índices de pesquisa. Se você estiver preenchendo um repositório de conhecimento, use projeções para a configuração do caminho de dados.

Definir um mapeamento de campo de saída

Mapeamentos de campo de saída são adicionados à outputFieldMappings matriz em uma definição de indexador, normalmente colocada após a matriz fieldMappings. Um mapeamento de campo de saída é composto por três partes.

Use o portal, a API REST ou um SDK do Azure para definir mapeamentos de campo de saída.

Dica

Os indexadores criados pelo assistente de importação de dados incluem mapeamentos de campo de saída gerados pelo assistente. Se precisar de exemplos, execute o assistente em sua fonte de dados para ver os mapeamentos de campo de saída no indexador.

  1. Use Criar Indexador ou Criar ou Atualizar Indexador ou um método equivalente em um SDK do Azure. Veja a seguir um exemplo de definição de indexador.

    {
       "name": "myindexer",
       "description": null,
       "dataSourceName": "mydatasource",
       "targetIndexName": "myindex",
       "schedule": { },
       "parameters": { },
       "fieldMappings": [],
       "outputFieldMappings": [],
       "disabled": false,
       "encryptionKey": { }
     }
    
  2. Preencha a matriz outputFieldMappings para especificar os mapeamentos. Um mapeamento de campo é composto por três partes.

    "outputFieldMappings": [
      {
        "sourceFieldName": "/document/path-to-a-node-in-an-enriched-document",
        "targetFieldName": "some-search-field-in-an-index",
        "mappingFunction": null
      }
    ]
    
    Propriedade Descrição
    sourceFieldName Obrigatório. Especifica um caminho para conteúdo enriquecido. Um exemplo pode ser /document/content. Consulte Enriquecimentos de referência em um conjunto de habilidades da Pesquisa de IA do Azure para obter sintaxe de caminho e exemplos.
    targetFieldName Opcional. Especifica o campo de pesquisa que recebe o conteúdo enriquecido. Os campos de destino devem ser campos ou coleções simples de nível superior. Não pode ser um caminho para um subcampo em um tipo complexo. Se quiser recuperar nós específicos em uma estrutura complexa, poderá nivelar nós individuais na memória e, em seguida, enviar a saída para uma coleção de cadeias de caracteres em seu índice.
    mappingFunction Opcional. Adiciona processamento extra fornecido por funções de mapeamento com suporte pelos indexadores. Para nós de enriquecimento, codificação e decodificação são as funções mais usadas.
  3. O targetFieldName é sempre o nome do campo no índice de pesquisa.

  4. O sourceFieldName é um caminho para um nó no documento enriquecido. É a saída de uma habilidade. O caminho sempre começa com /document e, se você estiver indexando de um blob, o segundo elemento do caminho será /content. O terceiro elemento é o valor produzido pela habilidade. Para obter mais informações e exemplos, consulte Enriquecimentos de referência em um conjunto de habilidades da Pesquisa de IA do Azure.

    Este exemplo adiciona entidades e rótulos de sentimento extraídos da propriedade de conteúdo de um blob a campos em um índice de pesquisa.

    {
        "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. Atribua as funções de mapeamento necessárias para transformar o conteúdo de um campo antes que ele seja armazenado no índice. Para nós de enriquecimento, codificação e decodificação são as funções mais usadas.

Mapeamento de campo de saída um para muitos

Você pode usar um mapeamento de campo de saída para rotear um único campo de origem para vários campos em um índice de pesquisa. Você pode fazer isso para testes de comparação ou se quiser campos com atributos diferentes.

Suponha um conjunto de habilidades que gere inserções para um campo de vetor e um índice que tenha vários campos de vetor que variam de acordo com o algoritmo e as configurações de compactação. No indexador, mapeie a saída da habilidade de inserção para cada um dos vários campos de vetor em um índice de pesquisa.

"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" }       
  ]

O caminho do campo de origem é a saída da habilidade. Neste exemplo, a saída é text_vector. O nome do destino é uma propriedade opcional. Se você não der um nome de destino ao mapeamento de saída, o caminho será embedding ou mais precisamente, /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
    }
  ]
}

Nivelar estruturas complexas em uma coleção de cadeias de caracteres

Se os dados de origem forem compostos por JSON aninhado ou hierárquico, você não poderá usar os mapeamentos de campo para configurar os caminhos de dados. Em vez disso, o índice de pesquisa deve espelhar a estrutura de dados de origem para cada nível para uma importação completa.

Esta seção orienta você por um processo de importação que produz um reflexo um-para-um de um documento complexo nos lados de origem e de destino. Em seguida, ele usa o mesmo documento de origem para ilustrar a recuperação e o nivelamento de nós individuais em coleções de cadeias de caracteres.

Aqui está um exemplo de um documento no Azure Cosmos DB com JSON aninhado:

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

Se você quisesse indexar totalmente este documento de origem, criaria uma definição de índice em que os nomes, níveis e tipos de campo são refletidos como um tipo complexo. Como não há suporte para mapeamentos de campo para tipos complexos no índice de pesquisa, sua definição de índice deve espelhar o documento de origem.

{
  "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,
        }
      ]
    }
  ]
}

Aqui está uma definição de indexador de amostra que executa a importação. Observe que não há mapeamentos de campo nem conjunto de habilidades.

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

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

O resultado é o documento de pesquisa de exemplo a seguir, semelhante ao original no 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"
          ]
        }
      ]
    }
  ]
}

Uma renderização alternativa em um índice de pesquisa é nivelar nós individuais na estrutura aninhada da origem em uma coleção de cadeias de caracteres em um índice de pesquisa.

Para realizar essa tarefa, você precisará de um outputFieldMappings que mapeie um nó na memória para uma coleção de cadeias de caracteres no índice. Embora os mapeamentos de campo de saída se apliquem principalmente a saídas de habilidades, você também pode usá-los para endereçar nós depois de quebra de documento em que o indexador abre um documento de origem e o lê na memória.

A definição de índice de amostra a seguir usa coleções de cadeias de caracteres para receber uma saída nivelada:

{
  "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}
  ]
}

Aqui está a definição do indexador de exemplo, usando outputFieldMappings para associar o JSON aninhado aos campos de coleção de cadeias de caracteres. Observe que o campo de origem usa a sintaxe de caminho para nós de enriquecimento, mesmo que não haja nenhum conjunto de habilidades. Documentos enriquecidos são criados no sistema durante a quebra de documentos, o que significa que você pode acessar nós em cada árvore de documentos, desde que esses nós existam quando o documento é quebrado.

{
  "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"
    }
  ]
}

Os resultados da definição acima são os seguintes. Simplificar a estrutura, perde contexto nesse caso. Não há mais associações entre uma determinada cor e os meios em que ela está disponível. No entanto, dependendo do seu cenário, um resultado semelhante ao exemplo a seguir pode ser exatamente o que você precisa.

{
  "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\"]"
      ]
    }
  ]
}