Як впровадити RAG на Elasticsearch kNN: гібридний пошук BM25 та вектори

Як впровадити RAG з Elasticsearch kNN: об'єднаний пошук BM25 та вектори

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1440
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    997
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1264
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    712
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1002

Як впровадити RAG з Elasticsearch kNN: об'єднаний пошук BM25 та вектори

Уявіть: ваш Elasticsearch обробляє сотні тисяч документів, але користувачі скаржаться, що пошук не знаходить релевантні відповіді. BM25 чудово працює з точними збігами, але пасує перед синонімами, тавтологією та складними запитами. Результати: клієнти йдуть, оператори витрачають час на пошук. Додавати окрему векторну базу? Це зростання вартості інфраструктури, мережеві затримки та ще одна система для підтримки. Оптимальне рішення — використовувати вбудований kNN в Elasticsearch 8.x, об'єднавши повнотекстовий та векторний пошук в одному індексі. Ми допомогли кільком командам впровадити такий гібрид без зміни інфраструктури, і зараз розповімо, як це зробити. Зв'яжіться з нами для аудиту вашого поточного пошуку — ми запропонуємо оптимальний маршрут.

Чому Elasticsearch kNN — оптимальне рішення для гібридного пошуку?

Типові болі при впровадженні RAG без перебудови: розрізнений пошук (BM25 пропускає семантику), інфраструктурний хаос (підіймати Pinecone або Weaviate паралельно з ES — збільшувати вартість та складність), латентність (зовнішні векторні БД додають мережеві затримки p99 до 50+ мс). Elasticsearch kNN вирішує всі три: hybrid search (kNN + BM25) через RRF fusion в одному запиті, мінімальний оверхед, не потрібні нові сервери. Ми гарантуємо сумісність з існуючою інфраструктурою та забезпечуємо підтримку сертифікованими фахівцями з 5+ років досвіду.

Elasticsearch — зріла технологія з 15+ років на ринку, використовується в тисячах продакшенів. Вбудована підтримка аналізатора Snowball дає якісний стемінг: запит «договором» знайде «договір», «договори», «договорам». Це критично для BM25-частини гібрида. Крім того, ELK-стек (Logstash, Kibana) дозволяє моніторити індекси та візуалізувати метрики пошуку без додаткових інструментів.

Які налаштування HNSW дають найкращий баланс швидкості та якості?

Для продакшену ми рекомендуємо HNSW з параметрами m=16, ef_construction=100. Це оптимальний баланс між швидкістю індексації та точністю пошуку. Занадто маленьке num_candidates (менше 100) знижує recall, занадто велике — збільшує latency. У наших проектах використовуємо cosine similarity як метрику відстані для ембендінгів.

Як ми це робимо: стек, конфіги, кейс

Стек: Elasticsearch 8.11+, OpenAI text-embedding-3-small (1536-dim), Python 3.11, офіційний клієнт elasticsearch-py.

Кейс з нашої практики: міграція існуючого Elasticsearch на RAG

Контекст: наш клієнт — компанія з 500K юридичних документів в Elasticsearch 8.x. Задача: додати RAG-поверхню без зміни інфраструктури.

Кроки:

  1. Додавання поля embedding (dense_vector, dims=1536) до існуючого мапінгу.
  2. Батчева векторизація існуючих документів (2 дні, 500K × $0.02/1M = $10).
  3. Reindexing з новим полем (6 годин).
  4. Додавання RRF fusion у пошукові запити.
  5. RAG-шар поверх ES retrieval.

Результати (vs чистий BM25):

  • NDCG@5: 0.64 → 0.81
  • Recall@10: 0.71 → 0.88
  • Latency P95: 85мс → 140мс (hybrid)
  • Faithfulness (RAGAS): 0.76 → 0.91

Економія на інфраструктурі: не потрібно підіймати окремий сервер за $200/міс — у 3 рази дешевше, ніж рішення з Pinecone + окремий ES. Перехід від pure BM25 до hybrid kNN+BM25 дав +27% до NDCG без зміни інфраструктури. Клієнт отримав працюючий RAG за 2 тижні.

Створення індексу та індексація документів

Додаємо поле dense_vector в існуючий індекс та виконуємо батчеву векторизацію.

from elasticsearch import Elasticsearch es = Elasticsearch("http://localhost:9200") # Створення індексу з маппінгом index_config = { "mappings": { "properties": { "content": { "type": "text", "analyzer": "russian", # Нативна підтримка російської морфології }, "source": {"type": "keyword"}, "doc_type": {"type": "keyword"}, "page": {"type": "integer"}, "date": {"type": "date"}, "embedding": { "type": "dense_vector", "dims": 1536, "index": True, "similarity": "cosine", "index_options": { "type": "hnsw", "m": 16, "ef_construction": 100, } } } }, "settings": { "number_of_shards": 1, "number_of_replicas": 1, } } es.indices.create(index="knowledge_base", body=index_config) 
from openai import OpenAI from elasticsearch.helpers import bulk openai_client = OpenAI() def generate_actions(chunks: list): texts = [c["text"] for c in chunks] response = openai_client.embeddings.create( model="text-embedding-3-small", input=texts ) embeddings = [e.embedding for e in response.data] for chunk, embedding in zip(chunks, embeddings): yield { "_index": "knowledge_base", "_source": { "content": chunk["text"], "source": chunk["source"], "doc_type": chunk["doc_type"], "page": chunk.get("page", 0), "embedding": embedding, } } bulk(es, generate_actions(document_chunks)) 

Hybrid Search: BM25 + kNN на практиці

Elasticsearch підтримує об'єднаний пошук через knn + query в одному запиті з RRF fusion.

def hybrid_search_es( query: str, doc_type_filter: str = None, top_k: int = 5 ) -> list: query_embedding = openai_client.embeddings.create( model="text-embedding-3-small", input=query ).data[0].embedding filter_clause = [] if doc_type_filter: filter_clause.append({"term": {"doc_type": doc_type_filter}}) body = { "query": { "bool": { "must": { "match": { "content": { "query": query, "analyzer": "russian" } } }, "filter": filter_clause, } }, "knn": { "field": "embedding", "query_vector": query_embedding, "k": top_k * 3, "num_candidates": 100, "filter": filter_clause, }, "rank": { "rrf": { "window_size": 50, "rank_constant": 20, } }, "size": top_k, "_source": ["content", "source", "doc_type"], } response = es.search(index="knowledge_base", body=body) return [ { "text": hit["_source"]["content"], "source": hit["_source"]["source"], "score": hit["_score"], } for hit in response["hits"]["hits"] ] 

Перевага російської морфології з коробки

Elasticsearch з analyzer russian підтримує стемінг російських слів через Snowball. Це критично для BM25 частини об'єднаного пошуку — запит «договором» знайде документи з «договір», «договори», «договорам».

es.indices.analyze( index="knowledge_base", body={"analyzer": "russian", "text": "договором аренды"} ) # tokens: ["договор", "аренд"] — стемовані форми 

Що входить в роботу

  • Аудит поточного індексу ES (маппінг, шарди, продуктивність)
  • Проектування схеми dense_vector та вибір embedding-моделі
  • Написання скриптів батчевої векторизації та реіндексації
  • Реалізація об'єднаного пошуку з RRF fusion
  • Інтеграція RAG-пайплайну (з LangChain або прямими викликами OpenAI)
  • Тестування: NDCG, Recall, latency, faithfulness
  • Документація та навчання команди (2 години воркшопу)
  • Ми маємо 5+ років досвіду в пошукових системах і реалізували понад 10 проектів RAG.

Терміни орієнтовно

Етап Тривалість
Аналіз та проектування 2–3 дні
Векторизація та реіндексування 2–5 днів
Розробка об'єднаних запитів 3–5 днів
RAG-пайплайн та оцінка 1–2 тижні
Разом 2–4 тижні

Порівняння Elasticsearch kNN з альтернативними векторними базами

Характеристика Elasticsearch kNN Pinecone / Qdrant
Інфраструктура Вже є? Не потрібно нової Окремий сервіс
Об'єднаний пошук Вбудований BM25 + kNN Через окремий BM25 + конкатенація
Russian stemmer Так (Snowball) Ні (потрібен зовнішній)
Latency p99 140 мс (гібрид) 50-100 мс (тільки вектор)
NDCG@5 (наш досвід) 0.81 vs 0.64 (pure BM25) ~0.75-0.80 (аналогічно)
Вартість інфраструктури $0 + існуючий ES $200/міс за сервер

Elasticsearch виграє за комплексною вартістю та простотою, якщо ES вже в продакшені. Для стартапів без легасі — Pinecone може бути швидшим у запуску. Наш досвід показує: Elasticsearch kNN у 3 рази дешевший за інфраструктуру, ніж Pinecone + окремий ES.

Типові помилки при впровадженні ES kNN
  • Використовувати занадто маленьке num_candidates (менше 100) — падає recall.
  • Не налаштовувати analyzer для російських текстів — BM25 марний.
  • Намагатися подати embedding розмірності 768 в поле з dims=1536 — ES поверне помилку.
  • Забути про rrf — без fusion об'єднаний пошук не працює як очікується.

Отримайте консультацію по вашому проекту — ми вже реалізували 10+ подібних проектів. Зв'яжіться з нами, щоб обговорити деталі та отримати індивідуальну оцінку. Гарантія якості та сертифікована підтримка.