0Pricing
AI Engineering Academy · Урок

Плотный и разреженный поиск: компромиссы

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

«Плотный и разреженный поиск: компромиссы» — бесплатный урок AI Engineering Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Engineering Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Engineering Academy содержит 4 уроков всего.

Части этого урока еще не переведены и отображаются на английском.

Two Fundamentally Different Retrieval Signals

Modern retrieval systems rely on two distinct signals: dense retrieval encodes meaning into continuous vector spaces, while sparse retrieval counts exact term occurrences. These signals are complementary, not interchangeable. Understanding their individual strengths and weaknesses is the first step toward building a system that uses both effectively.

How Dense Embeddings Work

Dense retrieval maps both the query and each document into a high-dimensional vector using a neural encoder. Similarity is measured by cosine distance or dot product between vectors. Because the encoder was trained on large text corpora, semantically related phrases end up near each other in vector space even if they share no common words — this is the key advantage of dense retrieval.

from openai import OpenAI
import numpy as np

client = OpenAI()

def embed(text: str) -> list[float]:
    resp = client.embeddings.create(
        model='text-embedding-3-small',
        input=text,
    )
    return resp.data[0].embedding

def cosine_similarity(a, b):
    a, b = np.array(a), np.array(b)
    return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

q = embed('How do I cancel my subscription?')
d = embed('Steps to unsubscribe from the service')
print(cosine_similarity(q, d))  # high similarity despite different words

Where Dense Retrieval Fails

Dense models struggle with rare terms that were underrepresented during encoder training. A query containing a specific product model number like RTX-4090-Ti-OC, a medical drug name, or a proprietary internal identifier will often fail to match the correct document because the encoder has no learned representation for that token sequence. The vector just lands somewhere unhelpful in embedding space.

How Sparse BM25 Retrieval Works

BM25 (Best Matching 25) is a probabilistic ranking function that scores documents based on how often query terms appear in the document, normalized for document length and dampened by term frequency saturation. It produces a sparse score vector — most dimensions are zero because documents contain only a small fraction of the vocabulary.

# BM25 scoring formula (conceptual)
# score(D, Q) = sum over query terms t of:
#   IDF(t) * (tf(t,D) * (k1 + 1)) / (tf(t,D) + k1 * (1 - b + b * |D|/avgdl))

# k1 controls term frequency saturation (typically 1.2-2.0)
# b controls document length normalization (typically 0.75)
# IDF(t) = log((N - df(t) + 0.5) / (df(t) + 0.5))

# N = total documents, df(t) = documents containing term t
# tf(t,D) = frequency of t in document D, |D| = doc length, avgdl = average doc length

BM25 Strengths: Exact Terms and Jargon

BM25 excels at queries involving exact technical terms, product names, error codes, and numeric identifiers that should match precisely. A query for ORA-01017 (an Oracle error code) will rank documents containing that exact string far above documents that merely discuss database authentication in general terms. This is impossible for a dense model that has never seen that specific code.

from rank_bm25 import BM25Okapi

corpus = [
    'Oracle database ORA-01017 invalid username or password logon denied',
    'Database authentication and connection troubleshooting guide',
    'How to resolve login errors in Oracle and MySQL databases',
]

tokenized_corpus = [doc.lower().split() for doc in corpus]
bm25 = BM25Okapi(tokenized_corpus)

query = 'ORA-01017 error fix'
scores = bm25.get_scores(query.lower().split())
print(dict(zip(range(len(corpus)), scores)))
# doc 0 scores highest because it contains ORA-01017

Where BM25 Fails: Paraphrases and Synonyms

BM25 is blind to semantic paraphrasing. A document about 'automobile engine repair' will score zero for a query about 'car motor maintenance' because none of the exact words overlap. This vocabulary mismatch problem, sometimes called the lexical gap, means pure keyword search misses huge amounts of relevant content that simply uses different words to express the same idea.

from rank_bm25 import BM25Okapi

corpus = [
    'automobile engine repair and maintenance tips',
    'car motor maintenance guide for beginners',
    'vehicle powertrain service intervals',
]
tokenized = [doc.split() for doc in corpus]
bm25 = BM25Okapi(tokenized)

scores = bm25.get_scores(['car', 'motor', 'maintenance'])
print(scores)
# doc 1 scores high, doc 0 and 2 score lower despite being semantically related

Benchmark Evidence: Hybrid Wins Consistently

Benchmarks on BEIR, MS MARCO, and enterprise Q&A datasets consistently show that hybrid retrieval outperforms either dense or sparse alone by 5-15 percent on NDCG@10. The improvement is largest on datasets with a mix of factual lookups (where BM25 helps) and paraphrase queries (where dense embeddings help). No single retrieval method dominates across all query types.

Query Type Analysis: Which Retriever Wins

You can predict which retriever will perform better by analyzing the query type. Dense retrieval wins on conceptual questions, paraphrases, and broad topic queries. BM25 wins on queries containing proper nouns, version numbers, code snippets, acronyms, and rare technical terms. Hybrid always wins when query type is unknown in advance — which is almost always true in production.

# Query type heuristics
def predict_retriever_advantage(query: str) -> str:
    tokens = query.split()
    has_numbers = any(t[0].isdigit() for t in tokens)
    has_uppercase_acronyms = any(t.isupper() and len(t) > 2 for t in tokens)
    is_short = len(tokens) <= 4

    if has_numbers or has_uppercase_acronyms:
        return 'BM25 likely wins (exact terms)'
    elif is_short:
        return 'Dense likely wins (semantic matching needed)'
    else:
        return 'Hybrid recommended (mixed signals)'

Score Incompatibility Problem

Combining dense and sparse results is non-trivial because their scores are on incompatible scales. Cosine similarity produces values between -1 and 1, while BM25 produces unbounded positive scores that depend on corpus size. You cannot simply add them. The standard solution is to use rank-based fusion rather than score-based fusion — merging ranked lists instead of raw scores.

Practical Decision: When to Use Each

Use dense-only retrieval when your corpus is in a narrow domain with consistent vocabulary and you need semantic generalization across paraphrases. Use BM25-only when queries are primarily lookup-style with exact identifiers and your dataset is small enough that brute-force is feasible. Use hybrid in all production RAG systems where query types vary — the overhead is modest and the recall improvement is significant.

Performance and Infrastructure Trade-offs

Dense retrieval requires GPU-accelerated approximate nearest neighbor search or a vector database, which adds infrastructure cost. BM25 runs entirely on CPU with an inverted index and is extremely fast. Hybrid retrieval requires both infrastructure components plus a fusion step. The added complexity is justified by the recall improvement for most production use cases, but must be weighed against your infrastructure budget.

Quick Check

Test your understanding of dense versus sparse retrieval trade-offs from this lesson.

Lesson Recap

In this lesson you learned: dense retrieval captures semantic meaning but fails on rare exact terms, BM25 sparse retrieval handles exact keywords but misses paraphrases, and hybrid retrieval consistently outperforms either method alone across diverse query types. Their scores are incompatible and must be merged via rank fusion rather than score addition. Next up we implement BM25 keyword search in Python.

Часто задаваемые вопросы

Урок «Плотный и разреженный поиск: компромиссы» бесплатный?

Да — полный текст урока «Плотный и разреженный поиск: компромиссы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Engineering Academy, подпишись на CoddyKit PRO. Курс AI Engineering Academy содержит 4 уроков всего.

Чему я научусь в уроке «Плотный и разреженный поиск: компромиссы»?

Разберитесь, когда плотные эмбеддинги не находят точные совпадения ключевых слов, а BM25 пропускает семантические перефразирования, и почему их сочетание стабильно превосходит каждый подход по отдель… Ты практикуешь AI Engineering Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Engineering Academy?

Предыдущий опыт не требуется. AI Engineering Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Плотный и разреженный поиск: компромиссы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Engineering Academy?

Да. Каждый урок AI Engineering Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Плотный и разреженный поиск: компромиссы
  2. Реализация поиска по ключевым словам BM25
  3. Объединение оценок с помощью слияния обратных рангов
  4. Гибридный поиск в Pinecone и pgvector
← Назад к AI Engineering Academy