# 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]] — улучшение качества результатов