Как да създам vector database?

Най-практичният начин да „създадеш vector database“ е да избереш платформа (най-често Postgres + pgvector за старт или управлявана услуга като Pinecone/Weaviate/Qdrant), да дефинираш схема за (текст + embedding + метаданни), да индексираш за бързо търсене по сходство и да изградиш надежден процес за ingest (chunking, embeddings, обновявания и мониторинг).

Vector database е полезна само ако имаш ясна дефиниция какво означава „сходство“ за твоите данни.

Въведение

Vector database (vector DB) е база, оптимизирана за съхранение и бързо търсене на вектори (embedding-и) с метрики като cosine similarity или dot product. Това е основен компонент в RAG (Retrieval-Augmented Generation), семантично търсене, препоръчващи системи и детекция на дубликати.

В тази статия ще минем през процес, който работи в реални проекти: започваш с минимална, ясна архитектура (за да стигнеш до работещ прототип), после добавяш индекси, филтри, обновявания и оценка на качеството.

Стъпка 1: Изясни use case и метриката за сходство

Преди да инсталираш каквото и да е, отговори на тези въпроси:

  • Какво търсиш: „най-близки по смисъл параграфи“, „подобни продукти“, „сходни тикети“, „подобни изображения“?
  • Какъв е входът: текст, таблици, PDF, изображения, аудио?
  • Какво е unit of retrieval: документ, страница, параграф, изречение?
  • Нужни ли са филтри: по език, дата, клиент, тагове, права за достъп?

Метриката има значение:

  • Cosine similarity: често работи добре за нормализирани embedding-и.
  • Dot product: удобна и бърза; често еквивалентна при нормализация.
  • Euclidean distance: по-рядко в практиката за текст.

Най-честата причина vector DB да „не работи“ е лош chunking и неподходящ embedding модел, не самата база.

Стъпка 2: Избери платформа: Postgres + pgvector или управлявана услуга

Има два разумни пътя.

Вариант A: Postgres + pgvector (често най-добрият старт)

Подходящо, ако:

  • правиш MVP или пилот;
  • искаш и класически SQL заявки + векторно търсене в една база;
  • имаш нужда от транзакции, RLS/права, joins и отчетност.

Можеш да го пуснеш локално (Docker) или като управляван Postgres (например Supabase). В Supabase цената зависи от compute и disk; страницата им за Compute and Disk описва примерни планове и как се формират разходите за compute, storage и I/O (проверено към 10 февруари 2026).

Вариант B: Управлявана vector DB услуга (Pinecone / Weaviate / Qdrant)

Подходящо, ако:

  • очакваш бърз растеж и искаш „готово за продукция“ с минимален DevOps;
  • търсиш специфични възможности (многорегионност, HA, специализирани оптимизации).

Към началото на 2026 (провери страниците за ценообразуване преди решение):

  • Pinecone: има Starter и Standard планове, като Standard започва от минимум месечна такса и после се таксува според ползването.
  • Weaviate Cloud: публикува облачни планове/минимуми и различни режими (включително serverless).
  • Qdrant Cloud: има free tier и платени планове според ресурси.

Ако не си сигурен за натоварването и данните, започни с Postgres + pgvector и мигрирай към специализирана услуга, когато имаш метрики и болки.

Стъпка 3: Създай схема и индекси (пример с PostgreSQL + pgvector)

1) Инсталирай разширението

CREATE EXTENSION IF NOT EXISTS vector;

2) Създай таблица за chunk-ове

Измеренията (vector(1536) например) трябва да съвпадат с embedding модела, който използваш.

CREATE TABLE IF NOT EXISTS doc_chunks (
  id bigserial primary key,
  doc_id text not null,
  source text,
  chunk_index int not null,
  content text not null,
  metadata jsonb default '{}'::jsonb,
  embedding vector(1536) not null,
  created_at timestamptz default now()
);

CREATE INDEX IF NOT EXISTS doc_chunks_doc_id_idx ON doc_chunks (doc_id);
CREATE INDEX IF NOT EXISTS doc_chunks_metadata_gin ON doc_chunks USING gin (metadata);

3) Добави векторен индекс

Подходът зависи от pgvector версията и размера на данните. За старт (и малки обеми) може да минеш и без индекс, но за реално търсене ще ти трябва.

Пример (HNSW, ако е налично):

CREATE INDEX IF NOT EXISTS doc_chunks_embedding_hnsw
ON doc_chunks USING hnsw (embedding vector_cosine_ops);

Важно: индексът ускорява, но изисква настройка и периодично VACUUM/ANALYZE.

Стъпка 4: Подготви данните: чистене, chunking, метаданни

Добър ingest започва с дисциплина:

  • Нормализирай текста (премахни шум, странни символи, повторения).
  • Chunking:
    • за общ текст: 300–800 думи е добър старт;
    • добави overlap (например 10–20%), за да не режеш смисъл по средата;
    • пази chunk_index, за да можеш да възстановиш контекст.
  • Метаданни:
    • language, created_date, customer_id, permissions, tags;
    • ако ще филтрираш, сложи ги в metadata и индексирай (GIN).

Стъпка 5: Генерирай embeddings (API или локален модел)

Имаш два варианта:

  • API услуга (по-бързо за старт, плаща се на токени/заявки).
  • Локален/само-хостван embedding модел (по-ниска маргинална цена при голям обем, но изисква GPU/ops).

Как да избереш:

  • Ако данните са чувствителни: прецени дали имаш право да ги изпращаш към външен доставчик.
  • Ако обемът е малък: API често е най-евтиният път към резултат.
  • Ако обемът е голям и постоянен: локалният модел може да намали разходите, но увеличава инженерната сложност.

Стъпка 6: Ingest: запиши embeddings и метаданни

Минималният pipeline изглежда така:

  1. Зареждаш документ.
  2. Разделяш на chunk-ове.
  3. За всеки chunk генерираш embedding.
  4. INSERT в таблицата.

Псевдо-Python (идеята, не библиотеките):

chunks = chunk_text(text)
rows = []
for i, chunk in enumerate(chunks):
    emb = embed(chunk)  # връща list[float] с фиксирана дължина
    rows.append((doc_id, source, i, chunk, metadata, emb))

# после batch insert

Практически съвети:

  • Прави batch insert-и (примерно 100–1000 реда), вместо по един.
  • Записвай doc_id и версия на документа, за да можеш да обновяваш.
  • Ако документ се промени, изтрий старите chunk-ове за doc_id и вкарай новите (или поддържай version).

Стъпка 7: Търси, филтрирай и измервай качество

1) Семантично търсене

В Postgres с pgvector често ще правиш заявки тип:

SELECT id, doc_id, chunk_index, content, metadata,
       1 - (embedding <=> $1) AS score
FROM doc_chunks
WHERE metadata @> '{"language":"bg"}'
ORDER BY embedding <=> $1
LIMIT 10;

Тук $1 е query embedding.

2) Добави филтри

С филтри можеш да намалиш „шум“ и да подобриш precision. Пример: по клиент, дата, тип документ.

3) Въведи втори етап: reranking (по желание)

Vector търсенето е първи етап (retrieval). Ако искаш по-точни резултати, добави втори етап:

  • взимаш top 20–50 chunk-а;
  • прилагаш по-„умен“ модел/правила за да подредиш отново (rerank);
  • подаваш на LLM само най-добрите 3–8.

Това често подобрява качеството повече от „още индекси“.

Настройки за скалиране и производителност (когато натоварването расте)

Когато започнеш да имаш хиляди заявки на ден или милиони chunk-ове, дребните решения стават важни:

  • Измервай latency по етапи: embedding на заявката, vector search, rerank, LLM отговор.
  • Използвай кеширане за популярни заявки (дори само кеш на query embedding-ите може да свали разход и време).
  • Пази размерите под контрол: embedding-ите са „широки“ данни; метаданните също могат да надуят storage.
  • Не увеличавай top_k без причина: често k=5..20 е достатъчно, ако chunking-ът и метаданните са добри.
  • Планирай re-embed: смяна на embedding модел почти винаги означава преизчисляване на всички вектори; това е проект сам по себе си.

Сигурност, права и съответствие (лесно се пропуска)

Vector DB често държи „извадка“ от фирмено знание. Ако работиш с клиентски или вътрешни данни:

  • прилагай филтри по customer_id/права на ниво заявка, не само в приложението;
  • внимавай с PII: понякога е по-добре да mask-неш или да не индексираш чувствителни полета;
  • дефинирай retention: кога триеш данни и как доказваш, че са изтрити;
  • логовете са данни: ако логваш заявки и пасажи, третирай ги като чувствителни.

Семантичното търсене без контрол на достъп е риск за изтичане на информация, дори когато „нямаш директни линкове“.

Архитектура за продукция: минимален чеклист

Когато MVP тръгне, добави тези 6 елемента:

  1. Версиониране на данните (документ/източник/дата).
  2. Контрол на достъп: филтри по клиент/права, за да няма data leak.
  3. Наблюдение: latency, грешки, rate limiting, размер на индекса.
  4. Оценка: recall@k, human spot-check, „лоши“ заявки.
  5. Backup и възстановяване: особено ако embedding-ите са скъпи за пресмятане.
  6. План за миграция: ако смениш embedding модел, ще преизчисляваш (re-embed) и ще имаш период на „двойно“ поддържане.

Съвети за по-добри резултати

  • Започни с ясна цел: „намирам най-добрите 5 пасажа за отговор“, не „правя AI“.
  • Дръж метаданните чисти и консистентни; филтрите са половината качество.
  • Ако резултатите са близки, добави reranking (втори етап) преди да покажеш на потребителя.
  • Логвай заявки и кликове (implicit feedback) и обновявай evaluation set-а.
  • Помисли за hybrid search (BM25 + vector), ако имаш много термини/номера/кодове.

Чести грешки, които да избягваш

  • Да индексираш всичко, без да знаеш какво ще търсиш.
  • Да правиш огромни chunk-ове (целият документ) или микроскопични (по 1 изречение) без причина.
  • Да смесваш езици и домейни в един индекс без метаданни и филтри.
  • Да пускаш в продукция без метрики (поне recall@k и latency).
  • Да пренебрегнеш правата за достъп и да „смесиш“ клиентски данни в еднакъв retrieval.

Често задавани въпроси

1) Трябва ли ми отделна vector DB или стига Postgres?

Ако правиш MVP, имаш умерен обем и искаш SQL + права + транзакции, Postgres + pgvector често е достатъчен. При много големи обеми или специфични SLA изисквания, управляваните vector услуги могат да са по-подходящи.

2) Колко „скъпо“ е да съхранявам embeddings?

Цената идва от три места: генериране на embeddings (ако е платен API), съхранение (disk) и заявки/compute. Управляваните услуги често имат минимум или pay-as-you-go модели, а при Postgres плащаш compute/disk според хостинга.

3) Какъв размер chunk да избера?

Започни с 300–800 думи и 10–20% overlap, после измери recall@k на реални въпроси. Няма универсално число, но има универсален тест: работи ли за твоите случаи.

4) Как да обновявам данните без хаос?

Въведи doc_id + version (или checksum). При промяна: изтрий старите chunk-ове за документа и вкарай новите, или маркирай версията и филтрирай по „активна“.

5) Как да разбера дали ми трябва специализирана услуга като Pinecone/Weaviate/Qdrant?

Когато имаш ясни метрики и виждаш ограничения: latency при голям k, сложни SLA изисквания, HA/многорегионност, или оперативна тежест. Тогава сравни актуалните планове и модели за таксуване на страниците им (проверено към 10 февруари 2026).

Източници (проверено към 10 февруари 2026)