Semantic Search

semantic search — поиск по смыслу через векторные представления

Раздел
Языковые модели
Обновлено
11.08.26

Semantic Search — поиск документов по **смыслу запроса**, а не по ключевым словам. Запрос превращается в эмбеддинг, документы заранее тоже, поиск идёт через cosine similarity между векторами. Запрос «как сделать возврат» найдёт документ «refund procedure», даже если совпадающих слов нет. Базовый компонент RAG, modern search, recommendation systems.

Коротко

Коротко. Semantic Search ищет по смыслу, а не по ключевым словам. Каждый документ заранее превращается в вектор-эмбеддинг (1500+ чисел), запрос — тоже. Поиск — найти ближайшие векторы по cosine similarity. Запрос «как отменить заказ» найдёт «процедура возврата покупки», даже без совпадающих слов. Главное от обычного keyword-поиска: понимает синонимы, контекст, перефразировки. Основа RAG.

Что это такое

Пользователь приходит на сайт интернет-магазина. Хочет вернуть товар. Ищет в базе знаний: «как сделать возврат?».

Keyword-поиск (Elasticsearch без NLP): ищет точные слова «возврат», «как», «сделать». Находит:

  • Статью «Возврат денежных средств: правила» (релевантна).
  • Статью «Как сделать заказ» (нерелевантна, но 2/3 слов совпали).
  • Не находит статью «Procedure for product refunds» (английский, нет совпадающих слов с русским запросом).

Semantic Search: превращает запрос в вектор (через embedding-модель), сравнивает с векторами всех документов. Топ-результаты:

  • «Возврат денежных средств: правила» (semantic similarity 0.87).
  • «Procedure for product refunds» (similarity 0.84 — модель понимает что это синонимы на разных языках).
  • «Обмен товара» (similarity 0.76 — близкая тема).
  • Статья «Как сделать заказ» НЕ попала — другая семантика.

Вот это и есть semantic search — поиск по смыслу, не по словам.

Как это работает

Двухфазный pipeline:

Фаза 1: индексация (offline)

# для каждого документа в базе
for doc in documents:
    chunks = split(doc, size=500)  # chunking
    for chunk in chunks:
        vector = embedding_model.embed(chunk)  # 1536-dim вектор
        vector_db.insert(chunk_id=id, vector=vector, text=chunk)

Получаем базу: миллионы chunk'ов, каждый — вектор в 1500-мерном пространстве.

Фаза 2: поиск (online)

def search(query, top_k=5):
    query_vector = embedding_model.embed(query)
    # Cosine similarity со всеми векторами
    results = vector_db.find_nearest(query_vector, k=top_k)
    return results

Cosine similarity между двумя векторами:

similarity = (A · B) / (|A| × |B|)

Диапазон 0..1. Чем ближе к 1 — тем ближе по смыслу.

Дополнительные техники:

  • Approximate Nearest Neighbors (ANN) — алгоритмы FAISS, HNSW для быстрого поиска в миллионах векторов.
  • Filtering — комбинировать векторный поиск с метаданными: «найди близкие по смыслу, но только из категории X».
  • Hybrid Search — комбинация semantic + keyword (BM25) для лучшего качества.

Пример на практике

Команда строит документацию для своего SaaS-продукта. 1000 страниц, 4 языка (RU, EN, DE, FR).

Стек может быть простым:

  • Embedding: мультиязычная модель с подходящей лицензией и длиной входа.
  • Vector DB: локальное или облачное хранилище с нужным типом индекса и фильтрами.
  • Интерфейс: обычная строка поиска с подсказками и понятными фрагментами результатов.
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient

model = SentenceTransformer('BAAI/bge-m3')
qdrant = QdrantClient("localhost")

# индексация
for chunk in all_chunks:
    vec = model.encode(chunk['text'])
    qdrant.upsert("docs", points=[{
        "id": chunk['id'],
        "vector": vec.tolist(),
        "payload": {"text": chunk['text'], "lang": chunk['lang'], "url": chunk['url']}
    }])

# поиск
def search(query, lang_filter=None):
    qv = model.encode(query).tolist()
    return qdrant.search(
        collection_name="docs",
        query_vector=qv,
        limit=5,
        query_filter={"must": [{"key": "lang", "match": {"value": lang_filter}}]} if lang_filter else None
    )

Пользователь ищет «отменить подписку» — получает релевантные документы на всех языках. Если выбрал фильтр «только русский» — только русские.

Скорость зависит от размера индекса, размерности, типа поиска, фильтров и оборудования. Качество сравнивают с полнотекстовым поиском на размеченных запросах: семантический подход не обязан выигрывать на артикулах, именах и точных формулировках.

В ComfyUI с RAG-нодами обычно используется Qdrant или ChromaDB как vector store + одна из embedding-моделей. Workflow строится в виде «загрузил доки → проиндексировал → ищем при каждом промпте».

С чем часто путают

  • Semantic Search и Keyword Search — Keyword (BM25, Elasticsearch) ищет точные слова. Semantic — векторы смысла.
  • Semantic Search и Full-text Search — Full-text это частный случай keyword. Semantic — другая парадигма.
  • Semantic Search и Hybrid Search — Hybrid объединяет смысловую близость и совпадения по словам. Он особенно полезен, когда в запросах встречаются артикулы, имена и точные термины.
  • Embedding и Semantic Search — Embedding это вектор одного объекта. Semantic Search — процесс поиска по векторам.
  • Semantic Search и LLM — LLM генерирует текст, Semantic Search ищет существующий. Часто работают вместе в RAG.

Частые ошибки и заблуждения

  • «Semantic Search всегда лучше keyword». Не всегда. На точных запросах с уникальными терминами (артикулы, имена) BM25 часто лучше. Hybrid решает этот компромисс.
  • «Чем больше dim в embedding, тем лучше». До определённого предела. 1536 (OpenAI) хватает для большинства задач. 3072+ — мало улучшения, больше storage и compute.
  • «Любая embedding-модель сработает». Качество сильно различается. Проверяйте на бенчмарках (MTEB) для вашего языка/домена.
  • «Косинусная similarity — единственная метрика». Есть и dot-product, и euclidean. Для нормализованных векторов cosine = dot. На практике cosine популярнее.
  • «Semantic Search не нужен фильтр по точным словам». Нужен. Часто пользователю нужно найти документ с именно словом X — semantic может «забыть» это в пользу синонимов.

Связанные термины

  • Embeddingвектор-представление, на котором работает search.
  • Vector Database — хранилище эмбеддингов.
  • Hybrid Search — комбинация semantic + keyword.
  • Reranking — улучшение результатов после первого retrieval.
  • RAG — главный сценарий применения semantic search.
  • Cosine Similarity — главная метрика близости векторов.
  • MTEB — главный бенчмарк embedding-моделей.

Частые вопросы

Какую embedding-модель выбрать? Ту, которая поддерживает языки корпуса, помещает типичный документ в свой лимит и показывает хороший recall на ваших вопросах. Публичные рейтинги дают список кандидатов, но финальный выбор делает собственный тест.

Какую Vector DB? Открытые: Qdrant (Rust, быстрая), Weaviate, ChromaDB (для прототипов). Managed: Pinecone, Vespa, Postgres + pgvector.

Сколько документов выдержит? С HNSW-индексом — до сотен миллионов на одной машине. Поиск по миллиарду векторов — десятки серверов через шардинг.

Когда semantic search хуже keyword? Поиск по уникальным идентификаторам (SKU, имена файлов, технические коды). Там keyword точнее.

Можно ли искать на одном языке, документы — на другом? Да, если embedding-модель обучена сопоставлять несколько языков в общем пространстве. Качество всё равно лучше отдельно проверить на каждой нужной языковой паре.

Как тестировать качество search? Метрики: recall@k (доля «правильных» документов в топ-k), MRR (Mean Reciprocal Rank), nDCG. Собрать 50–100 тестовых пар (query, правильный документ).

Главное

Semantic Search сопоставляет запрос и документы по смысловой близости, а не только по совпавшим словам. Тексты и запрос превращаются в embedding-векторы, после чего система сравнивает их, например, по cosine similarity. Это помогает находить синонимы и перефразировки. На практике смысловой поиск часто объединяют с полнотекстовым, а способ хранения выбирают по объёму, фильтрам, обновлениям и инфраструктуре проекта.