# Dense Retrieval (Embedding-based Search)
> [!SUMMARY]+ Краткое резюме
> - Текст преобразуется в плотный вектор фиксированной размерности
> - Поиск = нахождение ближайших векторов по косинусному расстоянию
> - Работает с синонимами и перефразировками
## Принцип работы
Каждый документ и запрос преобразуются в ==плотный вектор== (dense vector) фиксированной размерности (256–4096). Все позиции вектора заполнены значениями (в отличие от sparse, где большинство — нули).
```mermaid
flowchart LR
subgraph Индексация
D[Документы] --> E1[Encoder]
E1 --> V1[Векторы 768-4096 dim]
V1 --> DB[(Vector DB)]
end
subgraph Поиск
Q[Запрос] --> E2[Encoder]
E2 --> V2[Вектор запроса]
V2 --> S[Similarity Search]
DB --> S
S --> R[Top-K результатов]
end
```
**Меры близости:**
- **Cosine similarity** — угол между векторами (самый популярный)
- **Dot product** — скалярное произведение (быстрее, если векторы нормализованы)
- **Euclidean distance** — евклидово расстояние
$\text{cosine}(a, b) = \frac{a \cdot b}{\|a\| \cdot \|b\|}$
---
## Модели эмбеддингов
### Коммерческие API
| Модель | Размерность | Контекст | Особенности |
|--------|-------------|----------|-------------|
| `text-embedding-3-large` (OpenAI) | 3072 | 8191 | Лучшее качество |
| `text-embedding-3-small` (OpenAI) | 1536 | 8191 | Баланс цена/качество |
| `embed-v4` (Cohere) | 1024 | 512 | Мультиязычный |
| `voyage-3` (Voyage AI) | 1024 | 32000 | Длинный контекст |
### Open-source модели
| Модель | Размерность | Языки | MTEB Score |
|--------|-------------|-------|------------|
| `BAAI/bge-m3` | 1024 | 100+ | 66.5 |
| `intfloat/multilingual-e5-large` | 1024 | 100+ | 64.5 |
| `sentence-transformers/all-MiniLM-L6-v2` | 384 | EN | 56.3 |
| `nomic-ai/nomic-embed-text-v1.5` | 768 | EN | 62.3 |
| `Alibaba-NLP/gte-large-en-v1.5` | 1024 | EN | 65.4 |
> [!TIP] Выбор модели
> - **Прототип:** `all-MiniLM-L6-v2` — быстрый, 384 dim
> - **Production (EN):** `bge-large-en-v1.5` или `gte-large`
> - **Мультиязычный:** `bge-m3` или `multilingual-e5-large`
> - **Максимальное качество:** OpenAI `text-embedding-3-large`
---
## Примеры кода
### OpenAI Embeddings
```python
from openai import OpenAI
import numpy as np
client = OpenAI()
def get_embedding(text: str, model="text-embedding-3-small") -> list[float]:
"""Получить embedding для текста."""
response = client.embeddings.create(
input=text,
model=model
)
return response.data[0].embedding
def cosine_similarity(a: list, b: list) -> float:
"""Косинусное сходство между векторами."""
a, b = np.array(a), np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# Пример использования
docs = [
"Kubernetes — система оркестрации контейнеров",
"Рецепт борща с говядиной",
"Machine learning pipeline на Python"
]
# Индексация
doc_embeddings = [get_embedding(d) for d in docs]
# Поиск
query = "как деплоить контейнеры"
query_emb = get_embedding(query)
scores = [cosine_similarity(query_emb, de) for de in doc_embeddings]
# [0.82, 0.15, 0.31] — первый документ наиболее релевантен
```
### Sentence Transformers (локально)
```python
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer('BAAI/bge-m3')
docs = [
"Kubernetes — система оркестрации контейнеров",
"Рецепт борща с говядиной",
"Machine learning pipeline на Python"
]
# Индексация (batch encoding — быстрее)
doc_embeddings = model.encode(docs, normalize_embeddings=True)
# Поиск
query = "как деплоить контейнеры"
query_emb = model.encode(query, normalize_embeddings=True)
# Dot product (векторы нормализованы = cosine)
scores = doc_embeddings @ query_emb
```
### С векторной БД (Qdrant)
```python
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
from sentence_transformers import SentenceTransformer
# Инициализация
client = QdrantClient(":memory:") # или url="http://localhost:6333"
model = SentenceTransformer('BAAI/bge-m3')
# Создание коллекции
client.create_collection(
collection_name="docs",
vectors_config=VectorParams(size=1024, distance=Distance.COSINE)
)
# Индексация
docs = ["Kubernetes basics", "Docker tutorial", "Helm charts guide"]
embeddings = model.encode(docs)
client.upsert(
collection_name="docs",
points=[
PointStruct(id=i, vector=emb.tolist(), payload={"text": doc})
for i, (doc, emb) in enumerate(zip(docs, embeddings))
]
)
# Поиск
query_emb = model.encode("container orchestration")
results = client.search(
collection_name="docs",
query_vector=query_emb.tolist(),
limit=3
)
```
---
## Плюсы и минусы
> [!SUCCESS] Преимущества
> - **Семантика** — находит документы по смыслу, не по словам
> - **Синонимы** — «машина» найдёт «автомобиль»
> - **Мультиязычность** — запрос на русском найдёт документ на английском
> - **Перефразировки** — разные формулировки одного вопроса работают
> [!FAIL] Недостатки
> - **Редкие термины** — плохо ищет аббревиатуры, ID, коды (`ERR_CONNECTION_REFUSED`)
> - **Точное совпадение** — может не найти документ с точным словом из запроса
> - **Ресурсы** — требует GPU для больших объёмов
> - **Галлюцинации** — может вернуть семантически близкий, но нерелевантный документ
---
## Оптимизация
### Chunking (разбиение документов)
```python
def chunk_text(text: str, chunk_size: int = 512, overlap: int = 100) -> list[str]:
"""Разбить текст на чанки с перекрытием."""
words = text.split()
chunks = []
for i in range(0, len(words), chunk_size - overlap):
chunk = " ".join(words[i:i + chunk_size])
chunks.append(chunk)
return chunks
```
> [!IMPORTANT] Рекомендации по chunking
> - **Размер:** 256–1024 токенов (зависит от модели)
> - **Overlap:** 10–20% от размера чанка
> - **Границы:** лучше по предложениям/абзацам, не по словам
### Quantization (сжатие векторов)
- **Scalar quantization** — float32 → int8 (4x меньше памяти)
- **Binary quantization** — float → bit (32x меньше, но потеря качества)
- **Product quantization** — разбиение на подвекторы
---
## Когда использовать
| Сценарий | Подходит? |
|----------|-----------|
| Поиск по документации | ++ |
| FAQ / Q&A системы | +++ |
| RAG для LLM | +++ |
| Поиск похожих товаров | +++ |
| Поиск по логам (точные ID) | - |
| Поиск кода по имени функции | - |
---
## Связанные страницы
- [[Семантический поиск]] — обзор всех методов
- [[Sparse Retrieval]] — альтернативный подход (BM25, SPLADE)
- [[Hybrid Search]] — комбинация dense + sparse
- [[Re-ranking]] — улучшение качества результатов