Při ukládání dat do Elasticsearch probíhá na polích typu text textová analýza. Během analýzy Elasticsearch rozdělí text na slova (tokeny), převede je do základní formy (například převede množné číslo na jednotné) a uloží je do speciální datové struktury zvané invertovaný index.
Výchozí analyzér se jmenuje standard. S jeho pomocí je možné implementovat full textové vyhledávání nezávislé na velikosti písmen. Pro kontrolu, jak bude vypadat výsledek analýzy pro daný text lze využít endpoint _analyze:
xxxxxxxxxxPOST _analyze{ "analyzer": "standard", "text": "Order with ID d03fd6k-2da consists of four products."}xxxxxxxxxx{ "tokens" : [ { "token" : "order", "start_offset" : 0, "end_offset" : 5, "type" : "<ALPHANUM>", "position" : 0 }, { "token" : "with", "start_offset" : 6, "end_offset" : 10, "type" : "<ALPHANUM>", "position" : 1 }, { "token" : "id", "start_offset" : 11, "end_offset" : 13, "type" : "<ALPHANUM>", "position" : 2 }, { "token" : "d03fd6k", "start_offset" : 14, "end_offset" : 21, "type" : "<ALPHANUM>", "position" : 3 }, { "token" : "2da", "start_offset" : 22, "end_offset" : 25, "type" : "<ALPHANUM>", "position" : 4 }, { "token" : "consists", "start_offset" : 26, "end_offset" : 34, "type" : "<ALPHANUM>", "position" : 5 }, { "token" : "of", "start_offset" : 35, "end_offset" : 37, "type" : "<ALPHANUM>", "position" : 6 }, { "token" : "four", "start_offset" : 38, "end_offset" : 42, "type" : "<ALPHANUM>", "position" : 7 }, { "token" : "products", "start_offset" : 43, "end_offset" : 51, "type" : "<ALPHANUM>", "position" : 8 } ]}
Při definici mapování lze zvolit, jaký analyzer má být pro dané pole použit. Stejný analyzér pak bude použit i pro vyhledávání.
xxxxxxxxxxPUT data_analyzed{ "mappings": { "properties": { "description": { "type": "text", "analyzer": "standard" } } }}
Přestože bude standard analyzer pro mnoho případů dostačující, při práci s přirozeným jazykem dosáhneme lepších výsledků s specifickými analyzéry pro dané jazyky, tzv. language analyzers. Pro porovnání můžeme vyzkoušet anglický analyzér (english) pro shodný vstupní text:
xxxxxxxxxxPOST _analyze{ "analyzer": "english", "text": "Order with ID d03fd6k-2da consists of four products."}xxxxxxxxxx{ "tokens" : [ { "token" : "order", "start_offset" : 0, "end_offset" : 5, "type" : "<ALPHANUM>", "position" : 0 }, { "token" : "id", "start_offset" : 11, "end_offset" : 13, "type" : "<ALPHANUM>", "position" : 2 }, { "token" : "d03fd6k", "start_offset" : 14, "end_offset" : 21, "type" : "<ALPHANUM>", "position" : 3 }, { "token" : "2da", "start_offset" : 22, "end_offset" : 25, "type" : "<ALPHANUM>", "position" : 4 }, { "token" : "consist", "start_offset" : 26, "end_offset" : 34, "type" : "<ALPHANUM>", "position" : 5 }, { "token" : "four", "start_offset" : 38, "end_offset" : 42, "type" : "<ALPHANUM>", "position" : 7 }, { "token" : "product", "start_offset" : 43, "end_offset" : 51, "type" : "<ALPHANUM>", "position" : 8 } ]}Jazyková analýza navíc převede:
Díky tomu je možné vyhledávat v dokumentech nezávisle na tvarosloví.
Pokud však ani jazyková analýza nedostačuje, je nutné vytvořit vlastní (custom) analyzer. Každý analyzér sestává z tří částí:
Custom analyzer lze definovat v rámci nastavení indexu:
xxxxxxxxxxPUT custom_html_analyzer{ "settings": { "analysis": { "analyzer": { "my_html_analyzer": { "type": "custom", "tokenizer": "standard", "char_filter": ["html_strip"], "filter": ["lowercase", "asciifolding"] } } } }}jakmile je index vytvořen, lze otestovat textovou analýzu:
xxxxxxxxxxPOST custom_html_analyzer/_analyze{ "analyzer": "my_html_analyzer", "text": "<b>Hello</b> world!"}Nejpoužívanější filtry jsou:
html_strip: odstraní HTML značkymapping: nahradí znakypattern_replace: nahradí text dle zadaného regulárního výrazustandard: výchozí tokenizerkeyword: zachová text nerozdělenýletter: vytváří tokeny podle všeho, co není písmenowhitespace: vytváří tokeny pouze podle bílých znakůpattern: token může být reprezentován regulárním výrazemngram a edge_ngram: vytváří tokeny pro našeptávání a fuzzy vyhledáváníuax_url_email: rozdělí e-mailovou adresu na tokenypath_hierarchy: cesty v filesystémuasciifolding, icu_folding: odstranění diakritikylowercase, uppercase: převedení na malá nebo velká písmenastop: odstraní stopslovastemmer: algoritmické převedení slova na základní tvarhunspell: slovníkové převedení slova na základní tvarsynonym: přidá synonyma jako nové tokenyshingle: vytváří sousloví pro frázové vyhledávánílength: odstraní tokeny na základě jejich délkyunique: ponechá pouze unikátní tokeny
Při vytváření českého analyzéru je třeba vzít v úvahu:
xxxxxxxxxxPUT product-czech{ "settings": { "analysis": { "analyzer": { "my_czech": { "type": "custom", "tokenizer": "standard", "filter": [ "stemmer_cs", "lowercase", "stop_cs", "asciifolding", "synonym_cz", "unique" ] } }, "filter": { "stemmer_cs": { "type": "stemmer", "language": "czech" }, "stop_cs": { "type": "stop", "stopwords": [ "_czech_" ] }, "synonym_cz": { "type": "synonym", "synonyms" : [ "lednicka,lednice=>chladnicka" ] } } } }, "mappings": { "properties": { "name": { "type": "text", "analyzer": "my_czech" } } }}
POST product-czech/_analyze{ "analyzer": "my_czech", "text": "Kombinovaná lednička s mrazákem BOSCH KGN39VL35"}
POST product-czech/_doc{ "name": "Chladnička BOSCH KWG22VL30"}
GET product-czech/_search{ "_source": "name", "query": { "match": { "name": "lednicka" } }}Alternativou k algoritmickému stemmeru může být slovníkový, který je v případě Elasticsearch reprezentován hunspell token filtrem. Jakmile přidáte slovníky do konfigurační složky Elasticsearch, můžete nadefinovat v rámci analýzy vlastní filtr:
xxxxxxxxxx..."filter": {"hunspell_cs": {"type": "hunspell","locale": "cs_CZ"},...
Uživatelský vstup často obsahuje chyby ve formě překlepů. Vypořádat se s nimi je možné:
V době dotazu
match query s argumentem fuzziness (pro pole typu text)fuzzy query (pro pole typu keyword)Při indexování dat
ngram tokenizerPři hledání s překlepy dávejte pozor na výkonnost. Fuzzy query může vyhledávání znatelně zpomalit. Na druhé straně při použití n-gramů dochází k nárůstu velikosti indexů.
Alternativou k n-gramům může být suggester (docs). Nabízí rychlé vyhledávání za cenu vyššího využití paměti. Dále není tak konfigurovatelný.
Situace je obdobná jako v předchozím případě s jediným rozdílem: Přesně víme, že hledáme od začátku slova. Opět máme k dispozici obdobné přístupy:
V době dotazu
match_phrase_prefix query pro pole typu textprefix query pro pole typu keywordPři indexování dat
edge_ngram tokenizersearch_as_you_type datový typ:xxxxxxxxxxPUT brands{ "mappings": { "properties": { "name": { "type": "search_as_you_type" } } }}
PUT brands/_doc/1?refresh{ "name": "Western Digital"}
GET brands/_search{ "query": { "multi_match": { "query": "western di", "type": "bool_prefix", "fields": [ "name", "name._2gram", "name._3gram" ] } }}
Připravte nastavení indexu pro nový index nazvaný my_em_analyzer — zkopírujte nastavení anglického analyzéru z https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lang-analyzer.html#english-analyzer
Rozšiřte analyzér:
failure na errorVytvořte následující mapping:
messagetextmessage by mělo využívat analyzer definovaný v předchozím krokuUložte následující dokumenty do ES:
xxxxxxxxxxPOST my_em_analyzer/_doc{ "message": "An error occured"}
POST my_em_analyzer/_doc{ "message": "There was a failure during processing request"}Vyhledejte error v poli message. Oba dokumenty by měly být nalezeny.