Перейти к содержимому

Векторные базы данных

Машинное обучение и особенно нейросети позволяют преобразовывать «неструктурированные данные» в векторы фиксированной длины (чаще всего float32), которые сохраняют семантику исходного объекта. Например, два похожих текста будут иметь близкие векторы (малая евклидова дистанция или высокая косинусная близость).

Векторные базы данных (vector databases):
это специализированные хранилища, предназначенные для эффективного поиска и сопоставления векторов (обычно — эмбеддингов), которые представляют объекты вроде текста, изображений, аудио или видео в числовом виде.

КомпонентЧто этоПример
IDУникальный идентификатор записи«doc-001» или 123
ВекторЧисловой список, представляющий объект[0.12, -0.56, 0.44, …, -0.03] (обычно float32)
ДокументИсходный текст или файл (опционально)«Как дела?»
МетаданныеДоп. поля для фильтрации, тегов, контекста{«language»: «ru», «user»: «petya», «tags»: [«faq»]}
НазваниеРазработчикИндексированиеМетрикиПлюсыМинусы
MilvusZillizIVF_FLAT, IVF_SQ8, IVF_PQ, HNSW, ANNOY, FlatL2, IP, Cosine, Jaccard, HammingМасштабируемость (миллиарды точек)
Много индексов
gRPC/REST
Требует Docker или Standalone
Сложнее развернуть
QdrantQdrant (на Rust)HNSW (модифицированный), FlatCosine, Dot, Euclidean (L2)Быстрый, Rust-движок
Лёгкая установка
Фильтрация по метаданным
Пока меньше индексов
Нет встроенной кластеризации
WeaviateSemi.technologiesHNSW + Text (Hybrid Search)Cosine, Dot, EuclideanГибридный поиск (BM25 + векторный)
GraphQL API
Автоинжекция данных
Требует больше памяти
GraphQL не всегда удобен
ChromaChroma orgFlat (точный), HNSW (в roadmap/частично)CosineОчень простая установка
Идеален для RAG и локального запуска
Только Flat (пока)
Нет фильтрации по метаданным (частично есть)
FAISSFacebook/MetaFlat, IVF, PQ, OPQ, HNSW, LSHL2, Dot, Cosine (через нормализацию)Очень гибкий
GPU-поддержка
Лучшая производительность на CPU/GPU
Это библиотека, не сервер
Нужна ручная настройка и кодирование
OpenSearchAmazonHNSW, Faiss backend, ANN native pluginL2, Dot, CosineГибридный поиск (BM25 + ANN)
Интеграция с текстом
Elasticsearch-совместим
Сложная настройка ANN
Высокие требования к памяти

Например, текст «Как дела?» может быть преобразован в вектор из 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-v2384
text-embedding-ada-002 (OpenAI)1536
bge-small-en384
bge-base-en768
bge-large-en1024
e5-small-v2384
e5-base-v2768
e5-large-v21024
mpnet-base-v2768
LaBSE768
Instructor-XL768 или 1024

Вектора, соответствующие объектам, индексируются, чтобы потом можно было быстро по входящему вектору искать максимально близкие из сохраненных в базе.
Способы индексации векторов:

Виды индексов:

НазваниеКак работаетПреимуществаНедостатки
FlatПеребирает все векторы вручнуюСамый точный поиск
Простая реализация
Идеально для отладки и небольших наборов
Очень медленно при большом объёме
Требует много вычислений
Не масштабируется
HNSWПоиск по сети похожих векторов (начиная с «центров»)Очень быстрый
Высокая точность
Подходит для больших баз
Требует много памяти
Долгое построение индекса
Сложен в параметризации
IVFДелит векторы на группы (кластеры), ищет только в нихБыстрее, чем Flat
Гибкая настройка (nprobe)
Хорошо масштабируется
Может пропустить похожие векторы
Требует предварительного обучения
PQЗаменяет части вектора короткими кодамиСильно экономит память
Быстрый поиск по таблице
Идеален для больших наборов
Потеря точности
Требуется обучение (codebook)
Не для задач с высокой точностью
OPQУлучшенная версия PQ — сначала «поправляет» векторВыше точность, чем у PQ
Хорошо работает в FAISS, Milvus
Комбинируется с IVF
Сложнее в обучении
Всё ещё приближённый метод
AnnoyСтроит много случайных деревьев, ищет по нимПрост в использовании
Мало зависит от ресурсов
Подходит для CPU и мобильных
Менее точный, чем HNSW
Долгое построение индекса
Нельзя обновить после построения

Когда пользователь вводит запрос, он преобразуется в вектор, и база выполняет поиск ближайших соседей (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()