Анализаторы Elasticsearch для поиска на русском и узбекском
Практика4 минРедакция Innovialabs
Коротко
Индексируйте название товара дважды — русским анализатором (стемминг, синонимы) и анализатором транслитерации кириллицы в узбекскую латиницу — и ищите по обоим полям с fuzziness, тогда «non», «нон» и «nonn» найдут хлеб.
Короткий ответ
В Узбекистане один и тот же пользователь может набрать «non» (узбекская латиница), «нон» (узбекская кириллица) или «хлеб» (русский), часто с опечаткой. Один анализатор с этим не справится. Рабочая схема:
- русское поле с приведением к нижнему регистру, стоп-словами, русским стеммером и синонимами на этапе поиска;
- подполе транслитерации, где любая кириллица превращается в узбекскую латиницу, а апострофы удаляются;
- запрос, который ищет по обоим полям, с fuzziness на поле транслитерации.
Каждое правило проверяется через API _analyze до выхода в продакшен.
Шаг 1. Анализаторы и маппинг
PUT /products
{
"settings": {
"analysis": {
"char_filter": {
"strip_apostrophes": {
"type": "pattern_replace",
"pattern": "[‘’ʻʼ'`ъьЪЬ]",
"replacement": ""
},
"ru_yo": { "type": "mapping", "mappings": ["ё => е", "Ё => Е"] },
"cyr_to_lat": { "type": "mapping", "mappings_path": "analysis/uz_cyr_lat.txt" }
},
"filter": {
"ru_stop": { "type": "stop", "stopwords": "_russian_" },
"ru_stemmer": { "type": "stemmer", "language": "russian" },
"product_synonyms": {
"type": "synonym_graph",
"synonyms": ["non, нон, хлеб, лепешка", "sharbat, шарбат, сок"]
}
},
"analyzer": {
"ru_index": {
"tokenizer": "standard",
"char_filter": ["ru_yo"],
"filter": ["lowercase", "ru_stop", "ru_stemmer"]
},
"ru_search": {
"tokenizer": "standard",
"char_filter": ["ru_yo"],
"filter": ["lowercase", "product_synonyms", "ru_stop", "ru_stemmer"]
},
"uz_translit": {
"tokenizer": "standard",
"char_filter": ["strip_apostrophes", "cyr_to_lat"],
"filter": ["lowercase", "asciifolding"]
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ru_index",
"search_analyzer": "ru_search",
"fields": {
"translit": { "type": "text", "analyzer": "uz_translit" }
}
}
}
}
}
Файл config/analysis/uz_cyr_lat.txt лежит на каждом узле и содержит по одному правилу в строке — для строчных и заглавных букв:
ў => o
Ў => O
қ => q
ғ => g
ҳ => h
ш => sh
ч => ch
ё => yo
ю => yu
я => ya
х => x
ц => ts
н => n
о => o
…и так далее по всему алфавиту. Ключевые решения:
- Сначала удаляются апострофы, поэтому «o‘zbek», «o'zbek», «ozbek» и «ўзбек» превращаются в
ozbek. Правильный символ ‘ пользователи набирают редко. - Синонимы — только при поиске.
synonym_graphставится в поисковый анализатор, и изменение списка не требует переиндексации документов. - Синонимы стоят до стеммера, иначе «лепешка» уже обрезана и не совпадает с правилом.
Шаг 2. Проверяем всё через _analyze
POST /products/_analyze
{ "field": "name.translit", "text": "Нон Ўзбекча" }
Ожидаемые токены: non, ozbekcha. Теперь русская часть:
POST /products/_analyze
{ "analyzer": "ru_search", "text": "лепёшка" }
Вы должны увидеть основы слов «лепешка» и «хлеб», а также non и нон. Если чего-то нет — проблема в порядке фильтров или в нормализации ё. Учтите, что синонимы совпадают с точной формой слова, поэтому при необходимости добавляйте в правила множественное число и другие частые формы. Сохраните эти вызовы как небольшой набор тестов и запускайте после каждого изменения анализаторов.
Шаг 3. Запрос с исправлением опечаток
GET /products/_search
{
"query": {
"bool": {
"should": [
{ "match": { "name": { "query": "нонн" } } },
{ "match": { "name.translit": {
"query": "нонн",
"fuzziness": "AUTO",
"prefix_length": 1
} } }
]
}
}
}
fuzziness: AUTOне допускает правок в очень коротких словах, одну правку в средних и две в длинных, поэтому «nonn» и «nan» всё равно находят «non».prefix_length: 1оставляет первую букву точной: меньше ложных совпадений и быстрее запросы.- Fuzziness применяется только к полю транслитерации. В сочетании с многословными синонимами результаты становятся менее предсказуемыми.
Узбекские суффиксы
Встроенного узбекского стеммера в Elasticsearch нет, а узбекский — агглютинативный язык: «nonlar», «nonni», «nonning». Варианты от простого к сложному:
- подполе с edge_ngram для поиска по префиксу и автодополнения;
- фильтр pattern_replace, который отрезает короткий список частых суффиксов, — аккуратно, чтобы не повредить корни слов;
- собственный словарь через
stemmer_overrideдля самых популярных названий товаров.
Частые ошибки
- Встроенный анализатор
russianдля всего подряд: запросы латиницей никогда не встретятся с кириллическими названиями. - Забытые заглавные буквы в файле маппинга.
- Fuzziness на артикулах и штрихкодах — для них нужно поле
keywordи точное совпадение. - Изменение анализаторов индексации без переиндексации: старые документы хранят старые токены.