Självstudie: Skapa en anpassad analysator för telefonnummer
I söklösningar kan strängar som har komplexa mönster eller specialtecken vara en utmaning att arbeta med eftersom standardanalysverktyget tar bort eller feltolkar meningsfulla delar av ett mönster, vilket resulterar i en dålig sökupplevelse när användarna inte kan hitta den information de förväntade sig. Telefonnummer är ett klassiskt exempel på strängar som är svåra att analysera. De finns i olika format och innehåller specialtecken som standardanalysatorn ignorerar.
Med telefonnummer som ämne tar den här självstudiekursen en närmare titt på problemen med mönstrade data och visar hur du löser problemet med hjälp av en anpassad analysator. Metoden som beskrivs här kan användas som den är för telefonnummer eller anpassas för fält med samma egenskaper (mönstrade, med specialtecken), till exempel URL:er, e-postmeddelanden, postnummer och datum.
I den här självstudien använder du en REST-klient och REST API:er för Azure AI Search för att:
- Förstå problemet
- Utveckla en första anpassad analysator för hantering av telefonnummer
- Testa den anpassade analysatorn
- Iterera anpassad analysdesign för att ytterligare förbättra resultaten
Förutsättningar
Följande tjänster och verktyg krävs för den här självstudien.
Visual Studio Code med en REST-klient.
Azure AI Search. Skapa eller hitta en befintlig Azure AI Search-resurs under din aktuella prenumeration. Du kan använda en kostnadsfri tjänst för den här snabbstarten.
Ladda ned filer
Källkoden för den här självstudien är filen custom-analyzer.rest i GitHub-lagringsplatsen Azure-Samples/azure-search-rest-samples .
Kopiera en nyckel och EN URL
REST-anropen i den här självstudien kräver en slutpunkt för söktjänsten och en api-nyckel för administratörer. Du kan hämta dessa värden från Azure Portal.
Logga in på Azure Portal, gå till sidan Översikt och kopiera URL:en. Här följer ett exempel på hur en slutpunkt kan se ut:
https://mydemo.search.windows.net
.Under Inställningar>Nycklar kopierar du en administratörsnyckel. Administratörsnycklar används för att lägga till, ändra och ta bort objekt. Det finns två utbytbara administratörsnycklar. Kopiera någon av dem.
En giltig API-nyckel upprättar förtroende per begäran mellan programmet som skickar begäran och söktjänsten som hanterar den.
Skapa ett första index
Öppna en ny textfil i Visual Studio Code.
Ange variabler till sökslutpunkten och API-nyckeln som du samlade in i föregående steg.
@baseUrl = PUT-YOUR-SEARCH-SERVICE-URL-HERE @apiKey = PUT-YOUR-ADMIN-API-KEY-HERE
Spara filen med ett
.rest
filnamnstillägg.Klistra in i följande exempel för att skapa ett litet index med namnet
phone-numbers-index
med två fält:id
ochphone_number
. Vi har inte definierat någon analysator än, såstandard.lucene
analysatorn används som standard.### 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 } ] }
Välj Skicka begäran. Du bör ha ett
HTTP/1.1 201 Created
svar och svarstexten bör innehålla JSON-representationen av indexschemat.Läs in data i indexet med dokument som innehåller olika telefonnummerformat. Det här är dina testdata.
### 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" } ] }
Nu ska vi prova några frågor som liknar vad en användare kan skriva. En användare kan söka efter
(425) 555-0100
i valfritt antal format och fortfarande förvänta sig att resultat returneras. Börja med att söka i(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}}
Frågan returnerar tre av fyra förväntade resultat, men returnerar också två oväntade resultat:
{ "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" } ] }
Nu ska vi försöka igen utan formatering:
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}}
Den här frågan är ännu värre och returnerar bara en av fyra korrekta matchningar.
{ "value": [ { "@search.score": 0.6015292, "phone_number": "4255550100" } ] }
Om du tycker att de här resultaten är förvirrande är du inte ensam. I nästa avsnitt ska vi gå in på varför vi får dessa resultat.
Granska hur analysverktyg fungerar
För att förstå dessa sökresultat måste vi förstå vad analysatorn gör. Därifrån kan vi testa standardanalysatorn med hjälp av Analys-API:et, vilket ger en grund för att utforma en analysator som bättre uppfyller våra behov.
En analysverktyg är en komponent i sökmotorn i fulltext som ansvarar för bearbetning av text i frågesträngar och indexerade dokument. Olika analysverktyg manipulerar text på olika sätt beroende på scenariot. I det här scenariot måste vi skapa en analysator som är skräddarsydd för telefonnummer.
Analysverktyg består av tre komponenter:
- Teckenfilter som tar bort eller ersätter enskilda tecken från indatatexten.
- En tokeniserare som bryter indatatexten i token, som blir nycklar i sökindexet.
- Tokenfilter som ändrar token som skapas av tokenizern.
I följande diagram kan du se hur dessa tre komponenter fungerar tillsammans för att tokenisera en mening:
Dessa token lagras sedan i ett inverterat index, vilket möjliggör snabba fulltextsökningar. Ett inverterat index möjliggör fulltextsökning genom att mappa alla unika termer som extraheras under lexikal analys till de dokument där de inträffar. Du kan se ett exempel i nästa diagram:
All sökning handlar om att söka efter de termer som lagras i det inverterade indexet. När en användare utfärdar en fråga:
- Frågan parsas och frågetermerna analyseras.
- Det inverterade indexet genomsöks sedan efter dokument med matchande termer.
- Slutligen rangordnas de hämtade dokumenten efter bedömningsalgoritmen.
Om frågetermerna inte matchar termerna i ditt inverterade index returneras inte resultaten. Mer information om hur frågor fungerar finns i den här artikeln om fulltextsökning.
Kommentar
Partiella termfrågor är ett viktigt undantag till den här regeln. Dessa frågor (prefixfråga, jokerteckenfråga, regex-fråga) kringgår den lexikala analysprocessen till skillnad från vanliga termfrågor. Partiella termer sänks bara innan de matchas mot termer i indexet. Om en analysator inte har konfigurerats för att stödja den här typen av frågor får du ofta oväntade resultat eftersom matchande termer inte finns i indexet.
Testa analysverktyg med hjälp av Analys-API:et
Azure AI Search tillhandahåller ett Analys-API som gör att du kan testa analysverktyg för att förstå hur de bearbetar text.
Analys-API:et anropas med hjälp av följande begäran:
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"
}
API:et returnerar de token som extraherats från texten med hjälp av analysatorn som du angav. Lucene-standardanalysatorn delar upp telefonnumret i tre separata token:
{
"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
}
]
}
Omvänt tokeniseras telefonnumret 4255550100
som formateras utan skiljetecken till en enda token.
{
"text": "4255550100",
"analyzer": "standard.lucene"
}
Svar:
{
"tokens": [
{
"token": "4255550100",
"startOffset": 0,
"endOffset": 10,
"position": 0
}
]
}
Tänk på att både frågetermer och indexerade dokument genomgår analys. När vi tänker tillbaka på sökresultaten från föregående steg kan vi börja se varför dessa resultat returnerades.
I den första frågan returnerades oväntade telefonnummer eftersom en av deras token, 555
, matchade ett av de termer som vi sökte i. I den andra frågan returnerades bara ett tal eftersom det var den enda posten som hade en token som matchade 4255550100
.
Skapa en anpassad analys
Nu när vi förstår de resultat vi ser ska vi skapa en anpassad analysator för att förbättra tokeniseringslogiken.
Målet är att ge intuitiv sökning mot telefonnummer oavsett vilket format frågan eller den indexerade strängen finns i. För att uppnå det här resultatet anger vi ett teckenfilter, en tokenizer och ett tokenfilter.
Teckenfilter
Teckenfilter används för att bearbeta text innan den matas in i tokenizern. Vanliga användningsområden för teckenfilter är att filtrera bort HTML-element eller ersätta specialtecken.
För telefonnummer vill vi ta bort blanksteg och specialtecken eftersom inte alla telefonnummerformat innehåller samma specialtecken och blanksteg.
"charFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.MappingCharFilter",
"name": "phone_char_mapping",
"mappings": [
"-=>",
"(=>",
")=>",
"+=>",
".=>",
"\\u0020=>"
]
}
]
Filtret tar bort -
+
(
)
.
och blanksteg från indata.
Indata | Utdata |
---|---|
(321) 555-0199 |
3215550199 |
321.555.0199 |
3215550199 |
Tokenizers
Tokenizers delar upp text i token och tar bort vissa tecken, till exempel skiljetecken, längs vägen. I många fall är målet med tokenisering att dela upp en mening i enskilda ord.
I det här scenariot använder vi en nyckelordstokeniserare, keyword_v2
, eftersom vi vill avbilda telefonnumret som en enda term. Observera att detta inte är det enda sättet att lösa det här problemet. Se avsnittet Alternativa metoder nedan.
Nyckelordstokeniserare matar alltid ut samma text som den angavs som en enda term.
Indata | Utdata |
---|---|
The dog swims. |
[The dog swims.] |
3215550199 |
[3215550199] |
Tokenfilter
Tokenfilter filtrerar bort eller ändrar de token som genereras av tokenizern. En vanlig användning av ett tokenfilter är att ge gemener alla tecken med hjälp av ett tokenfilter med gemener. En annan vanlig användning är att filtrera bort stoppord som the
, and
eller is
.
Även om vi inte behöver använda något av dessa filter för det här scenariot använder vi ett nGram-tokenfilter för att tillåta partiella sökningar av telefonnummer.
"tokenFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2",
"name": "custom_ngram_filter",
"minGram": 3,
"maxGram": 20
}
]
NGramTokenFilterV2
Filtret nGram_v2 token delar upp token i n-gram av en viss storlek baserat på parametrarna minGram
ochmaxGram
.
För telefonanalysen anger minGram
vi till 3
eftersom det är den kortaste delsträngen som vi förväntar oss att användarna ska söka efter. maxGram
är inställd på att se till 20
att alla telefonnummer, även med tillägg, får plats i ett enda n-gram.
Den olyckliga bieffekten av n-gram är att vissa falska positiva kommer att returneras. Vi åtgärdar detta i ett senare steg genom att skapa en separat analysator för sökningar som inte innehåller tokenfiltret n-gram.
Indata | Utdata |
---|---|
[12345] |
[123, 1234, 12345, 234, 2345, 345] |
[3215550199] |
[321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ] |
Analyzer
Med våra teckenfilter, tokenizer- och tokenfilter på plats är vi redo att definiera vår analys.
"analyzers": [
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer",
"tokenizer": "keyword_v2",
"tokenFilters": [
"custom_ngram_filter"
],
"charFilters": [
"phone_char_mapping"
]
}
]
Med hjälp av följande indata från analys-API:et visas utdata från den anpassade analysatorn i följande tabell.
Indata | Utdata |
---|---|
12345 |
[123, 1234, 12345, 234, 2345, 345] |
(321) 555-0199 |
[321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ] |
Alla token i utdatakolumnen finns i indexet. Om vår fråga innehåller någon av dessa villkor returneras telefonnumret.
Återskapa med hjälp av den nya analysatorn
Ta bort det aktuella indexet:
### Delete the index DELETE {{baseUrl}}/indexes/phone-numbers-index?api-version=2024-07-01 HTTP/1.1 api-key: {{apiKey}}
Återskapa indexet med hjälp av den nya analysatorn. Det här indexschemat lägger till en anpassad analysatordefinition och en anpassad analystilldelning i fältet telefonnummer.
### 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 } ] }
Testa den anpassade analysatorn
När du har återskapat indexet kan du nu testa analysatorn med hjälp av följande begäran:
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"
}
Nu bör du se samlingen med token som är resultatet av telefonnumret:
{
"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
},
...
...
...
]
}
Ändra den anpassade analysatorn för att hantera falska positiva identifieringar
När du har gjort några exempelfrågor mot indexet med den anpassade analysatorn upptäcker du att återkallandet har förbättrats och att alla matchande telefonnummer nu returneras. Men filtret för n-gram-token gör att även vissa falska positiva identifieringar returneras. Detta är en vanlig bieffekt av ett n-gram tokenfilter.
För att förhindra falska positiva identifieringar skapar vi en separat analysator för frågor. Den här analysatorn är identisk med den tidigare, förutom att den utelämnar custom_ngram_filter
.
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer_search",
"tokenizer": "custom_tokenizer_phone",
"tokenFilters": [],
"charFilters": [
"phone_char_mapping"
]
}
I indexdefinitionen anger vi sedan både en indexAnalyzer
och en searchAnalyzer
.
{
"name": "phone_number",
"type": "Edm.String",
"sortable": false,
"searchable": true,
"filterable": false,
"facetable": false,
"indexAnalyzer": "phone_analyzer",
"searchAnalyzer": "phone_analyzer_search"
}
Med den här ändringen är du redo. Här följer nästa steg:
Ta bort indexet.
Återskapa indexet när du har lagt till den nya anpassade analysatorn (
phone_analyzer-search
) och tilldela analysatorn tillphone-number
fältetssearchAnalyzer
egenskap.Ladda om data.
Testa frågorna igen för att verifiera att sökningen fungerar som förväntat. Om du använder exempelfilen skapar det här steget det tredje indexet med namnet
phone-number-index-3
.
Alternativa sätt
Analysatorn som beskrivs i föregående avsnitt är utformad för att maximera flexibiliteten för sökning. Men det gör det på bekostnad av att lagra många potentiellt oviktiga termer i indexet.
I följande exempel visas en alternativ analysator som är effektivare vid tokenisering, men som har nackdelar.
Med en indata av 14255550100
kan analysatorn inte logiskt segmentera telefonnumret. Det kan till exempel inte skilja landskoden, 1
, från riktnumret, 425
. Den här avvikelsen skulle leda till att telefonnumret inte returneras om en användare inte tog med någon landskod i sökningen.
"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": ""
}
]
I följande exempel ser du att telefonnumret är uppdelat i de segment som du normalt förväntar dig att en användare söker efter.
Indata | Utdata |
---|---|
(321) 555-0199 |
[321, 555, 0199, 321555, 5550199, 3215550199] |
Beroende på dina krav kan detta vara en effektivare metod för problemet.
Lärdomar
I den här självstudien demonstrerades processen för att skapa och testa en anpassad analysator. Du skapade ett index, indexerade data och frågade sedan mot indexet för att se vilka sökresultat som returnerades. Därifrån använde du Analysera API för att se den lexikala analysprocessen i praktiken.
Även om analysatorn som definieras i den här självstudien erbjuder en enkel lösning för sökning mot telefonnummer, kan samma process användas för att skapa en anpassad analysator för alla scenarion som har liknande egenskaper.
Rensa resurser
När du arbetar i din egen prenumeration är det en bra idé att ta bort de resurser som du inte längre behöver i slutet av ett projekt. Resurser som fortsätter att köras kostar pengar. Du kan ta bort enstaka resurser eller hela resursgruppen om du vill ta bort alla resurser.
Du kan hitta och hantera resurser i Azure Portal med hjälp av länken Alla resurser eller Resursgrupper i det vänstra navigeringsfönstret.
Nästa steg
Nu när du är bekant med hur du skapar en anpassad analysator ska vi ta en titt på alla olika filter, tokenizers och analysverktyg som är tillgängliga för dig för att skapa en omfattande sökupplevelse.