Машинное обучение и особенно нейросети позволяют преобразовывать «неструктурированные данные» в векторы фиксированной длины (чаще всего float32), которые сохраняют семантику исходного объекта. Например, два похожих текста будут иметь близкие векторы (малая евклидова дистанция или высокая косинусная близость).
Векторные базы данных (vector databases):
это специализированные хранилища, предназначенные для эффективного поиска и сопоставления векторов (обычно — эмбеддингов), которые представляют объекты вроде текста, изображений, аудио или видео в числовом виде.
Что обычно хранится в векторной базе
Компонент | Что это | Пример |
---|---|---|
ID | Уникальный идентификатор записи | «doc-001» или 123 |
Вектор | Числовой список, представляющий объект | [0.12, -0.56, 0.44, …, -0.03] (обычно float32) |
Документ | Исходный текст или файл (опционально) | «Как дела?» |
Метаданные | Доп. поля для фильтрации, тегов, контекста | {«language»: «ru», «user»: «petya», «tags»: [«faq»]} |
Популярные векторные базы
Название | Разработчик | Индексирование | Метрики | Плюсы | Минусы |
---|---|---|---|---|---|
Milvus | Zilliz | IVF_FLAT, IVF_SQ8, IVF_PQ, HNSW, ANNOY, Flat | L2, IP, Cosine, Jaccard, Hamming | Масштабируемость (миллиарды точек) Много индексов gRPC/REST | Требует Docker или Standalone Сложнее развернуть |
Qdrant | Qdrant (на Rust) | HNSW (модифицированный), Flat | Cosine, Dot, Euclidean (L2) | Быстрый, Rust-движок Лёгкая установка Фильтрация по метаданным | Пока меньше индексов Нет встроенной кластеризации |
Weaviate | Semi.technologies | HNSW + Text (Hybrid Search) | Cosine, Dot, Euclidean | Гибридный поиск (BM25 + векторный) GraphQL API Автоинжекция данных | Требует больше памяти GraphQL не всегда удобен |
Chroma | Chroma org | Flat (точный), HNSW (в roadmap/частично) | Cosine | Очень простая установка Идеален для RAG и локального запуска | Только Flat (пока) Нет фильтрации по метаданным (частично есть) |
FAISS | Facebook/Meta | Flat, IVF, PQ, OPQ, HNSW, LSH | L2, Dot, Cosine (через нормализацию) | Очень гибкий GPU-поддержка Лучшая производительность на CPU/GPU | Это библиотека, не сервер Нужна ручная настройка и кодирование |
OpenSearch | Amazon | HNSW, Faiss backend, ANN native plugin | L2, Dot, Cosine | Гибридный поиск (BM25 + ANN) Интеграция с текстом Elasticsearch-совместим | Сложная настройка ANN Высокие требования к памяти |
Преобразование данных в векторы (Embedding)
Например, текст «Как дела?» может быть преобразован в вектор из 384 значений
[0.12, -0.56, 0.44, ..., -0.03]
Для этого используются специализированные embedding модели, такие как:
Название | Что кодирует и как работает | Преимущества |
---|---|---|
all-MiniLM-L6-v2 | Лёгкая и быстрая модель на базе Transformer Кодирует фразы, вопросы, абзацы | Компактная (~80MB) Поддержка в sentence-transformers Работает «из коробки» |
text-embedding-ada-002 (OpenAI) | Коммерческая модель от OpenAI Требует API-ключ Кодирует любые тексты | Высокое качество эмбеддингов Поддержка разных языков Отлично подходит для RAG |
bge-small-en | Современная модель от BAAI Поддерживает шаблоны: «query:…», «passage:…» | Высокая точность Поддержка многоязычия (в M3E) Отлична для Qdrant, LangChain |
e5-base / e5-large | Универсальные модели от FlagAI Подходят для поиска, кластеризации, QA | Лучшие показатели на MTEB Поддержка многоязычных задач Работают без fine-tune |
Instructor-XL | Кодирует текст с учётом задачи Использует инструкции в стиле: «Represent the … for …» | Повышенная точность Подходит для task-aware embedding Отлично для RAG/FAQ |
mpnet-base-v2 | От Microsoft Контекстно-чувствительная модель Хороша для похожих фраз | Хороший баланс точности и скорости Подходит для paraphrase и general search |
LaBSE | От Google Многоязычная модель Лучше всего с короткими предложениями | Поддержка 100+ языков Отличный выбор для кросс-языкового поиска |
Типичные размеры векторов (длины эмбеддингов) разных моделей:
Модель | Длина вектора |
---|---|
all-MiniLM-L6-v2 | 384 |
text-embedding-ada-002 (OpenAI) | 1536 |
bge-small-en | 384 |
bge-base-en | 768 |
bge-large-en | 1024 |
e5-small-v2 | 384 |
e5-base-v2 | 768 |
e5-large-v2 | 1024 |
mpnet-base-v2 | 768 |
LaBSE | 768 |
Instructor-XL | 768 или 1024 |
Индексирование векторов
Вектора, соответствующие объектам, индексируются, чтобы потом можно было быстро по входящему вектору искать максимально близкие из сохраненных в базе.
Способы индексации векторов:
Виды индексов:
Название | Как работает | Преимущества | Недостатки |
---|---|---|---|
Flat | Перебирает все векторы вручную | Самый точный поиск Простая реализация Идеально для отладки и небольших наборов | Очень медленно при большом объёме Требует много вычислений Не масштабируется |
HNSW | Поиск по сети похожих векторов (начиная с «центров») | Очень быстрый Высокая точность Подходит для больших баз | Требует много памяти Долгое построение индекса Сложен в параметризации |
IVF | Делит векторы на группы (кластеры), ищет только в них | Быстрее, чем Flat Гибкая настройка (nprobe) Хорошо масштабируется | Может пропустить похожие векторы Требует предварительного обучения |
PQ | Заменяет части вектора короткими кодами | Сильно экономит память Быстрый поиск по таблице Идеален для больших наборов | Потеря точности Требуется обучение (codebook) Не для задач с высокой точностью |
OPQ | Улучшенная версия PQ — сначала «поправляет» вектор | Выше точность, чем у PQ Хорошо работает в FAISS, Milvus Комбинируется с IVF | Сложнее в обучении Всё ещё приближённый метод |
Annoy | Строит много случайных деревьев, ищет по ним | Прост в использовании Мало зависит от ресурсов Подходит для CPU и мобильных | Менее точный, чем HNSW Долгое построение индекса Нельзя обновить после построения |
Поиск ближайших векторов (Similarity Search)
Когда пользователь вводит запрос, он преобразуется в вектор, и база выполняет поиск ближайших соседей (KNN) по выбранной метрике.
Виды метрик:
Название метрики | Как работает | Преимущества | Недостатки |
---|---|---|---|
Cosine Similarity | Сравниваем угол между векторами. Чем ближе угол к 0°, тем больше сходство. | Учитывает только направление Хорошо работает с текстами и эмбеддингами Не зависит от длины вектора | Не учитывает масштаб (длину) Не подходит, если длина вектора важна |
Euclidean (L2) | Меряем «линейное» расстояние между точками. Ближе — значит похожее. | Простая и интуитивно понятная Подходит для координат, изображений | Не нормирует вектора (масштаб влияет) Не всегда хорошо для текстов |
Inner Product (Dot Product) | Складываем соответствующие координаты. Чем больше сумма, тем выше сходство. | Очень быстро считается Хорошо работает с ненормализованными векторами | Чувствителен к длине вектора Могут быть трудно интерпретируемые значения |
Manhattan (L1) | Сумма модулей разностей по каждой координате — как по клеткам на сетке. | Устойчив к выбросам Лучше работает с разреженными векторами | Реже используется Хуже работает с плотными векторами |
Hamming Distance | Считаем количество битов, в которых отличаются два бинарных вектора. | Очень быстрый для бинарных данных Подходит для fingerprint и хэшей | Работает только с бинарными векторами Не применим к float |
Jaccard Similarity | Отношение пересечения к объединению множеств или бинарных векторов. | Идеален для тегов и бинарных признаков Понятная метрика | Только для бинарных векторов Не работает с float-векторами |
Tanimoto | Обобщённая Jaccard-метрика, применимая и к float-векторам. | Подходит для химических структур, fingerprint Работает и с бинарными, и с вещественными | Редко используется Ограниченная поддержка в библиотеках |
Пример работы с векторной базой
В примере CRUD операций будем использовать Python, базу Milvus, embedding модель e5‑base
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection from pymilvus.model.dense import SentenceTransformerEmbeddingFunction # 1. Подключение к Milvus (по умолчанию localhost:19530) connections.connect("default", host="localhost", port="19530") # 2. Инициализация функции эмбеддинга с моделью e5-base-v2 # Эта модель требует: # - Префикс "passage: " для документов # - Префикс "query: " для поисковых запросов ef = SentenceTransformerEmbeddingFunction("intfloat/e5-base-v2") # 3. Определение схемы коллекции: # - "id" — целочисленный идентификатор (первичный ключ) # - "text" — исходный текст документа (строка) # - "emb" — эмбеддинг-вектор размерности 768 fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=False), FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=512), FieldSchema(name="emb", dtype=DataType.FLOAT_VECTOR, dim=768) ] schema = CollectionSchema(fields, description="Коллекция с эмбеддингами от e5-base-v2") # 4. Создание коллекции в Milvus с заданной схемой collection = Collection("e5_collection", schema) # 5. Подготовка и вставка документов # Важно: перед подачей в модель нужно добавить префикс "passage: " raw_docs = ["Hello world", "Milvus vector database", "Semantic search with e5 model"] docs = [f"passage: {d}" for d in raw_docs] # добавляем префикс ids = [1, 2, 3] # Вычисляем эмбеддинги для документов используя e5‑base embs = ef.encode_documents(docs) # Вставляем в коллекцию: # - идентификаторы # - исходные (чистые) тексты без префиксов # - эмбеддинги collection.insert([ids, raw_docs, embs]) # 6. Создание индекса по полю "emb" для ускорения поиска collection.create_index( field_name="emb", index_params={ # тип индекса "index_type": "IVF_FLAT", # параметр разбиения на кластеры "params": {"nlist": 128}, # метрика расстояния (евклидово расстояние) "metric_type": "L2" } ) # 7. Загрузка коллекции в оперативную память # Без этого поиск работать не будет collection.load() # 8. Поисковый запрос # Аналогично — используем префикс "query: " перед текстом запроса query_docs = ["query: vector database"] q_emb = ef.encode_queries(query_docs) # Выполняем семантический поиск по эмбеддингам results = collection.search( # эмбеддинг поискового запроса data=q_emb, # поле, по которому осуществляется поиск anns_field="emb", # параметры поиска param={"metric_type": "L2", "params": {"nprobe": 10}}, # количество ближайших соседей limit=2, # дополнительные поля, которые нужно вернуть output_fields=["text"] ) # 9. Выводим результаты поиска for i, hits in enumerate(results): print(f"Результаты для запроса: '{query_docs[i]}'") if not hits: print("Ничего не найдено") continue for rank, hit in enumerate(hits, start=1): print(f" {rank}:") print(f" ID: {hit.id}") print(f" Текст: {hit.entity.get('text')}") print(f" Расстояние: {hit.distance:.4f}") # Результаты для запроса: 'query: vector database' # 1: # ID: 2 # Текст: Milvus vector database # Расстояние: 2.8374 # 2: # ID: 3 # Текст: Semantic search with e5 model # Расстояние: 5.4931 # 10. Удаление документа по ID # В данном случае удаляется документ с id = 1 collection.delete(expr="id in [1]") # 11. Удаление всей коллекции (если больше не нужна) collection.drop()