Векторні бази даних
Машинне навчання і особливо нейромережі дозволяють перетворювати "неструктуровані дані" на вектори фіксованої довжини (найчастіше 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, Collectionfrom 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" — ембединг-вектор розмірності 768fields = [ 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‑baseembs = 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 = 1collection.delete(expr="id in [1]")
# 11. Видалення всієї колекції (якщо більше не потрібна)collection.drop()