---
title: "Векторні бази даних"
url: "https://romankryvolapov.com/uk/vector-databases/"
description: "Векторні бази на практиці: чим відрізняються Milvus, Qdrant і Weaviate, як рахуються ембединги, працюють індекси HNSW та пошук за схожістю."
language: uk
updated: 2026-01-21
---
Машинне навчання і особливо нейромережі дозволяють перетворювати "неструктуровані дані" на вектори фіксованої довжини (найчастіше 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 | Масштабованість (мільярди точок)<br>Багато індексів<br>gRPC/REST | Потребує Docker або Standalone<br>Складніше розгорнути |
| **Qdrant** | Qdrant (на Rust) | HNSW (модифікований), Flat | Cosine, Dot, Euclidean (L2) | Швидкий, Rust-рушій<br>Легке встановлення<br>Фільтрація за метаданими | Поки менше індексів<br>Немає вбудованої кластеризації |
| **Weaviate** | Semi.technologies | HNSW + Text (Hybrid Search) | Cosine, Dot, Euclidean | Гібридний пошук (BM25 + векторний)<br>GraphQL API<br>Автоінжекція даних | Потребує більше пам'яті<br>GraphQL не завжди зручний |
| **Chroma** | Chroma org | Flat (точний), HNSW (у roadmap/частково) | Cosine | Дуже просте встановлення<br>Ідеальний для RAG і локального запуску | Тільки Flat (поки)<br>Немає фільтрації за метаданими (частково є) |
| **FAISS** | Facebook/Meta | Flat, IVF, PQ, OPQ, HNSW, LSH | L2, Dot, Cosine (через нормалізацію) | Дуже гнучкий<br>GPU-підтримка<br>Найкраща продуктивність на CPU/GPU | Це бібліотека, не сервер<br>Потрібне ручне налаштування і кодування |
| **OpenSearch** | Amazon | HNSW, Faiss backend, ANN native plugin | L2, Dot, Cosine | Гібридний пошук (BM25 + ANN)<br>Інтеграція з текстом<br>Elasticsearch-сумісний | Складне налаштування ANN<br>Високі вимоги до пам'яті |

## Перетворення даних на вектори (Embedding)

Наприклад, текст "Як справи?" може бути перетворений на вектор із 384 значень

```kotlin
[0.12, -0.56, 0.44, ..., -0.03]
```

Для цього використовуються спеціалізовані embedding моделі, такі як:

| **Назва** | **Що кодує і як працює** | **Переваги** |
| --- | --- | --- |
| **all-MiniLM-L6-v2** | Легка і швидка модель на базі Transformer<br>Кодує фрази, питання, абзаци | Компактна (~80MB)<br>Підтримка в sentence-transformers<br>Працює «з коробки» |
| **text-embedding-ada-002**<br>(OpenAI) | Комерційна модель від OpenAI<br>Потребує API-ключа<br>Кодує будь-які тексти | Висока якість ембедингів<br>Підтримка різних мов<br>Чудово підходить для RAG |
| **bge-small-en** | Сучасна модель від BAAI<br>Підтримує шаблони: "query:...", "passage:..." | Висока точність<br>Підтримка багатомовності (у M3E)<br>Чудова для Qdrant, LangChain |
| **e5-base / e5-large** | Універсальні моделі від FlagAI<br>Підходять для пошуку, кластеризації, QA | Найкращі показники на MTEB<br>Підтримка багатомовних завдань<br>Працюють без fine-tune |
| **Instructor-XL** | Кодує текст з урахуванням завдання<br>Використовує інструкції у стилі: "Represent the ... for ..." | Підвищена точність<br>Підходить для task-aware embedding<br>Чудово для RAG/FAQ |
| **mpnet-base-v2** | Від Microsoft<br>Контекстно-чутлива модель<br>Добра для схожих фраз | Хороший баланс точності і швидкості<br>Підходить для paraphrase і general search |
| **LaBSE** | Від Google<br>Багатомовна модель<br>Найкраще з короткими реченнями | Підтримка 100+ мов<br>Чудовий вибір для крос-мовного пошуку |

Типові розміри векторів (довжини ембедингів) різних моделей:

| **Модель** | **Довжина вектора** |
| --- | --- |
| 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** | Перебирає всі вектори вручну | Найточніший пошук<br>Проста реалізація<br>Ідеально для налагодження і невеликих наборів | Дуже повільно за великого обсягу<br>Потребує багато обчислень<br>Не масштабується |
| **HNSW** | Пошук за мережею схожих векторів (починаючи з "центрів") | Дуже швидкий<br>Висока точність<br>Підходить для великих баз | Потребує багато пам'яті<br>Довга побудова індексу<br>Складний у параметризації |
| **IVF** | Ділить вектори на групи (кластери), шукає тільки в них | Швидше, ніж Flat<br>Гнучке налаштування (nprobe)<br>Добре масштабується | Може пропустити схожі вектори<br>Потребує попереднього навчання |
| **PQ** | Замінює частини вектора короткими кодами | Сильно економить пам'ять<br>Швидкий пошук за таблицею<br>Ідеальний для великих наборів | Втрата точності<br>Потрібне навчання (codebook)<br>Не для завдань з високою точністю |
| **OPQ** | Покращена версія PQ — спочатку "виправляє" вектор | Вища точність, ніж у PQ<br>Добре працює у FAISS, Milvus<br>Комбінується з IVF | Складніший у навчанні<br>Все ще наближений метод |
| **Annoy** | Будує багато випадкових дерев, шукає за ними | Простий у використанні<br>Мало залежить від ресурсів<br>Підходить для CPU і мобільних | Менш точний, ніж HNSW<br>Довга побудова індексу<br>Не можна оновити після побудови |

## Пошук найближчих векторів (Similarity Search)

Коли користувач вводить запит, він перетворюється на вектор, і база виконує пошук найближчих сусідів (KNN) за обраною метрикою.

**Види метрик:**

| **Назва метрики** | **Як працює** | **Переваги** | **Недоліки** |
| --- | --- | --- | --- |
| **Cosine Similarity** | Порівнюємо кут між векторами. Що ближчий кут до 0°, то більша схожість. | Враховує тільки напрямок<br>Добре працює з текстами і ембедингами<br>Не залежить від довжини вектора | Не враховує масштаб (довжину)<br>Не підходить, якщо довжина вектора важлива |
| **Euclidean (L2)** | Міряємо «лінійну» відстань між точками. Ближче — значить схоже. | Проста й інтуїтивно зрозуміла<br>Підходить для координат, зображень | Не нормує вектори (масштаб впливає)<br>Не завжди добре для текстів |
| **Inner Product (Dot Product)** | Додаємо відповідні координати. Що більша сума, то вища схожість. | Дуже швидко рахується<br>Добре працює з ненормалізованими векторами | Чутливий до довжини вектора<br>Можуть бути важко інтерпретовані значення |
| **Manhattan (L1)** | Сума модулів різниць за кожною координатою — як по клітинках на сітці. | Стійкий до викидів<br>Краще працює з розрідженими векторами | Рідше використовується<br>Гірше працює зі щільними векторами |
| **Hamming Distance** | Рахуємо кількість бітів, у яких відрізняються два бінарні вектори. | Дуже швидкий для бінарних даних<br>Підходить для fingerprint і хешів | Працює тільки з бінарними векторами<br>Не застосовний до float |
| **Jaccard Similarity** | Відношення перетину до об'єднання множин або бінарних векторів. | Ідеальний для тегів і бінарних ознак<br>Зрозуміла метрика | Тільки для бінарних векторів<br>Не працює з float-векторами |
| **Tanimoto** | Узагальнена Jaccard-метрика, застосовна і до float-векторів. | Підходить для хімічних структур, fingerprint<br>Працює і з бінарними, і з дійсними | Рідко використовується<br>Обмежена підтримка в бібліотеках |

## Приклад роботи з векторною базою

У прикладі CRUD операцій використовуватимемо Python, базу Milvus, embedding модель e5‑base

```python
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()
```

[Copyright: Roman Kryvolapov](https://t.me/RomanKryvolapov)
