Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Em soluções de pesquisa, cadeias de caracteres que têm padrões complexos ou caracteres especiais podem ser difíceis de trabalhar porque o analisador padrão remove ou interpreta incorretamente partes significativas de um padrão. Isso resulta em uma experiência de pesquisa ruim, onde os usuários não conseguem encontrar as informações esperadas. Os números de telefone são um exemplo clássico de cadeias de caracteres difíceis de analisar. Eles vêm em vários formatos e incluem caracteres especiais que o analisador padrão ignora.
Com números de telefone como assunto, este tutorial mostra como resolver problemas de dados padronizados usando um analisador personalizado. Essa abordagem pode ser usada como é para números de telefone ou adaptada para campos com as mesmas características (padronizados com caracteres especiais), como URLs, e-mails, códigos postais e datas.
Neste tutorial, você usa um cliente REST e as APIs REST do Azure AI Search para:
- Entenda o problema
- Desenvolver um analisador personalizado inicial para lidar com números de telefone
- Testar o analisador personalizado
- Reitere o design do analisador personalizado para melhorar ainda mais os resultados
Pré-requisitos
Uma conta do Azure com uma assinatura ativa. Crie uma conta gratuitamente.
Azure AI Search. Crie um serviço ou encontre um serviço existente na sua subscrição atual. Para este tutorial, você pode usar um serviço gratuito.
Transferir ficheiros
O código-fonte deste tutorial está no arquivo custom-analyzer.rest no repositório GitHub Azure-Samples/azure-search-rest-samples .
Copiar uma chave de administração e um URL
As chamadas REST neste tutorial exigem um endpoint de serviço de pesquisa e uma chave API de administração. Você pode obter esses valores no portal do Azure.
Entre no portal do Azure, vá para a página Visão geral e copie a URL. Um ponto final de exemplo poderá ser parecido com
https://mydemo.search.windows.net
.Em Configurações>Teclas, copie uma chave de administrador. As chaves de administrador são usadas para adicionar, modificar e excluir objetos. Existem duas chaves de administração intercambiáveis. Copie qualquer uma delas.
Uma chave de API válida estabelece confiança, por solicitação, entre o aplicativo que envia a solicitação e o serviço de pesquisa que a manipula.
Criar um índice inicial
Abra um novo arquivo de texto no Visual Studio Code.
Defina variáveis para o ponto de extremidade de pesquisa e a chave de API coletada na seção anterior.
@baseUrl = PUT-YOUR-SEARCH-SERVICE-URL-HERE @apiKey = PUT-YOUR-ADMIN-API-KEY-HERE
Salve o arquivo com uma
.rest
extensão de arquivo.Cole o exemplo a seguir para criar um pequeno índice chamado
phone-numbers-index
com dois campos:id
ephone_number
. Você ainda não definiu um analisador, portanto, ostandard.lucene
analisador é usado por padrão.### Create a new index POST {{baseUrl}}/indexes?api-version=2024-07-01 HTTP/1.1 Content-Type: application/json api-key: {{apiKey}} { "name": "phone-numbers-index", "fields": [ { "name": "id", "type": "Edm.String", "key": true, "searchable": true, "filterable": false, "facetable": false, "sortable": true }, { "name": "phone_number", "type": "Edm.String", "sortable": false, "searchable": true, "filterable": false, "facetable": false } ] }
Selecione Enviar pedido. Você deve ter uma
HTTP/1.1 201 Created
resposta e o corpo da resposta deve incluir a representação JSON do esquema de índice.Carregue dados no índice, usando documentos que contêm vários formatos de número de telefone. Estes são os seus dados de teste.
### Load documents POST {{baseUrl}}/indexes/phone-numbers-index/docs/index?api-version=2024-07-01 HTTP/1.1 Content-Type: application/json api-key: {{apiKey}} { "value": [ { "@search.action": "upload", "id": "1", "phone_number": "425-555-0100" }, { "@search.action": "upload", "id": "2", "phone_number": "(321) 555-0199" }, { "@search.action": "upload", "id": "3", "phone_number": "+1 425-555-0100" }, { "@search.action": "upload", "id": "4", "phone_number": "+1 (321) 555-0199" }, { "@search.action": "upload", "id": "5", "phone_number": "4255550100" }, { "@search.action": "upload", "id": "6", "phone_number": "13215550199" }, { "@search.action": "upload", "id": "7", "phone_number": "425 555 0100" }, { "@search.action": "upload", "id": "8", "phone_number": "321.555.0199" } ] }
Tente consultas semelhantes ao que um usuário pode digitar. Por exemplo, um usuário pode pesquisar
(425) 555-0100
em qualquer número de formatos e ainda esperar que os resultados sejam retornados. Comece por pesquisar(425) 555-0100
.### Search for a phone number GET {{baseUrl}}/indexes/phone-numbers-index/docs/search?api-version=2024-07-01&search=(425) 555-0100 HTTP/1.1 Content-Type: application/json api-key: {{apiKey}}
A consulta retorna três dos quatro resultados esperados, mas também retorna dois resultados inesperados.
{ "value": [ { "@search.score": 0.05634898, "phone_number": "+1 425-555-0100" }, { "@search.score": 0.05634898, "phone_number": "425 555 0100" }, { "@search.score": 0.05634898, "phone_number": "425-555-0100" }, { "@search.score": 0.020766128, "phone_number": "(321) 555-0199" }, { "@search.score": 0.020766128, "phone_number": "+1 (321) 555-0199" } ] }
Tente novamente sem qualquer formatação:
4255550100
.### Search for a phone number GET {{baseUrl}}/indexes/phone-numbers-index/docs/search?api-version=2024-07-01&search=4255550100 HTTP/1.1 Content-Type: application/json api-key: {{apiKey}}
Esta consulta é ainda menos eficaz, retornando apenas uma das quatro correspondências corretas.
{ "value": [ { "@search.score": 0.6015292, "phone_number": "4255550100" } ] }
Se você acha esses resultados confusos, você não está sozinho. A próxima seção explica por que você está obtendo esses resultados.
Rever como os analisadores funcionam
Para entender esses resultados de pesquisa, você deve entender o que o analisador está fazendo. A partir daí, você pode testar o analisador padrão usando a API de análise, fornecendo uma base para projetar um analisador que atenda melhor às suas necessidades.
Um analisador é um componente do mecanismo de pesquisa de texto completo responsável pelo processamento de texto em cadeias de caracteres de consulta e documentos indexados. Diferentes analisadores manipulam o texto de maneiras diferentes, dependendo do cenário. Para este cenário, precisamos construir um analisador adaptado para números de telefone.
Os analisadores consistem em três componentes:
- Filtros de caracteres que removem ou substituem caracteres individuais do texto de entrada.
- Um tokenizador que divide o texto de entrada em tokens, que se tornam chaves no índice de pesquisa.
- Filtros de token que manipulam os tokens produzidos pelo tokenizador.
O diagrama a seguir mostra como esses três componentes trabalham juntos para tokenizar uma frase.
Esses tokens são então armazenados em um índice invertido, o que permite pesquisas rápidas de texto completo. Um índice invertido permite a pesquisa de texto completo, mapeando todos os termos únicos extraídos durante a análise lexical para os documentos em que ocorrem. Você pode ver um exemplo no diagrama a seguir:
Toda a pesquisa se resume à busca pelos termos armazenados no índice invertido. Quando um usuário emite uma consulta:
- A consulta é analisada e os termos da consulta são analisados.
- O índice invertido é percorrido em busca de documentos com termos correspondentes.
- O algoritmo de pontuação classifica os documentos recuperados.
Se os termos da consulta não corresponderem aos termos do índice invertido, os resultados não serão retornados. Para saber mais sobre como as consultas funcionam, consulte Pesquisa de texto completo no Azure AI Search.
Nota
Consultas parciais de termos são uma exceção importante a esta regra. Ao contrário das consultas de termo regulares, essas consultas (consulta de prefixo, consulta curinga e consulta regex) ignoram o processo de análise lexical. Os termos parciais são apenas reduzidos antes de serem comparados com os termos do índice. Se um analisador não estiver configurado para suportar esses tipos de consultas, você geralmente receberá resultados inesperados porque os termos correspondentes não existem no índice.
Analisadores de teste usando a API de análise
O Azure AI Search fornece uma API de Análise que permite testar analisadores para entender como eles processam texto.
Chame a API Analyze usando a seguinte solicitação:
POST {{baseUrl}}/indexes/phone-numbers-index/analyze?api-version=2024-07-01 HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}
{
"text": "(425) 555-0100",
"analyzer": "standard.lucene"
}
A API retorna os tokens extraídos do texto, usando o analisador especificado. O analisador Lucene padrão divide o número de telefone em três tokens separados.
{
"tokens": [
{
"token": "425",
"startOffset": 1,
"endOffset": 4,
"position": 0
},
{
"token": "555",
"startOffset": 6,
"endOffset": 9,
"position": 1
},
{
"token": "0100",
"startOffset": 10,
"endOffset": 14,
"position": 2
}
]
}
Por outro lado, o número 4255550100
de telefone formatado sem qualquer pontuação é tokenizado em um único token.
{
"text": "4255550100",
"analyzer": "standard.lucene"
}
Resposta:
{
"tokens": [
{
"token": "4255550100",
"startOffset": 0,
"endOffset": 10,
"position": 0
}
]
}
Tenha em mente que tanto os termos de consulta quanto os documentos indexados passam por análise. Pensando nos resultados da pesquisa da etapa anterior, você pode começar a ver por que esses resultados são retornados.
Na primeira consulta, números de telefone inesperados são retornados porque um de seus tokens, 555
, correspondeu a um dos termos que você pesquisou. Na segunda consulta, apenas um número é retornado porque é o único registro que tem uma correspondência de token 4255550100
.
Crie um analisador personalizado
Agora que você entende os resultados que está vendo, crie um analisador personalizado para melhorar a lógica de tokenização.
O objetivo é fornecer uma pesquisa intuitiva em relação a números de telefone, independentemente do formato da consulta ou da cadeia de caracteres indexada. Para obter esse resultado, especifique um filtro de caracteres, um tokenizador e um filtro de token.
Filtros de caracteres
Os filtros de caracteres processam o texto antes que ele seja inserido no tokenizador. Os usos comuns de filtros de caracteres são filtrar elementos HTML e substituir caracteres especiais.
Para números de telefone, você deseja remover espaços em branco e caracteres especiais porque nem todos os formatos de número de telefone contêm os mesmos caracteres especiais e espaços.
"charFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.MappingCharFilter",
"name": "phone_char_mapping",
"mappings": [
"-=>",
"(=>",
")=>",
"+=>",
".=>",
"\\u0020=>"
]
}
]
O filtro remove -
(
)
+
.
e espaços da entrada.
Entrada | Saída |
---|---|
(321) 555-0199 |
3215550199 |
321.555.0199 |
3215550199 |
Tokenizadores
Os tokenizadores dividem o texto em tokens e descartam alguns caracteres, como pontuação, ao longo do caminho. Em muitos casos, o objetivo da tokenização é dividir uma frase em palavras individuais.
Para esse cenário, use um tokenizador de palavra-chave, keyword_v2
, para capturar o número de telefone como um único termo. Esta não é a única maneira de resolver esse problema, conforme explicado na seção Abordagens alternativas .
Os tokenizadores de palavras-chave sempre produzem o mesmo texto que recebem como um único termo.
Entrada | Saída |
---|---|
The dog swims. |
[The dog swims.] |
3215550199 |
[3215550199] |
Filtros de token
Os filtros de token modificam ou filtram os tokens gerados pelo tokenizador. Um uso comum de um filtro de token é converter todos os caracteres em minúsculas usando um filtro de minúsculas. Outro uso comum é filtrar palavras paradas, como the
, and
ou is
.
Embora você não precise usar nenhum desses filtros para esse cenário, use um filtro de token nGram para permitir pesquisas parciais de números de telefone.
"tokenFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2",
"name": "custom_ngram_filter",
"minGram": 3,
"maxGram": 20
}
]
NGramTokenFilterV2
O filtro de token nGram_v2 divide os tokens em n-gramas de um determinado tamanho com base nos parâmetros minGram
e maxGram
.
Para o analisador de telefone, minGram
está definido como 3
porque essa é a substring mais curta que os usuários devem pesquisar.
maxGram
está configurado como 20
para garantir que todos os números de telefone, mesmo com extensões, encaixem em um único n-gram.
O infeliz efeito colateral dos n-gramas é que alguns falsos positivos podem ocorrer. Você corrige isso em uma etapa posterior, criando um analisador separado para pesquisas que não inclui o filtro de token n-grama.
Entrada | Saída |
---|---|
[12345] |
[123, 1234, 12345, 234, 2345, 345] |
[3215550199] |
[321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ] |
Analisador
Com os filtros de caracteres, tokenizador e filtros de token no lugar, você está pronto para definir o analisador.
"analyzers": [
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer",
"tokenizer": "keyword_v2",
"tokenFilters": [
"custom_ngram_filter"
],
"charFilters": [
"phone_char_mapping"
]
}
]
A partir da API Analyze, dadas as seguintes entradas, as saídas do analisador personalizado são as seguintes:
Entrada | Saída |
---|---|
12345 |
[123, 1234, 12345, 234, 2345, 345] |
(321) 555-0199 |
[321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ] |
Todos os tokens na coluna de saída existem no índice. Se a sua consulta incluir qualquer um desses termos, o número de telefone será devolvido.
Reconstruir usando o novo analisador
Exclua o índice atual.
### Delete the index DELETE {{baseUrl}}/indexes/phone-numbers-index?api-version=2024-07-01 HTTP/1.1 api-key: {{apiKey}}
Recrie o índice usando o novo analisador. Este esquema de índice adiciona uma definição de analisador personalizado e uma atribuição de analisador personalizado no campo de número de telefone.
### Create a new index POST {{baseUrl}}/indexes?api-version=2024-07-01 HTTP/1.1 Content-Type: application/json api-key: {{apiKey}} { "name": "phone-numbers-index-2", "fields": [ { "name": "id", "type": "Edm.String", "key": true, "searchable": true, "filterable": false, "facetable": false, "sortable": true }, { "name": "phone_number", "type": "Edm.String", "sortable": false, "searchable": true, "filterable": false, "facetable": false, "analyzer": "phone_analyzer" } ], "analyzers": [ { "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer", "name": "phone_analyzer", "tokenizer": "keyword_v2", "tokenFilters": [ "custom_ngram_filter" ], "charFilters": [ "phone_char_mapping" ] } ], "charFilters": [ { "@odata.type": "#Microsoft.Azure.Search.MappingCharFilter", "name": "phone_char_mapping", "mappings": [ "-=>", "(=>", ")=>", "+=>", ".=>", "\\u0020=>" ] } ], "tokenFilters": [ { "@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2", "name": "custom_ngram_filter", "minGram": 3, "maxGram": 20 } ] }
Testar o analisador personalizado
Depois de recriar o índice, teste o analisador usando a seguinte solicitação:
POST {{baseUrl}}/indexes/tutorial-first-analyzer/analyze?api-version=2024-07-01 HTTP/1.1
Content-Type: application/json
api-key: {{apiKey}}
{
"text": "+1 (321) 555-0199",
"analyzer": "phone_analyzer"
}
Agora você deve ver a coleção de tokens resultantes do número de telefone.
{
"tokens": [
{
"token": "132",
"startOffset": 1,
"endOffset": 17,
"position": 0
},
{
"token": "1321",
"startOffset": 1,
"endOffset": 17,
"position": 0
},
{
"token": "13215",
"startOffset": 1,
"endOffset": 17,
"position": 0
},
...
...
...
]
}
Revisar o analisador personalizado para lidar com falsos positivos
Depois de usares o analisador personalizado para fazeres consultas de amostra no índice, deverás perceber que a abrangência melhorou e todos os números de telefone correspondentes agora são apresentados. No entanto, o filtro de token n-gram também faz com que alguns falsos positivos sejam retornados. Este é um efeito colateral comum de um filtro de token de n-grama.
Para evitar falsos positivos, crie um analisador separado para consulta. Este analisador é idêntico ao anterior, exceto que omite o custom_ngram_filter
.
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer_search",
"tokenizer": "custom_tokenizer_phone",
"tokenFilters": [],
"charFilters": [
"phone_char_mapping"
]
}
Na definição de índice, especifique um indexAnalyzer
e um searchAnalyzer
.
{
"name": "phone_number",
"type": "Edm.String",
"sortable": false,
"searchable": true,
"filterable": false,
"facetable": false,
"indexAnalyzer": "phone_analyzer",
"searchAnalyzer": "phone_analyzer_search"
}
Com essa mudança, você está pronto. Eis os passos seguintes:
Exclua o índice.
Recrie o índice depois de adicionar o novo analisador personalizado (
phone_analyzer-search
) e atribua esse analisador à propriedadephone-number
do camposearchAnalyzer
.Recarregue os dados.
Teste novamente as consultas para verificar se a pesquisa funciona conforme o esperado. Se você estiver usando o arquivo de exemplo, esta etapa criará o terceiro índice chamado
phone-number-index-3
.
Abordagens alternativas
O analisador descrito na seção anterior foi projetado para maximizar a flexibilidade de pesquisa. No entanto, fá-lo à custa do armazenamento de muitos termos potencialmente sem importância no índice.
O exemplo a seguir mostra um analisador alternativo que é mais eficiente na tokenização, mas tem desvantagens.
Dada uma entrada de 14255550100
, o analisador não pode logicamente dividir o número de telefone. Por exemplo, não é possível separar o código do país, 1
, do código de área, 425
. Esta discrepância faz com que o número de telefone não seja devolvido se um utilizador não incluir um código de país na sua pesquisa.
"analyzers": [
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer_shingles",
"tokenizer": "custom_tokenizer_phone",
"tokenFilters": [
"custom_shingle_filter"
]
}
],
"tokenizers": [
{
"@odata.type": "#Microsoft.Azure.Search.StandardTokenizerV2",
"name": "custom_tokenizer_phone",
"maxTokenLength": 4
}
],
"tokenFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.ShingleTokenFilter",
"name": "custom_shingle_filter",
"minShingleSize": 2,
"maxShingleSize": 6,
"tokenSeparator": ""
}
]
No exemplo a seguir, o número de telefone é dividido em partes que normalmente espera-se que um utilizador procure.
Entrada | Saída |
---|---|
(321) 555-0199 |
[321, 555, 0199, 321555, 5550199, 3215550199] |
Dependendo das suas necessidades, esta pode ser uma abordagem mais eficiente para o problema.
Conclusões
Este tutorial demonstrou o processo de criação e teste de um analisador personalizado. Você criou um índice, indexou dados e, em seguida, consultou o índice para ver quais resultados de pesquisa foram retornados. A partir daí, você usou a API Analyze para ver o processo de análise lexical em ação.
Embora o analisador definido neste tutorial ofereça uma solução fácil para pesquisar números de telefone, esse mesmo processo pode ser usado para criar um analisador personalizado para qualquer cenário que compartilhe características semelhantes.
Limpar recursos
Quando estiver a trabalhar com a sua própria subscrição, é aconselhável remover os recursos de que já não necessita no final de um projeto. Os recursos que deixar em execução podem custar dinheiro. Pode eliminar recursos individualmente ou eliminar o grupo de recursos para eliminar todo o conjunto de recursos.
Você pode localizar e gerenciar recursos no portal do Azure, usando o link Todos os recursos ou Grupos de recursos no painel de navegação esquerdo.
Próximos passos
Agora que você sabe como criar um analisador personalizado, dê uma olhada em todos os diferentes filtros, tokenizadores e analisadores disponíveis para criar uma experiência de pesquisa rica: