Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você 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 desafiadoras para 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 em que os usuários não conseguem encontrar as informações esperadas. 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 está para números de telefone ou adaptada para campos com as mesmas características (padronizadas com caracteres especiais), como URLs, emails, códigos postais e datas.
Neste tutorial, você vai usar um cliente REST e as APIs REST da Pesquisa de IA do Azure para:
- Compreender o problema
- Desenvolver um analisador personalizado inicial para lidar com números de telefone
- Testar o analisador personalizado
- Interagir com o design do analisador personalizado para aprimorar ainda mais os resultados
Pré-requisitos
Uma conta do Azure com uma assinatura ativa. Crie uma conta gratuitamente.
Pesquisa de IA do Azure. Crie um serviço ou localize um serviço existente em sua assinatura atual. Para este tutorial, você pode usar um serviço gratuito.
Visual Studio Code com um cliente REST.
Baixar arquivos
O código-fonte deste tutorial está no arquivo custom-analyzer.rest no repositório GitHub do Azure-Samples/azure-search-rest-samples .
Copiar uma chave de administrador e uma URL
As chamadas REST neste tutorial requerem um endpoint de serviço de pesquisa e uma chave de API de administrador. 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 de extremidade de exemplo pode parecer com
https://mydemo.search.windows.net.Em Configurações>Chaves, copie uma chave de administrador. As chaves de administrador são usadas para adicionar, modificar e excluir objetos. Há duas chaves de administrador intercambiáveis. Copie uma delas.
Uma chave de API válida estabelece a confiança, por solicitação, entre o aplicativo que envia a solicitação e o serviço de pesquisa que a está tratando.
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-HERESalve o arquivo com uma extensão de arquivo
.rest.Cole o exemplo a seguir para criar um índice pequeno chamado
phone-numbers-indexcom dois campos:idephone_number. Você ainda não definiu um analisador, portanto, ostandard.luceneanalisador é usado por padrão.### Create a new index POST {{baseUrl}}/indexes?api-version=2025-09-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 solicitação. Você deve ter uma
HTTP/1.1 201 Createdresposta e o corpo da resposta deve incluir a representação JSON do esquema de índice.Carregue dados no índice usando documentos contendo vários formatos de número de telefone. Esses serão seus dados de teste.
### Load documents POST {{baseUrl}}/indexes/phone-numbers-index/docs/index?api-version=2025-09-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" } ] }Experimente consultas semelhantes ao que um usuário pode digitar. Por exemplo, um usuário pode pesquisar
(425) 555-0100em qualquer número de formatos e ainda esperar que os resultados sejam retornados. Comece pesquisando(425) 555-0100.### Search for a phone number GET {{baseUrl}}/indexes/phone-numbers-index/docs/search?api-version=2025-09-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 nenhuma formatação:
4255550100.### Search for a phone number GET {{baseUrl}}/indexes/phone-numbers-index/docs/search?api-version=2025-09-01&search=4255550100 HTTP/1.1 Content-Type: application/json api-key: {{apiKey}}Essa consulta apresenta um resultado ainda pior, retornando apenas uma de quatro correspondências corretas.
{ "value": [ { "@search.score": 0.6015292, "phone_number": "4255550100" } ] }
Se você considera esses resultados confusos, 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 da pesquisa, você deve entender o que o analisador está fazendo. A partir daí, você pode testar o analisador padrão usando a API analisar, fornecendo uma base para criar 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. Analisadores diferentes manipulam texto de maneiras diferentes, dependendo do cenário. Para esse cenário, precisamos criar um analisador personalizado para números de telefone.
Os analisadores consistem em três componentes:
- Filtros de caractere 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 criador de token.
O diagrama a seguir mostra como esses três componentes funcionam juntos para tokenizar uma frase.
Esses tokens são então armazenados em um índice invertido, que permite pesquisas rápidas de texto completo. Um índice invertido permite a pesquisa de texto completo mapeando todos os termos exclusivos extraídos durante a análise lexical para os documentos em que eles ocorrem. Você pode ver um exemplo no diagrama a seguir:
Toda a pesquisa se resume a procurar os termos armazenados no índice invertido. Quando o usuário emite uma consulta:
- A consulta é analisada e os termos da consulta são analisados.
- O índice invertido é verificado 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 no seu índice invertido, não serão retornados resultados. Para saber mais sobre como as consultas funcionam, consulte a pesquisa de texto completo no Azure AI Search.
Observação
As consultas de termo parcial são uma exceção importante a essa 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 minúsculos antes de serem combinados com relação aos termos no índice. Se um analisador não estiver configurado para dar suporte a esses tipos de consultas, você geralmente receberá resultados inesperados porque os termos correspondentes não existem no índice.
Testar analisadores usando a API de Análise
A Pesquisa de IA do Azure fornece uma API de Análise que permite testar analisadores para entender como eles processam texto.
Use a API Analyze com a seguinte solicitação:
POST {{baseUrl}}/indexes/phone-numbers-index/analyze?api-version=2025-09-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 que você especificou. 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
}
]
}
De modo inverso, o número de telefone 4255550100 formatado sem 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 termos de consulta quanto documentos indexados são analisados. 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 corresponde 555a um dos termos pesquisados. Na segunda consulta, somente o um número é retornado porque é o único registro que tem um token correspondendo a 4255550100.
Compilar um analisador personalizado
Agora que você entende os resultados que está vendo, crie um analisador personalizado para melhorar a lógica de tokenização.
A meta é fornecer uma pesquisa intuitiva em relação aos números de telefone, independentemente do formato em que a consulta ou a cadeia de caracteres indexada está. Para obter esse resultado, especifique um filtro de caractere, um tokenizador e um filtro de token.
Filtros de caractere
Os filtros de caracteres processam o texto antes de ser enviado ao tokenizador. Os usos comuns de filtros de caractere são filtrar elementos HTML e substituir caracteres especiais.
Para números de telefone, você deseja remover o espaço em branco e caracteres especiais porque nem todos os formatos de número de telefone contêm os mesmos caracteres e espaços especiais.
"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 |
Criadores de token
Tokenizadores dividem o texto em tokens e descartam alguns caracteres, como pontuação, no processo. Em muitos casos, a meta da geração de tokens é dividir uma frase em palavras individuais.
Para esse cenário, use um tokenizador keyword_v2de palavra-chave para capturar o número de telefone como um único termo. Essa não é a única maneira de resolver esse problema, conforme explicado na seção Abordagens alternativas .
Os tokenizadores de palavra-chave sempre geram 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 é colocar todos os caracteres em letras minúsculas usando um filtro de token em minúsculas. Outro uso comum é filtrar stopwords, 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 tokens nGram_v2 divide tokens em n-gramas de um determinado tamanho com base nos parâmetros minGram e maxGram.
Para o analisador de telefone, minGram é definido como 3 porque essa é a subcadeia de caracteres mais curta que os usuários devem pesquisar.
maxGram é definido como 20 para garantir que todos os números de telefone, mesmo com extensões, caibam em um único n-grama.
O infeliz efeito colateral de n-gram é que alguns falsos positivos são retornados. Você corrige isso em uma etapa posterior criando um analisador separado para pesquisas que não incluem o filtro de token n-gram.
| 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 caractere, o tokenizador e os filtros de token em vigor, 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"
]
}
]
Na API analisar, 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 consulta incluir qualquer um desses termos, o número de telefone será retornado.
Recompilar usando o novo analisador
Exclua o índice atual.
### Delete the index DELETE {{baseUrl}}/indexes/phone-numbers-index?api-version=2025-09-01 HTTP/1.1 api-key: {{apiKey}}Recrie o índice usando o novo analisador. Esse esquema de índice adiciona uma definição de analisador personalizado e uma atribuição de analisador personalizado no campo número de telefone.
### Create a new index POST {{baseUrl}}/indexes?api-version=2025-09-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=2025-09-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 usar o analisador personalizado para fazer consultas de exemplo no índice, você deverá ver que o recall melhorou e todos os números de telefone correspondentes agora são retornados. No entanto, o filtro de token n-gram também faz com que alguns falsos positivos sejam retornados. Esse é um efeito colateral comum de um filtro de token de n-gram.
Para evitar falsos positivos, crie um analisador separado para consulta. Esse analisador é idêntico ao anterior, exceto pelo fato de omitir 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 alteração, você está pronto. Estas são as próximas etapas:
Excluir o índice.
Recrie o índice depois de adicionar o novo analisador personalizado (
phone_analyzer-search) e atribua esse analisador à propriedadephone-numberdo camposearchAnalyzer.Recarregue os dados.
Repita as consultas para verificar se a pesquisa funciona conforme o esperado. Se você estiver usando a amostra de arquivo, essa 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 da pesquisa. No entanto, ele faz isso com o custo de armazenar muitos termos potencialmente não importantes no índice.
O exemplo a seguir mostra um analisador alternativo que é mais eficiente na tokenização, mas tem desvantagens.
Considerando-se uma entrada de 14255550100, o analisador não consegue dividir o número de telefone logicamente. Por exemplo, não consegue separar o código de país, 1, do código de área, 425. Essa discrepância faz com que o número de telefone não seja retornado se um usuário não incluir um código de país em 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 nas partes que você normalmente espera que um usuário pesquise.
| Entrada | Saída |
|---|---|
(321) 555-0199 |
[321, 555, 0199, 321555, 5550199, 3215550199] |
Dependendo dos seus requisitos, pode ser uma abordagem do problema mais eficiente.
Observações
Este tutorial demonstrou o processo de criação e teste de um analisador personalizado. Você criou um índice, indexou dados e consultou em relação ao índice para ver quais resultados da pesquisa eram retornados. A partir daí, você usou a API de Análise para ver o processo de análise léxica 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 apresente características semelhantes.
Limpar os recursos
Quando você está trabalhando em sua assinatura, é uma boa ideia remover os recursos que já não são necessários no final de um projeto. Recursos deixados em execução podem custar dinheiro. É possível excluir os recursos individualmente ou excluir o grupo de recursos para excluir todo o conjunto de recursos.
Você pode encontrar e gerenciar recursos no portal do Azure usando o link "Todos os recursos" ou "Grupos de recursos" no painel de navegação do lado esquerdo.
Próximas etapas
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 avançada: