Лого на 91. НЕГ „Проф. Константин Гълъбов“

Избираем модул · Урок 9

Векторна база

Къде живеят векторите: колона в релационната база с pgvector срещу отделна специализирана услуга. Схема, вмъкване и заявка за близост.

Списък в паметта не стига

В 11. клас пазехме векторите в списък. Това работи до няколкостотин парчета и до първото рестартиране. Реалната система иска векторите да са в базата — редом с данните, които описват.

Векторна база

Хранилище, което пази вектори и умее бързо да намира най-близките до зададен вектор.

Двата подхода

Разширение на релационна базаСпециализирана услуга
Примерpgvector в PostgreSQLотделна векторна база
Предимствоедно място за всичко; JOIN между вектори и таблиципо-бърза при десетки милиони вектори
Недостатъкпо-бавна при много голям обемвторо хранилище за поддръжка и синхронизиране
За училищен проектпочти винаги правилният изборизлишно усложнение

Правилото за избора

Започвайте от базата, която вече имате. Отделна векторна услуга се въвежда, когато измерите, че съществуващата не се справя — не предварително.

Схемата

Векторът никога не стои сам. Около него трябват поне: текстът на парчето, връзка към документа-родител, позиция и момент на изчисляване.

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE parcheta (
    id            SERIAL PRIMARY KEY,
    dokument_id   INT NOT NULL REFERENCES dokumenti(id),
    poredno       INT NOT NULL,
    tekst         TEXT NOT NULL,
    model         TEXT NOT NULL,          -- кой модел е правил вектора
    vektor        VECTOR(384),            -- броят измерения е фиксиран
    izchisleno_na TIMESTAMP DEFAULT NOW()
);
  • Броят измерения е част от типа — VECTOR(384). Друг модел с друга дължина изисква друга колона или друга таблица.
  • Името на модела се пази изрично, за да се знае кои вектори са остарели след смяна.
  • Текстът се пази до вектора — при търсене се връща веднага, без второ обръщение.

Заявката за близост

-- <=> е разстояние по косинус в pgvector (по-малко = по-близко)
SELECT p.id, d.zaglavie, p.tekst,
       1 - (p.vektor <=> $1) AS blizost
FROM parcheta p
JOIN dokumenti d ON d.id = p.dokument_id
WHERE p.model = 'multilingual-MiniLM'
ORDER BY p.vektor <=> $1
LIMIT 5;

Филтриране заедно с близост

Тук е основното предимство на подхода „вектори в релационната база“: смисловото търсене се комбинира с обикновени условия в една заявка.

SELECT p.id, p.tekst, 1 - (p.vektor <=> $1) AS blizost
FROM parcheta p
JOIN dokumenti d ON d.id = p.dokument_id
WHERE d.v_sila = TRUE
  AND d.data_na_sila <= CURRENT_DATE
ORDER BY p.vektor <=> $1
LIMIT 5;

С отделна векторна услуга същото изисква две заявки и обединяване в кода — и лесно връща по-малко резултати от очакваното.

Вмъкване

  1. Изчисляваме вектора в приложението (или в задача по разписание).
  2. Вмъкваме заедно с текста, родителя и името на модела.
  3. При обновяване на текста преизчисляваме и обновяваме реда.
  4. При изтриване на документа изтриваме и парчетата — оттам е външният ключ.

Пакетно, не по едно

Изчисляването на вектори е бавно. За хиляда парчета се прави на партиди от по 32–64 и се вмъква с една заявка на партида, а не с хиляда отделни.