Modelar tipos de dados complexos no Azure Cognitive Search
Os conjuntos de dados externos utilizados para preencher um índice de Azure Cognitive Search podem ter muitas formas. Por vezes, incluem subestruturas hierárquicas ou aninhadas. Os exemplos podem incluir vários endereços para um único cliente, múltiplas cores e tamanhos para um único SKU, vários autores de um único livro, entre outros. Em termos de modelação, poderá ver estas estruturas referidas como tipos de dados complexos, compostos, compostos ou agregados . O termo Azure Cognitive Search utiliza para este conceito é de tipo complexo. No Azure Cognitive Search, os tipos complexos são modelados com campos complexos. Um campo complexo é um campo que contém crianças (sub-campos) que podem ser de qualquer tipo de dados, incluindo outros tipos complexos. Isto funciona de forma semelhante aos tipos de dados estruturados numa linguagem de programação.
Os campos complexos representam um único objeto no documento ou uma matriz de objetos, dependendo do tipo de dados. Os campos do tipo Edm.ComplexType
representam objetos únicos, enquanto os campos do tipo Collection(Edm.ComplexType)
representam matrizes de objetos.
Azure Cognitive Search suporta nativamente tipos e coleções complexos. Estes tipos permitem-lhe modelar praticamente qualquer estrutura JSON num índice de Azure Cognitive Search. Nas versões anteriores das APIs Azure Cognitive Search, apenas os conjuntos de linhas achatados podiam ser importados. Na versão mais recente, o índice pode agora corresponder mais de perto aos dados de origem. Por outras palavras, se os dados de origem tiverem tipos complexos, o índice também pode ter tipos complexos.
Para começar, recomendamos o conjunto de dados Hotéis, que pode carregar no assistente Importar dados no portal do Azure. O assistente deteta tipos complexos na origem e sugere um esquema de índice com base nas estruturas detetadas.
Nota
O suporte para tipos complexos tornou-se geralmente disponível a partir do api-version=2019-05-06
.
Se a sua solução de pesquisa for criada com base em soluções anteriores de conjuntos de dados achatados numa coleção, deve alterar o índice para incluir tipos complexos, conforme suportado na versão mais recente da API. Para obter mais informações sobre a atualização das versões da API, consulte Atualizar para a versão mais recente da API REST ou Atualizar para a versão mais recente do SDK .NET.
Exemplo de uma estrutura complexa
O seguinte documento JSON é composto por campos simples e campos complexos. Os campos complexos, como Address
e Rooms
, têm sub-campos. Address
tem um único conjunto de valores para esses sub-campos, uma vez que é um único objeto no documento. Por outro lado, Rooms
tem vários conjuntos de valores para os respetivos sub-campos, um para cada objeto na coleção.
{
"HotelId": "1",
"HotelName": "Secret Point Motel",
"Description": "Ideally located on the main commercial artery of the city in the heart of New York.",
"Tags": ["Free wifi", "on-site parking", "indoor pool", "continental breakfast"],
"Address": {
"StreetAddress": "677 5th Ave",
"City": "New York",
"StateProvince": "NY"
},
"Rooms": [
{
"Description": "Budget Room, 1 Queen Bed (Cityside)",
"RoomNumber": 1105,
"BaseRate": 96.99,
},
{
"Description": "Deluxe Room, 2 Double Beds (City View)",
"Type": "Deluxe Room",
"BaseRate": 150.99,
}
. . .
]
}
Indexar tipos complexos
Durante a indexação, pode ter um máximo de 3000 elementos em todas as coleções complexas num único documento. Um elemento de uma coleção complexa é um membro dessa coleção, por isso, no caso dos Quartos (a única coleção complexa no exemplo hotel), cada quarto é um elemento. No exemplo acima, se o "Secret Point Motel" tivesse 500 quartos, o documento do hotel teria 500 elementos de quarto. Para coleções complexas aninhadas, cada elemento aninhado também é contado, além do elemento externo (principal).
Este limite aplica-se apenas a coleções complexas e não a tipos complexos (como Endereço) ou coleções de cadeias (como Etiquetas).
Criar campos complexos
Tal como acontece com qualquer definição de índice, pode utilizar o portal, a API REST ou o SDK .NET para criar um esquema que inclua tipos complexos.
Outros SDKs do Azure fornecem exemplos em Python, Java e JavaScript.
Inicie sessão no portal do Azure.
Na página Descrição geral do serviço de pesquisa, selecione o separador Índices .
Abra um índice existente ou crie um novo índice.
Selecione o separador Campos e, em seguida, selecione Adicionar campo. É adicionado um campo vazio. Se estiver a trabalhar com uma coleção de campos existente, desloque-se para baixo para configurar o campo.
Atribua um nome ao campo e defina o tipo como ou
Edm.ComplexType
Collection(Edm.ComplexType)
.Selecione as reticências na extremidade direita e, em seguida, selecione Adicionar campo ou Adicionar subcampo e, em seguida, atribua atributos.
Atualizar campos complexos
Todas as regras de reindexação aplicáveis aos campos em geral ainda se aplicam a campos complexos. A reenvio de algumas das regras principais aqui, adicionar um campo a um tipo complexo não requer uma reconstrução de índice, mas a maioria das modificações o fazem.
Atualizações estruturais da definição
Pode adicionar novos subcampos a um campo complexo em qualquer altura sem a necessidade de uma reconstrução de índice. Por exemplo, é permitido adicionar "Código Postal" a Address
ou "Amenidades", Rooms
tal como adicionar um campo de nível superior a um índice. Os documentos existentes têm um valor nulo para novos campos até preencher explicitamente esses campos ao atualizar os seus dados.
Tenha em atenção que, num tipo complexo, cada sub-campo tem um tipo e pode ter atributos, tal como os campos de nível superior
Atualizações de dados
A atualização de documentos existentes num índice com a ação upload
funciona da mesma forma para campos complexos e simples: todos os campos são substituídos. No entanto, merge
(ou mergeOrUpload
quando aplicado a um documento existente) não funciona da mesma forma em todos os campos. Especificamente, merge
não suporta a intercalação de elementos numa coleção. Esta limitação existe para coleções de tipos primitivos e coleções complexas. Para atualizar uma coleção, terá de obter o valor completo da coleção, fazer alterações e, em seguida, incluir a nova coleção no pedido da API de Índice.
Procurar campos complexos
As expressões de pesquisa de forma livre funcionam conforme esperado com tipos complexos. Se qualquer campo pesquisável ou sub-campo em qualquer parte de um documento corresponder, o próprio documento é uma correspondência.
As consultas são mais matizadas quando tem vários termos e operadores e alguns termos têm nomes de campo especificados, como é possível com a sintaxe Lucene. Por exemplo, esta consulta tenta corresponder a dois termos, "Portland" e "OR", em dois sub campos do campo Endereço:
search=Address/City:Portland AND Address/State:OR
Consultas como esta não estão correlacionadas para pesquisa em texto completo, ao contrário dos filtros. Nos filtros, as consultas sobre sub-campos de uma coleção complexa estão correlacionadas com variáveis de intervalo no any
ou all
. A consulta Lucene acima devolve documentos que contêm "Portland, Maine" e "Portland, Oregon", juntamente com outras cidades do Oregon. Isto acontece porque cada cláusula se aplica a todos os valores do respetivo campo em todo o documento, pelo que não existe nenhum conceito de "sub-documento atual". Para obter mais informações, veja Compreender os filtros da coleção OData no Azure Cognitive Search.
Selecionar campos complexos
O $select
parâmetro é utilizado para escolher os campos que são devolvidos nos resultados da pesquisa. Para utilizar este parâmetro para selecionar sub campos específicos de um campo complexo, inclua o campo principal e o sub-campo separados por uma barra (/
).
$select=HotelName, Address/City, Rooms/BaseRate
Os campos têm de ser marcados como Recuperáveis no índice se os quiser nos resultados da pesquisa. Apenas os campos marcados como Recuperáveis podem ser utilizados numa $select
instrução.
Filtrar, facetar e ordenar campos complexos
A mesma sintaxe do caminho OData utilizada para filtrar e procurar em campo também pode ser utilizada para facetar, ordenar e selecionar campos num pedido de pesquisa. Para tipos complexos, aplicam-se regras que regem os submenus que podem ser marcados como sortíveis ou facetáveis. Para obter mais informações sobre estas regras, veja a referência criar API de Índice.
Subdomissões de facetação
Qualquer sub-campo pode ser marcado como facetável, a menos que seja do tipo Edm.GeographyPoint
ou Collection(Edm.GeographyPoint)
.
As contagens de documentos devolvidas nos resultados de facetas são calculadas para o documento principal (um hotel), não para os sub-documentos numa coleção complexa (salas). Por exemplo, suponha que um hotel tem 20 quartos do tipo "suite". Tendo em conta este parâmetro facet=Rooms/Type
de faceta, a contagem de facetas será uma para o hotel e não 20 para os quartos.
Ordenar campos complexos
As operações de ordenação aplicam-se a documentos (Hotéis) e não a subconsultas (Salas). Quando tem uma coleção de tipos complexos, como Salas, é importante perceber que não pode ordenar em Salas. Na verdade, não pode ordenar em nenhuma coleção.
As operações de ordenação funcionam quando os campos têm um único valor por documento, se o campo é um campo simples ou um sub-campo num tipo complexo. Por exemplo, Address/City
é permitido ser ordenável porque há apenas um endereço por hotel, assim $orderby=Address/City
como ordenar hotéis por cidade.
Filtrar em campos complexos
Pode fazer referência a subdomissões de um campo complexo numa expressão de filtro. Basta utilizar a mesma sintaxe do caminho OData utilizada para facetar, ordenar e selecionar campos. Por exemplo, o seguinte filtro irá devolver todos os hotéis no Canadá:
$filter=Address/Country eq 'Canada'
Para filtrar num campo de coleção complexo, pode utilizar uma expressão lambda com os any
operadores e all
. Nesse caso, a variável de intervalo da expressão lambda é um objeto com submenus. Pode consultar esses subdomissos com a sintaxe do caminho OData padrão. Por exemplo, o seguinte filtro irá devolver todos os hotéis com, pelo menos, um quarto de luxo e todos os quartos que não fumam:
$filter=Rooms/any(room: room/Type eq 'Deluxe Room') and Rooms/all(room: not room/SmokingAllowed)
Tal como acontece com os campos simples de nível superior, os subdomissos simples de campos complexos só podem ser incluídos em filtros se tiverem o atributo filtráveis definido como true
na definição de índice. Para obter mais informações, veja a referência criar API de Índice.
Passos seguintes
Experimente o conjunto de dados Hotéis no assistente Importar dados . Precisará das informações de ligação do Azure Cosmos DB fornecidas no readme para aceder aos dados.
Com essas informações em mãos, o primeiro passo no assistente é criar uma nova origem de dados do Azure Cosmos DB. Mais à frente no assistente, quando chegar à página de índice de destino, verá um índice com tipos complexos. Crie e carregue este índice e, em seguida, execute consultas para compreender a nova estrutura.