Векторни бази данни
Машинното обучение и особено невронните мрежи позволяват да се преобразуват „неструктурирани данни“ във вектори с фиксирана дължина (най-често 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()