Малоиспользуемые возможности Elastic Search: векторный поиск

Привет, меня зовут Евгений Думчев, я разработчик в DD Planet. Сегодня хочу поделиться опытом применения одной из редко используемых, но полезных функций - Elasticsearch, которую мы успешно применили в одном из проектов.
Elasticsearch - это высокопроизводительная, масштабируемая, распределенная поисковая и аналитическая система, предназначенная для быстрого поиска, анализа и обработки больших объемов данных.
Основной и наиболее распространенной задачей применения Elasticsearch на проектах является внедрение полнотекстового поиска (поиск по текстовым полям с учетом морфологии, синонимов и релевантности) и точного поиска с применением фильтраций и агрегаций данных. В данном случае разработчик целенаправленно подключает Elasticsearch в приложение для того, чтобы воспользоваться средствами индексации и гибкого поиска данных. Для этого требуется создать индекс с маппингом типов данных и реализовать утилиту-индексатор, которая будет на основе данных из постоянного хранилища данных заполнять индекс документами (индексировать) в соответствии со структурой маппинга. И в основном API приложении требуется реализовать запрос к Elasticsearch (существуют библиотеки для большинства языков программирования) для поиска и получения данных из целевого индекса. Схема выглядит так:

И еще один, не менее популярный вариант использования Elasticsearch на проектах - в качестве инструмента для централизованного хранения и анализа логов приложений, баз данных и других инфраструктурных элементов. В связке с Logstash (для сбора и обработки логов) и Kibana (для визуализации) он образует стек ELK, который позволяет эффективно искать и анализировать большие объемы данных. Elasticsearch обеспечивает быстрый поиск по логам, агрегацию данных и настройку алертинга для обнаружения аномалий. Это делает его популярным решением для мониторинга инфраструктуры, диагностики проблем и аудита безопасности. Но данное решение не отражает весь масштаб и спектр возможностей, предоставляемых Elasticsearch, поскольку пользователь взаимодействует с поисковым движком только через визуальный интерфейс и функции, доступные в Kibana. Пример интерфейса Kibana:

Более сложные и специализированные возможности Elasticsearch, требующие дополнительной настройки и глубокого понимания системы, применяются реже, но могут оказаться очень полезными. Рассмотрим одну из таких малоиспользуемых возможностей - векторный поиск.
Концепция векторного поиска (vector search) основана на представлении объектов в виде многомерных числовых векторов и определении их близости по метрике расстояния (например, косинусное расстояние, евклидово расстояние или расстояние Джеффри). Близость векторов отражает семантическую или контекстуальную схожесть объектов. Текстовая информация может быть преобразована в вектор с помощью моделей машинного обучения, таких как Word2Vec, BERT или других методов embedding.
Создание и конфигурирование индекса
В Elasticsearch начиная с версии 7.10 появилась поддержка поля dense_vector - специального типа данных, позволяющего хранить и индексировать векторы фиксированной размерности. При создании этого типа данных можно указать следующие параметры:
- dims – количество измерений (размерность) вектора, обязательный.
- similarity – алгоритм сравнения векторов. Доступны следующие варианты: l2_norm – евклидово расстояние, dot_product – скалярное произведение, cosine – косинусное расстояние.
- index – логическое значение (true/false), указывает, нужно ли индексировать вектор для поиска (по умолчанию false).
- index_options – дополнительные параметры для индексации.
- type – тип индексации, например, hnsw (Hierarchical Navigable Small World).
- m – параметр HNSW, определяющий количество связей между узлами (обычно 16-100).
- ef_construction – параметр HNSW, управляющий точностью построения индекса (обычно 100-200).
Пример создания индекса:

Автоматически вычислить значения dense_vector встроенными средствами Elasticsearch нельзя, потому что в нем пока нет встроенных механизмов генерации эмбеддингов из текстовых или других данных без предварительно обученной модели машинного обучения. Даже встроенные модели, такие как ELSER, нужно сначала загрузить и активировать. Чтобы получить и проиндексировать семантические вектора, можно воспользоваться следующими способами:
получить вектора через внешний сервис и явно передать значения вектора при добавлении документа;
подключить предобученную ML-модель для генерации векторов через Inference Pipeline.
Индексация векторов через внешний сервис
Внешний сервис подразумевает решение, которое позволяет предварительно обработать текстовые данные и получить вектора. В качестве такого решения может выступать собственная NLP-модель или сервисы для семантического анализа, например: OpenAI, Hugging Face.
Как пример, для получения вектора воспользуемся библиотекой transformers от Hugging Face и фреймворком torch. Установим зависимости:

И воспользуемся специализированной моделью distiluse-base-multilingual-cased-v2 для поиска смысловой схожести между текстами. Эта многоязычная нейросетевая модель построена на базе DistilBERT и обучена на Natural Language Inference (NLI) и парафразных задачах, то есть способна определять насколько два предложения означают одно и то же. Модель позволяет сформировать 512-мерный вектор.
Скрипт на Python для получения вектора:

В результате получаем 512-мерный вектор, значение которого можно проиндексировать в Elasticsearch, указав в поле с типом dense_vector:

В результате в индексе сохранено 5 документов и они доступны для поиска.
Индексация векторов с использованием Ingest Pipeline с Inference
Альтернативный вариант получения и индексации векторов - это воспользоваться Ingest Pipeline с Inference. Данный инструмент позволяет интегрировать машинное обучение в обработку данных при индексации. Ограничением является то, что Elasticsearch ML доступен только в платных тарифах. В бесплатной версии не получится использовать Ingest Pipeline Inference или upload моделей.
Для начала нужно установить модель в Elasticsearch. Для этого можно воспользоваться инструментом Eland.

И проверить статус установки в Elasticsearch:

А также можно вызвать запрос получения семантического вектора:

Когда модель установлена в Elasticsearch необходимо создать Ingest Pipeline с Inference:

Также можно скорректировать настройки индекса и указать default_pipeline:

Теперь при добавлении документа Elasticsearch автоматически создаст dense_vector, используя дефолтный или указанный pipeline с NLP-моделью.

В результате pipeline автоматически создаст и заполнит поле vector, в индексе будет сохранено 5 документов и они будут доступны для поиска.
Применение запросов векторного поиска
Для векторного поиска семантически схожих объектов используется метод ближайших соседей (kNN). При выполнении kNN поиска, указывается вектор запроса (query vector) и количество ближайших соседей (k), которые нужно найти. Elasticsearch вычисляет расстояние между вектором запроса и векторами документов в индексе, используя метрику расстояния (например, евклидово расстояние или косинусное сходство). Документы ранжируются по их близости к вектору запроса. Чем меньше расстояние, т.е. больше сходство, тем выше документ окажется в результатах поиска. Elasticsearch возвращает k ближайших документов, отсортированных по степени их близости к запросу.
Сформируем вектора для фразы “Привет, как настроение?” и выполним запрос поиска похожих документов запросом knn:

В результате получаем:

Из результата выполнения запроса видно, что документы отранжировались по _score с учетом их смысловой близости. Чем значение _score ближе к 1, тем выше семантическая схожесть. В данном случае фраза “Привет, как настроение?” близка с фразами “Здравствуй, как жизнь?” и “Как дела?”, то есть смысловая нагрузка действительно учтена.
Нужно понимать, что качество векторного поиска зависит от поставленной задачи и используемой ML-модели. В некоторых случаях для достижения лучшего результата правильнее будет создать и использовать собственную ML-модель.
Потенциал векторного поиска
С появлением поддержки векторов (dense vectors) в Elasticsearch стало возможным выполнять семантический поиск, учитывающий смысловую близость терминов.
Использование kNN в Elasticsearch позволяет:
- Искать семантически похожие документы. Представить текст в виде векторов можно за счет моделей BERT, SBERT или OpenAI embeddings.
- Находить похожие изображения. Векторные представления изображений можно получать с помощью ResNet, ViT или CLIP.
- Создавать системы рекомендаций. Для этого нужно векторизовать предпочтения пользователя и искать товары, близкие к предпочтениям.
Однако из-за сложности настройки и необходимости интеграции с моделями машинного обучения, эта функция пока не получила широкого распространения.
В заключении хочется сказать, что Elasticsearch мощный инструмент, который предлагает широкий спектр функций и возможностей, но некоторые из них остаются недооцененными или редко используемыми из-за их сложности, специфичности или недостаточной осведомленности разработчиков. Повышение знаний об этих возможностях и обучение их эффективному использованию может значительно расширить потенциал приложений, основанных на Elasticsearch.