Share via


Exemplo detalhado de formas e projeções em um repositório de conhecimento

Este artigo fornece um exemplo detalhado que complementa conceitos de alto nível e artigos baseados em sintaxe, orientando-o pelas etapas de modelagem e projeção necessárias para expressar totalmente a saída de um conjunto de habilidades avançado em um repositório de conhecimento.

Se os requisitos do seu aplicativo exigem várias habilidades e projeções, este exemplo pode lhe dar uma ideia melhor de como formas e projeções se cruzam.

Configurar dados de exemplo

Os documentos de exemplo não estão incluídos na coleção Projeções, mas os arquivos de dados de demonstração de enriquecimento de IA contêm texto e imagens que funcionam com as projeções descritas neste exemplo.

Crie um contêiner de blob no Armazenamento do Azure e carregue todos os 14 itens.

Enquanto estiver no Armazenamento do Azure, copie uma cadeia de conexão.

Você pode usar o projections.rest arquivo para executar os exemplos neste artigo.

Exemplo de conjunto de competências

Para entender a dependência entre formas e projeções, revise o conjunto de habilidades a seguir que cria conteúdo enriquecido. Este conjunto de habilidades processa imagens e texto brutos, produzindo saídas que serão referenciadas em formas e projeções.

Preste muita atenção aos resultados de habilidades (targetNames). As saídas gravadas na árvore de documentos enriquecida são referenciadas em projeções e em formas (por meio de habilidades de Shaper).

{
    "name": "projections-demo-ss",
    "description": "Skillset that enriches blob data found in "merged_content". The enrichment granularity is a document.",
    "skills": [
        {
            "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
            "name": "#1",
            "description": null,
            "context": "/document/merged_content",
            "categories": [
                "Person",
                "Quantity",
                "Organization",
                "URL",
                "Email",
                "Location",
                "DateTime"
            ],
            "defaultLanguageCode": "en",
            "minimumPrecision": null,
            "inputs": [
                {
                    "name": "text",
                    "source": "/document/merged_content"
                },
                {
                    "name": "languageCode",
                    "source": "/document/language"
                }
            ],
            "outputs": [
                {
                    "name": "persons",
                    "targetName": "people"
                },
                {
                    "name": "organizations",
                    "targetName": "organizations"
                },
                {
                    "name": "locations",
                    "targetName": "locations"
                }
            ]
        },
        {
            "@odata.type": "#Microsoft.Skills.Text.KeyPhraseExtractionSkill",
            "name": "#2",
            "description": null,
            "context": "/document/merged_content",
            "defaultLanguageCode": "en",
            "maxKeyPhraseCount": null,
            "inputs": [
                {
                    "name": "text",
                    "source": "/document/merged_content"
                },
                {
                    "name": "languageCode",
                    "source": "/document/language"
                }
            ],
            "outputs": [
                {
                    "name": "keyPhrases",
                    "targetName": "keyphrases"
                }
            ]
        },
        {
            "@odata.type": "#Microsoft.Skills.Text.LanguageDetectionSkill",
            "name": "#3",
            "description": null,
            "context": "/document",
            "inputs": [
                {
                    "name": "text",
                    "source": "/document/merged_content"
                }
            ],
            "outputs": [
                {
                    "name": "languageCode",
                    "targetName": "language"
                }
            ]
        },
        {
            "@odata.type": "#Microsoft.Skills.Text.MergeSkill",
            "name": "#4",
            "description": null,
            "context": "/document",
            "insertPreTag": " ",
            "insertPostTag": " ",
            "inputs": [
                {
                    "name": "text",
                    "source": "/document/content"
                },
                {
                    "name": "itemsToInsert",
                    "source": "/document/normalized_images/*/text"
                },
                {
                    "name": "offsets",
                    "source": "/document/normalized_images/*/contentOffset"
                }
            ],
            "outputs": [
                {
                    "name": "mergedText",
                    "targetName": "merged_content"
                }
            ]
        },
        {
            "@odata.type": "#Microsoft.Skills.Vision.OcrSkill",
            "name": "#5",
            "description": null,
            "context": "/document/normalized_images/*",
            "textExtractionAlgorithm": "printed",
            "lineEnding": "Space",
            "defaultLanguageCode": "en",
            "detectOrientation": true,
            "inputs": [
                {
                    "name": "image",
                    "source": "/document/normalized_images/*"
                }
            ],
            "outputs": [
                {
                    "name": "text",
                    "targetName": "text"
                },
                {
                    "name": "layoutText",
                    "targetName": "layoutText"
                }
            ]
        }
    ],
    "cognitiveServices": {
        "@odata.type": "#Microsoft.Azure.Search.CognitiveServicesByKey",
        "description": "An Azure AI services resource in the same region as Search.",
        "key": "<Azure AI services All-in-ONE KEY>"
    },
    "knowledgeStore": null
}

Exemplo de habilidade Shaper

Uma habilidade Shaper é um utilitário para trabalhar com conteúdo enriquecido existente em vez de criar novo conteúdo enriquecido. Adicionar um Shaper a um conjunto de habilidades permite criar uma forma personalizada que você pode projetar no armazenamento de tabelas ou blobs. Sem uma forma personalizada, as projeções são limitadas a fazer referência a um único nó (uma projeção por saída), o que não é adequado para tabelas. A criação de uma forma personalizada agrega vários elementos em um novo todo lógico que pode ser projetado como uma única tabela ou fatiado e distribuído em uma coleção de tabelas.

Neste exemplo, a forma personalizada combina metadados de blob e entidades identificadas e frases-chave. A forma personalizada é chamada projectionShape e é parentada em /document.

Um objetivo da modelagem é garantir que todos os nós de enriquecimento sejam expressos em JSON bem formado, o que é necessário para projetar no armazenamento de conhecimento. Isso é especialmente verdadeiro quando uma árvore de enriquecimento contém nós que não são JSON bem formados (por exemplo, quando um enriquecimento é parente a uma primitiva como uma cadeia de caracteres).

Observe os dois últimos nós KeyPhrases e Entities. Eles são encapsulados em um objeto JSON válido com o sourceContext. Isso é necessário como keyphrases e entities são enriquecimentos em primitivos e precisam ser convertidos em JSON válido antes que eles possam ser projetados.

{
    "@odata.type": "#Microsoft.Skills.Util.ShaperSkill",
    "name": "ShaperForTables",
    "description": null,
    "context": "/document",
    "inputs": [
        {
            "name": "metadata_storage_content_type",
            "source": "/document/metadata_storage_content_type",
            "sourceContext": null,
            "inputs": []
        },
        {
            "name": "metadata_storage_name",
            "source": "/document/metadata_storage_name",
            "sourceContext": null,
            "inputs": []
        },
        {
            "name": "metadata_storage_path",
            "source": "/document/metadata_storage_path",
            "sourceContext": null,
            "inputs": []
        },
        {
            "name": "metadata_content_type",
            "source": "/document/metadata_content_type",
            "sourceContext": null,
            "inputs": []
        },
        {
            "name": "keyPhrases",
            "source": null,
            "sourceContext": "/document/merged_content/keyphrases/*",
            "inputs": [
                {
                    "name": "KeyPhrases",
                    "source": "/document/merged_content/keyphrases/*"
                }

            ]
        },
        {
            "name": "Entities",
            "source": null,
            "sourceContext": "/document/merged_content/entities/*",
            "inputs": [
                {
                    "name": "Entities",
                    "source": "/document/merged_content/entities/*/name"
                }

            ]
        }
    ],
    "outputs": [
        {
            "name": "output",
            "targetName": "projectionShape"
        }
    ]
}

Adicionar Shapers a um conjunto de habilidades

O conjunto de habilidades de exemplo introduzido no início deste artigo não incluiu a habilidade Shaper, mas as habilidades Shaper pertencem a um conjunto de habilidades e muitas vezes são colocadas no final.

Dentro de um conjunto de habilidades, uma habilidade Shaper pode ter esta aparência:

{
    "name": "projections-demo-ss",
    "skills": [
        {
            <Shaper skill goes here>
            }
        ],
    "cognitiveServices":  "A key goes here",
    "knowledgeStore": []
}  

Projeção em tabelas

Com base nos exemplos acima, há uma quantidade conhecida de enriquecimentos e formas de dados que podem ser referenciados em projeções de tabela. Na projeção de tabelas abaixo, três tabelas são definidas definindo o tableName, source e generatedKeyName propriedades.

Todas essas três tabelas serão relacionadas por meio de chaves geradas e pelo pai /document/projectionShapecompartilhado.

"knowledgeStore" : {
    "storageConnectionString": "DefaultEndpointsProtocol=https;AccountName=<Acct Name>;AccountKey=<Acct Key>;",
    "projections": [
        {
            "tables": [
                {
                    "tableName": "tblDocument",
                    "generatedKeyName": "Documentid",
                    "source": "/document/projectionShape"
                },
                {
                    "tableName": "tblKeyPhrases",
                    "generatedKeyName": "KeyPhraseid",
                    "source": "/document/projectionShape/keyPhrases/*"
                },
                {
                    "tableName": "tblEntities",
                    "generatedKeyName": "Entityid",
                    "source": "/document/projectionShape/Entities/*"
                }
            ],
            "objects": [],
            "files": []
        }
    ]
}

Teste o seu trabalho

Você pode verificar as definições de projeção seguindo estas etapas:

  1. Defina a propriedade do repositório de conhecimento como uma cadeia de storageConnectionString conexão de conta de armazenamento de uso geral V2 válida.

  2. Atualize o conjunto de habilidades emitindo a solicitação PUT.

  3. Depois de atualizar o conjunto de habilidades, execute o indexador.

Agora você tem uma projeção de trabalho com três tabelas. Importar essas tabelas para o Power BI deve resultar na descoberta das relações pelo Power BI.

Antes de passar para o próximo exemplo, vamos revisitar aspetos da projeção de tabela para entender a mecânica de fatiamento e relacionar dados.

Fatiar uma tabela em várias tabelas secundárias

O fatiamento é uma técnica que subdivide toda uma forma consolidada em partes constituintes. O resultado consiste em tabelas separadas, mas relacionadas, com as quais você pode trabalhar individualmente.

No exemplo, projectionShape é a forma consolidada (ou nó de enriquecimento). Na definição de projeção, projectionShape é fatiado em tabelas adicionais, o que permite retirar partes da forma, keyPhrases e Entities. No Power BI, isso é útil, pois várias entidades e frases-chave estão associadas a cada documento, e você obterá mais informações se puder ver entidades e frases-chave como dados categorizados.

O fatiamento gera implicitamente uma relação entre as tabelas pai e filho, usando o generatedKeyName na tabela pai para criar uma coluna com o mesmo nome na tabela filho.

Nomeando relações

As generatedKeyName propriedades e referenceKeyName são usadas para relacionar dados entre tabelas ou até mesmo entre tipos de projeção. Cada linha na tabela filho tem uma propriedade apontando para o pai. O nome da coluna ou propriedade no filho é o referenceKeyName do pai. Quando o referenceKeyName não é fornecido, o serviço assume como padrão o generatedKeyName do pai.

O Power BI depende dessas chaves geradas para descobrir relações dentro das tabelas. Se você precisar da coluna na tabela filho com nome diferente, defina a referenceKeyName propriedade na tabela pai. Um exemplo seria definir o generatedKeyName como ID na tabela tblDocument e o referenceKeyName como DocumentID. Isso resultaria na coluna nas tabelas tblEntities e tblKeyPhrases contendo a ID do documento sendo chamada DocumentID.

Projetando documentos de blob

As projeções de objeto são representações JSON da árvore de enriquecimento que podem ser originadas de qualquer nó. Em comparação com as projeções de tabela, as projeções de objetos são mais simples de definir e são usadas ao projetar documentos inteiros. As projeções de objetos são limitadas a uma única projeção em um contêiner e não podem ser fatiadas.

Para definir uma projeção de objeto, use a objects matriz na propriedade projections.

A fonte é o caminho para um nó da árvore de enriquecimento que é a raiz da projeção. Embora não seja necessário, o caminho do nó geralmente é a saída de uma habilidade Shaper. Isso ocorre porque a maioria das habilidades não produz objetos JSON válidos por conta própria, o que significa que alguma forma de modelagem é necessária. Em muitos casos, a mesma habilidade Shaper que cria uma projeção de tabela pode ser usada para gerar uma projeção de objeto. Como alternativa, a fonte também pode ser definida como um nó com uma modelagem embutida para fornecer a estrutura.

O destino é sempre um contêiner de blob.

O exemplo a seguir projeta documentos de hotel individuais, um documento de hotel por blob, em um contêiner chamado hotels.

"knowledgeStore": {
  "storageConnectionString": "an Azure storage connection string",
  "projections" : [
    {
      "tables": [ ]
    },
    {
      "objects": [
        {
        "storageContainer": "hotels",
        "source": "/document/objectprojection",
        }
      ]
    },
    {
        "files": [ ]
    }
  ]
}

A fonte é a saída de uma habilidade Shaper, chamada "objectprojection". Cada blob terá uma representação JSON de cada entrada de campo.

    {
      "@odata.type": "#Microsoft.Skills.Util.ShaperSkill",
      "name": "#3",
      "description": null,
      "context": "/document",
      "inputs": [
        {
          "name": "HotelId",
          "source": "/document/HotelId"
        },
        {
          "name": "HotelName",
          "source": "/document/HotelName"
        },
        {
          "name": "Category",
          "source": "/document/Category"
        },
        {
          "name": "keyPhrases",
          "source": "/document/HotelId/keyphrases/*"
        },
      ],
      "outputs": [
        {
          "name": "output",
          "targetName": "objectprojection"
        }
      ]
    }

Projetando um arquivo de imagem

As projeções de arquivos são sempre imagens binárias e normalizadas, onde a normalização se refere ao potencial redimensionamento e rotação para uso na execução do conjunto de habilidades. As projeções de arquivo, semelhantes às projeções de objeto, são criadas como blobs no Armazenamento do Azure e contêm a imagem.

Para definir uma projeção de arquivo, use a files matriz na propriedade projections.

A fonte é sempre /document/normalized_images/*. As projeções de arquivo atuam apenas na normalized_images coleção. Nem indexadores nem um conjunto de habilidades passarão pela imagem original não normalizada.

O destino é sempre um contêiner de blob, com um prefixo de pasta do valor codificado base64 da ID do documento. As projeções de arquivo não podem compartilhar o mesmo contêiner que as projeções de objeto e precisam ser projetadas em um contêiner diferente.

O exemplo a seguir projeta todas as imagens normalizadas extraídas do nó do documento de um documento enriquecido em um contêiner chamado myImages.

"knowledgeStore" : {
    "storageConnectionString": "DefaultEndpointsProtocol=https;AccountName=<Acct Name>;AccountKey=<Acct Key>;",
    "projections": [
        {
            "tables": [ ],
            "objects": [ ],
            "files": [
                {
                    "storageContainer": "myImages",
                    "source": "/document/normalized_images/*"
                }
            ]
        }
    ]
}

Projeção para vários tipos

Um cenário mais complexo pode exigir que você projete conteúdo entre tipos de projeção. Por exemplo, projetar frases-chave e entidades em tabelas, salvar resultados de OCR de texto e texto de layout como objetos e, em seguida, projetar as imagens como arquivos.

Etapas para vários tipos de projeção:

  1. Crie uma tabela com uma linha para cada documento.
  2. Crie uma tabela relacionada à tabela do documento com cada frase-chave identificada como uma linha nesta tabela.
  3. Crie uma tabela relacionada à tabela do documento com cada entidade identificada como uma linha nesta tabela.
  4. Crie uma projeção de objeto com o texto do layout para cada imagem.
  5. Crie uma projeção de arquivo, projetando cada imagem extraída.
  6. Crie uma tabela de referência cruzada que contenha referências à tabela do documento, à projeção de objetos com o texto do layout e à projeção do arquivo.

Dados da forma para projeção cruzada

Para obter as formas necessárias para essas projeções, comece adicionando uma nova habilidade Shaper que cria um objeto moldado chamado crossProjection.

{
    "@odata.type": "#Microsoft.Skills.Util.ShaperSkill",
    "name": "ShaperForCrossProjection",
    "description": null,
    "context": "/document",
    "inputs": [
        {
            "name": "metadata_storage_name",
            "source": "/document/metadata_storage_name",
            "sourceContext": null,
            "inputs": []
        },
        {
            "name": "keyPhrases",
            "source": null,
            "sourceContext": "/document/merged_content/keyphrases/*",
            "inputs": [
                {
                    "name": "KeyPhrases",
                    "source": "/document/merged_content/keyphrases/*"
                }

            ]
        },
        {
            "name": "entities",
            "source": null,
            "sourceContext": "/document/merged_content/entities/*",
            "inputs": [
                {
                    "name": "Entities",
                    "source": "/document/merged_content/entities/*/name"
                }

            ]
        },
        {
            "name": "images",
            "source": null,
            "sourceContext": "/document/normalized_images/*",
            "inputs": [
                {
                    "name": "image",
                    "source": "/document/normalized_images/*"
                },
                {
                    "name": "layoutText",
                    "source": "/document/normalized_images/*/layoutText"
                },
                {
                    "name": "ocrText",
                    "source": "/document/normalized_images/*/text"
                }
                ]
        }
 
    ],
    "outputs": [
        {
            "name": "output",
            "targetName": "crossProjection"
        }
    ]
}

Definir projeções de tabela, objeto e arquivo

A partir do objeto crossProjection consolidado, fatie o objeto em várias tabelas, capture a saída OCR como blobs e salve a imagem como arquivos (também no armazenamento de Blob).

"knowledgeStore" : {
    "storageConnectionString": "DefaultEndpointsProtocol=https;AccountName=<Acct Name>;AccountKey=<Acct Key>;",
    "projections": [
            {
            "tables": [
                {
                    "tableName": "crossDocument",
                    "generatedKeyName": "Id",
                    "source": "/document/crossProjection"
                },
                {
                    "tableName": "crossEntities",
                    "generatedKeyName": "EntityId",
                    "source": "/document/crossProjection/entities/*"
                },
                {
                    "tableName": "crossKeyPhrases",
                    "generatedKeyName": "KeyPhraseId",
                    "source": "/document/crossProjection/keyPhrases/*"
                },
                {
                    "tableName": "crossReference",
                    "generatedKeyName": "CrossId",
                    "source": "/document/crossProjection/images/*"
                }
                    
            ],
            "objects": [
                {
                    "storageContainer": "crossobject",
                    "generatedKeyName": "crosslayout",
                    "source": null,
                    "sourceContext": "/document/crossProjection/images/*/layoutText",
                    "inputs": [
                        {
                            "name": "OcrLayoutText",
                            "source": "/document/crossProjection/images/*/layoutText"
                        }
                    ]
                }
            ],
            "files": [
                {
                    "storageContainer": "crossimages",
                    "generatedKeyName": "crossimages",
                    "source": "/document/crossProjection/images/*/image"
                }
            ]
        }
    ]
}

As projeções de objetos exigem um nome de contêiner para cada projeção. Projeções de objetos e projeções de arquivo não podem compartilhar um contêiner.

Relações entre projeções de tabela, objeto e arquivo

Este exemplo também destaca outra característica das projeções. Ao definir vários tipos de projeções dentro do mesmo objeto de projeção, há uma relação expressa dentro e entre os diferentes tipos (tabelas, objetos, arquivos). Isso permite que você comece com uma linha de tabela para um documento e encontre todo o texto OCR para as imagens dentro desse documento na projeção de objeto.

Se não quiser que os dados sejam relacionados, defina as projeções em diferentes grupos de projeção. Por exemplo, o trecho a seguir resultará na relação das tabelas, mas sem relações entre as tabelas e as projeções de objeto (texto OCR).

Os grupos de projeção são úteis quando você deseja projetar os mesmos dados em formas diferentes para necessidades diferentes. Por exemplo, um grupo de projeção para o painel do Power BI e outro grupo de projeção para capturar dados usados para treinar um modelo de aprendizado de máquina envolvido em uma habilidade personalizada.

Ao construir projeções de diferentes tipos, as projeções de arquivos e objetos são geradas primeiro e os caminhos são adicionados às tabelas.

"knowledgeStore" : {
    "storageConnectionString": "DefaultEndpointsProtocol=https;AccountName=<Acct Name>;AccountKey=<Acct Key>;",
    "projections": [
        {
            "tables": [
                {
                    "tableName": "unrelatedDocument",
                    "generatedKeyName": "Documentid",
                    "source": "/document/projectionShape"
                },
                {
                    "tableName": "unrelatedKeyPhrases",
                    "generatedKeyName": "KeyPhraseid",
                    "source": "/document/projectionShape/keyPhrases"
                }
            ],
            "objects": [
                
            ],
            "files": []
        }, 
        {
            "tables": [],
            "objects": [
                {
                    "storageContainer": "unrelatedocrtext",
                    "source": null,
                    "sourceContext": "/document/normalized_images/*/text",
                    "inputs": [
                        {
                            "name": "ocrText",
                            "source": "/document/normalized_images/*/text"
                        }
                    ]
                },
                {
                    "storageContainer": "unrelatedocrlayout",
                    "source": null,
                    "sourceContext": "/document/normalized_images/*/layoutText",
                    "inputs": [
                        {
                            "name": "ocrLayoutText",
                            "source": "/document/normalized_images/*/layoutText"
                        }
                    ]
                }
            ],
            "files": []
        }
    ]
}

Próximos passos

O exemplo neste artigo demonstra padrões comuns sobre como criar projeções. Agora que você tem uma boa compreensão dos conceitos, está mais bem equipado para construir projeções para o seu cenário específico.