Что такое Elasticsearch и как устроен поисковый индекс
Основы4 минРедакция Innovialabs
Коротко
Elasticsearch — распределённый поисковый движок, который хранит JSON-документы в инвертированном индексе, поэтому быстро находит слова среди миллионов записей и сортирует результаты по релевантности; он нужен, когда LIKE-запросов к базе уже не хватает для нормального полнотекстового поиска.
Коротко о главном
Elasticsearch — поисковый и аналитический движок на основе библиотеки Apache Lucene. Вы отправляете в него JSON-документы (товары, статьи, строки логов), он разбивает текст на термы и складывает их в инвертированный индекс. Поиск потом идёт по термам, а не перебором всех записей, и результаты сортируются по релевантности, а не просто «нашлось / не нашлось».
OpenSearch — форк Elasticsearch, который развивает сообщество под эгидой Linux Foundation. Для базовых вещей из этой статьи оба работают одинаково.
Инвертированный индекс
Обычная таблица устроена как «документ → слова». Инвертированный индекс переворачивает это в «слово → документы» — как предметный указатель в конце книги.
Возьмём три описания товаров:
- «Красная кожаная сумка»
- «Кожаный кошелёк, коричневый»
- «Красная хлопковая футболка»
После обработки (о ней ниже) индекс выглядит примерно так:
| Терм | Документы |
|---|---|
| красн | 1, 3 |
| кожан | 1, 2 |
| сумк | 1 |
| кошел | 2 |
| коричнев | 2 |
| хлопков | 3 |
Запрос «красная кожаная» читает два коротких списка и объединяет их. Документ 1 содержит оба терма — он будет первым, документы 2 и 3 совпадают по одному. Полного перебора нет, поэтому поиск остаётся быстрым при росте данных.
Анализаторы: как текст превращается в термы
Прежде чем попасть в индекс, текст проходит через анализатор:
- Character filters чистят ввод, например убирают HTML-теги.
- Токенизатор делит текст на слова.
- Token filters приводят слова к нижнему регистру, убирают стоп-слова, отрезают окончания (стемминг: «сумки» → «сумк»), добавляют синонимы.
Тот же анализатор применяется к поисковому запросу, поэтому «Сумки» в запросе находит «сумка» в документе. Для русского и узбекского с их богатыми окончаниями правильный языковой анализатор сильно влияет на качество выдачи. На практике большинство проблем с поиском — это проблемы анализатора.
Документы, индексы и маппинг
- Документ — один JSON-объект с уникальным ID.
- Индекс — набор однотипных документов, грубо говоря, аналог таблицы.
- Маппинг описывает типы полей:
textанализируется для полнотекстового поиска,keywordхранится как есть — для точных фильтров, сортировки и агрегаций.
{
"mappings": {
"properties": {
"title": { "type": "text" },
"brand": { "type": "keyword" },
"price": { "type": "float" },
"in_stock": { "type": "boolean" }
}
}
}
Сменить тип уже существующего поля обычно можно только через переиндексацию, поэтому маппинг лучше продумать до загрузки данных.
Шарды и реплики
Индекс делится на шарды — каждый из них самостоятельный индекс Lucene. Шарды распределяются по узлам кластера, и данные с нагрузкой делятся между ними. Реплики — копии шардов на других узлах: они защищают от падения узла и могут обслуживать запросы на чтение.
Частая ошибка — множество мелких шардов. У каждого шарда есть накладные расходы, так что для небольшого или среднего проекта обычно лучше меньше шардов, но крупнее.
Как считается релевантность
Для каждого совпадения Elasticsearch вычисляет score. Алгоритм по умолчанию, BM25, учитывает:
- как часто терм встречается в документе;
- насколько терм редкий во всём индексе (редкие слова весят больше);
- длину поля (совпадение в коротком заголовке весит больше, чем в длинном тексте).
Ранжирование можно настраивать: поднять вес поля title над description, учитывать свежесть или популярность, включить нечёткий поиск для опечаток.
Когда проекту это действительно нужно
Elasticsearch или OpenSearch оправданы, если у вас:
- полнотекстовый поиск по большому каталогу или базе контента с опечатками, словоформами и синонимами;
- фасетные фильтры: количество товаров по бренду, цене и категории рядом с выдачей;
- автодополнение и поиск по мере ввода;
- логи и события: централизованный поиск и агрегации по большим объёмам.
Скорее всего, он не нужен, если:
- данных немного и хватает
LIKEили встроенного полнотекстового поиска базы (например, в PostgreSQL); - нужны только точные фильтры по ID, статусу или дате;
- команда не готова сопровождать ещё один сервис с состоянием.
Учтите: Elasticsearch обычно вторичное хранилище. Источник истины остаётся в основной базе, а данные синхронизируются в поисковый индекс. Эта синхронизация плюс мониторинг кластера и память — реальная цена внедрения.