---
title: "Векторни бази данни"
url: "https://romankryvolapov.com/bg/vector-databases/"
description: "Векторни бази на практика: с какво се различават Milvus, Qdrant и Weaviate, как се изчисляват ембедингите, как работят индексите HNSW и търсенето по близост."
language: bg
published: 2025-08-13
updated: 2026-11-13
---
Машинното обучение и особено невронните мрежи позволяват да се преобразуват „неструктурирани данни“ във вектори с фиксирана дължина (най-често 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 стойности

```text
[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)
