Разработка кастомных анализаторов Elasticsearch (языковые, синонимы)
Стандартный анализатор Elasticsearch покрывает базовые сценарии, но реальный поиск требует языковой специфики: стемминг, стоп-слова, синонимы, сложные правила токенизации. Кастомный анализатор — это цепочка из tokenizer + token filters, которая трансформирует текст в набор токенов для индекса.
Архитектура анализатора
Анализ текста проходит в три этапа:
-
Character filters — предобработка строки до токенизации. Удаление HTML-тегов (
html_strip), замена символов (mapping), нормализация Unicode. -
Tokenizer — разбивка текста на токены.
standard— по пробелам и пунктуации.whitespace— только по пробелам.ngram/edge_ngram— для автодополнения.keyword— вся строка как один токен. -
Token filters — трансформация токенов.
lowercase,stop, стемминг, синонимы, N-gram, удаление дублей.
Языковой анализатор для русского языка
Встроенный russian анализатор использует алгоритм Snowball для стемминга. Для большинства задач этого достаточно, но если нужна точная морфология — нужен плагин.
Кастомный Russian анализатор с настраиваемыми стоп-словами:
PUT /articles
{
"settings": {
"analysis": {
"filter": {
"russian_stop": {
"type": "stop",
"stopwords": "_russian_"
},
"russian_keywords": {
"type": "keyword_marker",
"keywords": ["пример", "тест"]
},
"russian_stemmer": {
"type": "stemmer",
"language": "russian"
},
"custom_stopwords": {
"type": "stop",
"stopwords": ["это", "также", "при", "для", "что", "как"]
}
},
"analyzer": {
"russian_custom": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"russian_stop",
"custom_stopwords",
"russian_keywords",
"russian_stemmer"
]
},
"russian_exact": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "russian_custom",
"search_analyzer": "russian_custom",
"fields": {
"exact": {
"type": "text",
"analyzer": "russian_exact"
}
}
}
}
}
}
Разница между analyzer (при индексации) и search_analyzer (при поиске) — ключевая. Обычно они одинаковы, но для некоторых задач (prefix search, синонимы) нужны разные анализаторы.
Синонимы
Синонимы расширяют поиск: запрос «ноутбук» находит документы со словом «лэптоп». Синонимы можно применять при индексации или при поиске.
Синонимы при поиске (рекомендуется) — синонимы применяются только к поисковому запросу, индекс не меняется. Синонимы можно обновлять без переиндексации.
Синонимы при индексации — синонимы записываются в индекс. Обновление синонимов требует переиндексации, но поиск быстрее (меньше токенов в запросе).
Файл синонимов config/synonyms/synonyms.txt:
ноутбук, лэптоп, laptop, notebook
смартфон, телефон, мобильный
телевизор, тв, tv
принтер, МФУ
Графы синонимов (explicit mapping) для сложных случаев:
i-pod, i pod => ipod
sea biscuit, sea biscit => seabiscuit
Конфигурация анализатора с синонимами:
PUT /products
{
"settings": {
"analysis": {
"filter": {
"synonym_filter": {
"type": "synonym",
"synonyms_path": "synonyms/synonyms.txt",
"updateable": true
},
"synonym_graph_filter": {
"type": "synonym_graph",
"synonyms": [
"amazon, амазон",
"google, гугл",
"яндекс, yandex"
],
"lenient": true
}
},
"analyzer": {
"search_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"russian_stop",
"synonym_graph_filter"
]
},
"index_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"russian_stop",
"russian_stemmer"
]
}
}
}
}
}
"updateable": true — обязательный флаг для синонимов, применяемых только при поиске. Позволяет перезагружать синонимы через _reload_search_analyzers без переиндексации.
Обновление синонимов без переиндексации:
# Обновить файл synonyms.txt на всех узлах кластера
# Затем выполнить:
POST /products/_reload_search_analyzers
Edge N-gram для поиска по префиксу
Для автодополнения при вводе — анализатор с edge_ngram:
"filter": {
"edge_ngram_filter": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 15
}
},
"analyzer": {
"autocomplete_index": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "edge_ngram_filter"]
},
"autocomplete_search": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase"]
}
}
При поиске используется autocomplete_search (без N-gram), при индексации — autocomplete_index. Иначе поиск по «ноутб» совпадёт с N-gram-токенами «но», «ноу», «ноут»... в результатах появится мусор.
Анализатор для транслитерации
Пользователи часто пишут транслитом: «noutbuk» вместо «ноутбук». Плагин analysis-icu позволяет обрабатывать Unicode, но транслитерацию обычно реализуют через char_filter типа mapping:
"char_filter": {
"translit_filter": {
"type": "mapping",
"mappings": [
"а => a", "б => b", "в => v", "г => g", "д => d",
"е => e", "ж => zh", "з => z", "и => i", "й => j",
"к => k", "л => l", "м => m", "н => n", "о => o",
"п => p", "р => r", "с => s", "т => t", "у => u",
"ф => f", "х => kh", "ц => ts", "ч => ch", "ш => sh",
"щ => shch", "ъ => ", "ы => y", "ь => ", "э => e",
"ю => yu", "я => ya"
]
}
}
Для продвинутой транслитерации — плагин analysis-icu с ICU transformers, который корректно обрабатывает Unicode normalization и множество языков.
Тестирование анализаторов
# Проверить как анализатор обрабатывает текст
POST /products/_analyze
{
"analyzer": "russian_custom",
"text": "Ноутбуки и лэптопы для работы"
}
# Проверить анализатор на уровне настроек (без привязки к индексу)
POST _analyze
{
"tokenizer": "standard",
"filter": ["lowercase", "russian_stop"],
"text": "Это тестовый пример для проверки"
}
# Проверить конкретное поле
POST /products/_analyze
{
"field": "title",
"text": "Купить ноутбук недорого"
}
Ответ содержит список токенов с позициями и типами — позволяет точно понять, что попадёт в индекс.
Многоязычные индексы
Два подхода: один индекс с полями для каждого языка, или отдельный индекс на язык.
Один индекс с языковыми полями:
"properties": {
"title_ru": { "type": "text", "analyzer": "russian_custom" },
"title_en": { "type": "text", "analyzer": "english" },
"title_de": { "type": "text", "analyzer": "german" }
}
Запрос по нескольким языкам:
{
"query": {
"multi_match": {
"query": "search term",
"fields": ["title_ru^2", "title_en", "title_de"]
}
}
}
Буст ^2 для русского поля — если основная аудитория русскоязычная.
Сроки
Разработка и тестирование кастомного анализатора под конкретный язык — 1 рабочий день. Настройка синонимов с файлом и механизмом обновления без переиндексации — ещё полдня. Многоязычная конфигурация с 3–5 языками — 2–3 дня включая тесты поисковой релевантности.







