Kurz: Vytvoření vlastního analyzátoru pro telefonní čísla
Ve vyhledávacích řešeních můžou být řetězce se složitými vzory nebo speciálními znaky náročné na práci, protože výchozí analyzátor odstraní nebo nesprávně interpretuje smysluplné části vzoru, což vede k špatnému vyhledávání, když uživatelé nemůžou najít očekávané informace. Telefonní čísla jsou klasickým příkladem řetězců, které se obtížně analyzují. Mají různé formáty a obsahují speciální znaky, které výchozí analyzátor ignoruje.
S telefonními čísly jako předmětem tohoto kurzu se blíže podíváme na problémy se vzorovými daty a ukáže vám, jak tento problém vyřešit pomocí vlastního analyzátoru. Zde uvedený přístup lze použít jako pro telefonní čísla nebo přizpůsobit polím se stejnými vlastnostmi (vzorovanými znaky), jako jsou adresy URL, e-maily, PSČ a kalendářní data.
V tomto kurzu použijete klienta REST a rozhraní REST API služby Azure AI Search k:
- Pochopení problému
- Vývoj počátečního vlastního analyzátoru pro zpracování telefonních čísel
- Testování vlastního analyzátoru
- Iterace návrhu vlastního analyzátoru za účelem dalšího zlepšení výsledků
Požadavky
Pro účely tohoto kurzu jsou vyžadovány následující služby a nástroje.
Visual Studio Code s klientem REST
Azure AI Search. Vytvořte nebo najděte existující prostředek služby Azure AI Search v rámci vašeho aktuálního předplatného. Pro účely tohoto rychlého startu můžete použít bezplatnou službu.
Stažení souborů
Zdrojový kód pro tento kurz je soubor custom-analyzer.rest v úložišti Azure-Samples/azure-search-rest-samples na GitHubu.
Zkopírování klíče a adresy URL
Volání REST v tomto kurzu vyžadují koncový bod vyhledávací služby a klíč rozhraní API pro správu. Tyto hodnoty můžete získat z webu Azure Portal.
Přihlaste se k webu Azure Portal, přejděte na stránku Přehled a zkopírujte adresu URL. Příkladem koncového bodu může být
https://mydemo.search.windows.net
.V části Klíče nastavení>zkopírujte klíč správce. Klíče správce slouží k přidávání, úpravám a odstraňování objektů. Existují dva zaměnitelné klíče správce. Zkopírujte jeden z nich.
Platný klíč rozhraní API vytváří na základě požadavku vztah důvěryhodnosti mezi aplikací, která požadavek odesílá, a vyhledávací službou, která ji zpracovává.
Vytvoření počátečního indexu
Otevřete nový textový soubor v editoru Visual Studio Code.
Nastavte proměnné na koncový bod vyhledávání a klíč rozhraní API, který jste shromáždili v předchozím kroku.
@baseUrl = PUT-YOUR-SEARCH-SERVICE-URL-HERE @apiKey = PUT-YOUR-ADMIN-API-KEY-HERE
Uložte soubor s příponou
.rest
souboru.Vložte následující příklad pro vytvoření malého indexu volaný
phone-numbers-index
se dvěma poli:id
aphone_number
. Ještě jsme nedefinují analyzátor, takžestandard.lucene
analyzátor se používá ve výchozím nastavení.### 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 } ] }
Vyberte Odeslat žádost. Měli byste mít
HTTP/1.1 201 Created
odpověď a text odpovědi by měl obsahovat reprezentaci JSON schématu indexu.Načtěte data do indexu pomocí dokumentů, které obsahují různé formáty telefonních čísel. Toto jsou vaše testovací data.
### 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" } ] }
Pojďme vyzkoušet několik dotazů podobných tomu, co uživatel může zadat. Uživatel může hledat
(425) 555-0100
v libovolném počtu formátů a stále očekává vrácení výsledků. Začněte hledáním(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}}
Dotaz vrátí tři ze čtyř očekávaných výsledků, ale také dva neočekávané výsledky:
{ "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" } ] }
Zkusme to znovu bez formátování:
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}}
Tento dotaz je ještě horší a vrací pouze jednu ze čtyř správných shod.
{ "value": [ { "@search.score": 0.6015292, "phone_number": "4255550100" } ] }
Pokud tyto výsledky zjistíte matoucí, nejste sami. V další části se podíváme na to, proč tyto výsledky dostáváme.
Kontrola fungování analyzátorů
Abychom porozuměli těmto výsledkům hledání, musíme pochopit, co analyzátor dělá. Odtud můžeme otestovat výchozí analyzátor pomocí rozhraní API pro analýzu a poskytnout základ pro návrh analyzátoru, který lépe vyhovuje našim potřebám.
Analyzátor je součástí fulltextového vyhledávacího webu zodpovědného za zpracování textu v řetězcích dotazů a indexovaných dokumentech. Různé analyzátory manipulují s textem různými způsoby v závislosti na scénáři. V tomto scénáři potřebujeme vytvořit analyzátor přizpůsobený telefonním číslům.
Analyzátory se skládají ze tří součástí:
- Filtry znaků, které odeberou nebo nahradí jednotlivé znaky ze vstupního textu.
- Tokenizátor, který rozdělí vstupní text na tokeny, které se stanou klíči v indexu vyhledávání.
- Filtry tokenů, které manipulují s tokeny vytvořenými tokenizátorem.
V následujícím diagramu vidíte, jak tyto tři komponenty spolupracují na tokenizaci věty:
Tyto tokeny se pak ukládají do invertovaného indexu, který umožňuje rychlé fulltextové vyhledávání. Invertovaný index umožňuje fulltextové vyhledávání namapováním všech jedinečných termínů extrahovaných během lexikální analýzy na dokumenty, ve kterých k nim dochází. Příklad vidíte v dalším diagramu:
Hledání všech možností spočívá v hledání termínů uložených v invertovaného indexu. Když uživatel vydá dotaz:
- Dotaz se analyzuje a termíny dotazu se analyzují.
- Invertovaný index se pak zkontroluje na dokumenty s odpovídajícími termíny.
- Nakonec načtené dokumenty jsou seřazené podle algoritmu vyhodnocování.
Pokud se termíny dotazu neshodují s termíny v inverzním indexu, výsledky se nevrátí. Další informace o fungování dotazů najdete v tomto článku o fulltextovém vyhledávání.
Poznámka:
Částečné dotazy termínů jsou důležitou výjimkou tohoto pravidla. Tyto dotazy (dotaz předpony, dotaz se zástupnými čísly, dotaz regex) obcházejí proces lexikální analýzy na rozdíl od běžných dotazů termínů. Částečné termíny jsou před porovnáním s termíny v indexu pouze nižší. Pokud není analyzátor nakonfigurovaný tak, aby podporoval tyto typy dotazů, často dostanete neočekávané výsledky, protože odpovídající termíny v indexu neexistují.
Testování analyzátorů pomocí rozhraní API pro analýzu
Azure AI Search poskytuje rozhraní API pro analýzu, které umožňuje testovat analyzátory, abyste pochopili, jak zpracovávají text.
Rozhraní API pro analýzu se volá pomocí následujícího požadavku:
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"
}
Rozhraní API vrátí tokeny extrahované z textu pomocí analyzátoru, který jste zadali. Standardní analyzátor Lucene rozdělí telefonní číslo na tři samostatné tokeny:
{
"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
}
]
}
Naopak telefonní číslo 4255550100
formátované bez interpunkce je tokenizováno do jednoho tokenu.
{
"text": "4255550100",
"analyzer": "standard.lucene"
}
Odpověď:
{
"tokens": [
{
"token": "4255550100",
"startOffset": 0,
"endOffset": 10,
"position": 0
}
]
}
Mějte na paměti, že termíny dotazu i indexované dokumenty procházejí analýzou. Když se vrátíme k výsledkům hledání z předchozího kroku, můžeme začít vidět, proč se tyto výsledky vrátily.
V prvním dotazu se vrátila neočekávaná telefonní čísla, protože jeden z jejich tokenů , odpovídal jednomu z hledaných termínů 555
. V druhém dotazu se vrátilo pouze jedno číslo, protože se jednalo o jediný záznam, který měl odpovídající 4255550100
token .
Vytvoření vlastního analyzátoru
Teď, když rozumíme výsledkům, které vidíme, vytvoříme vlastní analyzátor, abychom zlepšili logiku tokenizace.
Cílem je poskytovat intuitivní vyhledávání telefonních čísel bez ohledu na formát dotazu nebo indexovaného řetězce. K dosažení tohoto výsledku určíme filtr znaků, tokenizátor a filtr tokenů.
Filtry znaků
Filtry znaků se používají ke zpracování textu před jeho odesláním do tokenizátoru. Mezi běžné použití filtrů znaků patří filtrování elementů HTML nebo nahrazení speciálních znaků.
U telefonních čísel chceme odebrat prázdné znaky a speciální znaky, protože ne všechny formáty telefonních čísel obsahují stejné speciální znaky a mezery.
"charFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.MappingCharFilter",
"name": "phone_char_mapping",
"mappings": [
"-=>",
"(=>",
")=>",
"+=>",
".=>",
"\\u0020=>"
]
}
]
Filtr odebere -
+
(
)
.
ze vstupu mezery.
Vstup | Výstup |
---|---|
(321) 555-0199 |
3215550199 |
321.555.0199 |
3215550199 |
Tokenizátory
Tokenizátory rozdělují text na tokeny a zahodí některé znaky, jako je interpunkce, po cestě. V mnoha případech je cílem tokenizace rozdělit větu na jednotlivá slova.
V tomto scénáři použijeme tokenizátor klíčových slov, keyword_v2
protože chceme zachytit telefonní číslo jako jeden termín. Všimněte si, že toto není jediný způsob, jak tento problém vyřešit. Podívejte se na část Alternativní přístupy níže.
Tokenizátory klíčových slov vždy vypíše stejný text, který byl udělen jako jeden termín.
Vstup | Výstup |
---|---|
The dog swims. |
[The dog swims.] |
3215550199 |
[3215550199] |
Filtry tokenů
Filtry tokenů vyfiltrují nebo upraví tokeny vygenerované tokenizátorem. Jedním z běžných použití filtru tokenů je malá písmena všech znaků pomocí filtru tokenů malými písmeny. Dalším běžným použitím je filtrování slov, jako the
je , and
nebo is
.
I když pro tento scénář nepotřebujeme použít některý z těchto filtrů, použijeme filtr tokenu nGram, který umožní částečné hledání telefonních čísel.
"tokenFilters": [
{
"@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2",
"name": "custom_ngram_filter",
"minGram": 3,
"maxGram": 20
}
]
NGramTokenFilterV2
Filtr tokenů nGram_v2 rozdělí tokeny na n-gramy dané velikosti na minGram
základě parametrů a maxGram
parametrů.
U analyzátoru telefonu jsme nastavili minGram
3
to, že je to nejkratší podřetězení, které očekáváme, že uživatelé budou hledat. maxGram
je nastavena tak, aby 20
se všechna telefonní čísla, i s rozšířeními, vešla do jednoho n-gramu.
Nešťastný vedlejší účinek n-gram je, že některé falešně pozitivní výsledky budou vráceny. Tento problém vyřešíme v pozdějším kroku vytvořením samostatného analyzátoru pro vyhledávání, která neobsahuje filtr tokenů n-gram.
Vstup | Výstup |
---|---|
[12345] |
[123, 1234, 12345, 234, 2345, 345] |
[3215550199] |
[321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ] |
Analyzátor
S našimi filtry znaků, tokenizátorem a filtry tokenů jsme připraveni definovat náš analyzátor.
"analyzers": [
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer",
"tokenizer": "keyword_v2",
"tokenFilters": [
"custom_ngram_filter"
],
"charFilters": [
"phone_char_mapping"
]
}
]
Výstupy z vlastního analyzátoru jsou znázorněny v následující tabulce z rozhraní API Pro analýzu.
Vstup | Výstup |
---|---|
12345 |
[123, 1234, 12345, 234, 2345, 345] |
(321) 555-0199 |
[321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ] |
Všechny tokeny ve výstupním sloupci existují v indexu. Pokud náš dotaz obsahuje některý z těchto termínů, vrátí se telefonní číslo.
Opětovné sestavení pomocí nového analyzátoru
Odstraňte aktuální index:
### Delete the index DELETE {{baseUrl}}/indexes/phone-numbers-index?api-version=2024-07-01 HTTP/1.1 api-key: {{apiKey}}
Znovu vytvořte index pomocí nového analyzátoru. Toto schéma indexu přidá definici vlastního analyzátoru a přiřazení vlastního analyzátoru do pole telefonního čísla.
### 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 } ] }
Testování vlastního analyzátoru
Po opětovném vytvoření indexu teď můžete analyzátor otestovat pomocí následujícího požadavku:
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"
}
Teď byste měli vidět kolekci tokenů vyplývajících z telefonního čísla:
{
"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
},
...
...
...
]
}
Úprava vlastního analyzátoru pro zpracování falešně pozitivních výsledků
Po provedení ukázkových dotazů na index pomocí vlastního analyzátoru zjistíte, že odvolání se zlepšilo a vrátí se všechna odpovídající telefonní čísla. Filtr n-gram tokenů ale také způsobí vrácení některých falešně pozitivních výsledků. Jedná se o běžný vedlejší účinek filtru tokenů n-gram.
Abychom zabránili falešně pozitivním výsledkům, vytvoříme samostatný analyzátor pro dotazování. Tento analyzátor je identický s předchozím, s tím rozdílemcustom_ngram_filter
, že vynechá .
{
"@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "phone_analyzer_search",
"tokenizer": "custom_tokenizer_phone",
"tokenFilters": [],
"charFilters": [
"phone_char_mapping"
]
}
V definici indexu pak určíme jak an indexAnalyzer
, tak i a searchAnalyzer
.
{
"name": "phone_number",
"type": "Edm.String",
"sortable": false,
"searchable": true,
"filterable": false,
"facetable": false,
"indexAnalyzer": "phone_analyzer",
"searchAnalyzer": "phone_analyzer_search"
}
S touto změnou jste všichni nastaveni. Tady jsou další kroky:
Odstraňte index.
Znovu vytvořte index po přidání nového vlastního analyzátoru (
phone_analyzer-search
) a přiřazení analyzátoruphone-number
searchAnalyzer
k vlastnosti pole.Znovu načtěte data.
Znovu otestujte dotazy a ověřte, že hledání funguje podle očekávání. Pokud používáte ukázkový soubor, tento krok vytvoří třetí index s názvem
phone-number-index-3
.
Alternativní přístupy
Analyzátor popsaný v předchozí části je navržený tak, aby maximalizoval flexibilitu vyhledávání. To ale dělá za cenu uložení mnoha potenciálně nedůležitých termínů v indexu.
Následující příklad ukazuje alternativní analyzátor, který je efektivnější v tokenizaci, ale má nevýhody.
Při zadání 14255550100
nemůže analyzátor logicky zasunou telefonní číslo. Například nemůže oddělit kód země , 1
od směrového kódu oblasti, 425
. Tato nesrovnalost by vedla k tomu, že se telefonní číslo nevrácelo, pokud uživatel do hledání nezahrnoval kód země.
"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": ""
}
]
V následujícím příkladu vidíte, že telefonní číslo je rozdělené na bloky dat, které byste normálně očekávali, že uživatel bude hledat.
Vstup | Výstup |
---|---|
(321) 555-0199 |
[321, 555, 0199, 321555, 5550199, 3215550199] |
V závislosti na vašich požadavcích to může být efektivnější přístup k problému.
Shrnutí
V tomto kurzu jsme si ukázali proces sestavení a testování vlastního analyzátoru. Vytvořili jste index, indexovaná data a potom jste se na index dotazovali, abyste zjistili, jaké výsledky hledání se vrátily. Odtud jste použili rozhraní API pro analýzu k zobrazení procesu lexikální analýzy v akci.
I když analyzátor definovaný v tomto kurzu nabízí jednoduché řešení pro vyhledávání na telefonních číslech, stejný proces lze použít k vytvoření vlastního analyzátoru pro jakýkoli scénář, který sdílí podobné charakteristiky.
Vyčištění prostředků
Když pracujete ve vlastním předplatném, je vhodné odebrat prostředky, které už nepotřebujete na konci projektu. Prostředky, které necháte spuštěné, vás stojí peníze. Prostředky můžete odstraňovat jednotlivě nebo můžete odstranit skupinu prostředků, a odstranit tak celou sadu prostředků najednou.
Prostředky můžete najít a spravovat na portálu pomocí odkazu Všechny prostředky nebo skupiny prostředků v levém navigačním podokně.
Další kroky
Teď, když už víte, jak vytvořit vlastní analyzátor, se podíváme na všechny různé filtry, tokenizátory a analyzátory, které máte k dispozici k vytvoření bohatého vyhledávání.