Векторні бази даних
Векторна база відповідає на питання «що найбільш схоже на це» серед мільйонів обʼєктів за мілісекунди — і робить це, не дивлячись на більшість із них. У цьому й уся угода: кожна відповідь наближена, а наскільки саме — це число, яке ви задаєте, а не властивість продукту. На цій сторінці — що насправді зберігається, родини індексів і чого кожна коштує в памʼяті, чому фільтрація за метаданими складніша, ніж здається, що роблять з індексом видалення й переобчислення ембедингів, і коли колонка в базі, яку ви вже тримаєте, є кращою відповіддю.
- Кожна відповідь
- Наближена
- Повнота — це
- Налаштування
- Обмежує зазвичай
- Памʼять, не CPU
Угода, яку ви насправді укладаєте
Модель ембедингів перетворює шматок тексту, зображення чи товар на список чисел — зазвичай від кількох сотень до кількох тисяч — розміщених так, що речі, які людина назвала б схожими, опиняються поруч. Щойно зміст стає координатами, «знайти повʼязані документи» перетворюється на «знайти найближчі точки» — задачу геометрії з довгою історією й однією незручною властивістю: розвʼязати її точно означає виміряти відстань до кожної наявної точки. На десяти тисячах обʼєктів це миттєво. На пʼятдесяти мільйонах це вже не запит, а пакетна задача.
Тому кожна векторна база на масштабі відмовляється від точності. Вона будує індекс, що дозволяє пошуку відвідати кількасот перспективних кандидатів замість пʼятдесяти мільйонів, і мириться з тим, що справді ближчий обʼєкт іноді лишається невідвіданим. Частку справжніх найближчих сусідів, яку пошук насправді повертає, називають повнотою (recall), і найважливіше, що варто зрозуміти про ці системи: повнота — це регулятор. Підкрутіть його вгору — і ви відвідуєте більше кандидатів за більшу затримку й більше CPU; вниз — і дістаєте швидку відповідь, яка тихо щось пропускає.
Одна деталь підводить людей раніше, ніж усе решта починає важити: метрика відстані має бути тією, під яку тренували модель ембедингів. Косинусна подібність порівнює напрямок і ігнорує довжину; скалярний добуток винагороджує і довші вектори, і співнапрямлені; евклідова відстань міряє пряму лінію між точками. Візьміть скалярний добуток на векторах, які модель очікує нормалізованими, — і популярні обʼєкти домінуватимуть у кожному результаті з причин, що не мають стосунку до релевантності. Дивіться картку моделі, беріть названу нею метрику й нормалізуйте, якщо вона так каже.
Родини індексів — і чого коштує кожна
Кожен продукт на ринку реалізує якусь підмножину чотирьох ідей, зазвичай під власними назвами. Знати ідеї, а не бренди, — саме це дозволяє чесно читати бенчмарк, бо бенчмарк, що порівнює два продукти, майже завжди порівнює дві конфігурації індексу.
Flat — без індексу
Порівняти з усім. 100% повноти, лінійна вартість, без побудови й без параметрів. Правильний вибір до кількох сотень тисяч векторів — і базовий рівень, проти якого міряють решту індексів.
IVF — інвертовані списки
Один раз кластеризувати простір, потім шукати лише в кількох найближчих кластерах. Регулятор —
nprobe. Дешевий у побудові й у памʼяті, псується, коли дані відходять від кластеризації, на якій його збудовано.HNSW — навігований граф
Шари звʼязків: розріджені згори для довгих стрибків і щільні знизу для точності. Найкраща повнота на мілісекунду в загальному вжитку й типовий вибір майже всюди. Регулятор —
efSearch; сам граф коштує відчутної памʼяті понад вектори.Квантизація — PQ та інші
Не структура пошуку, а стиснення: зберігати наближення кожного вектора, часто у 4–32 рази менше. Кладеться під IVF чи HNSW, коли памʼять є звʼязувальним обмеженням, — ціною ще трохи повноти.
Арифметику памʼяті варто зробити на папері до того, як щось обирати, бо саме вона зазвичай вирішує. Вектор на 1536 вимірів у 32-бітних числах — це 6144 байти. Мільйон таких — близько 6 ГБ самих лише векторів, а граф HNSW над ними додає ще приблизно 20–40% на звʼязки, тобто 8 ГБ до корисного навантаження, реплік і запасу. Десять мільйонів — це машина, що коштує справжніх грошей щомісяця. Два рухи різко це зменшують: узяти модель ембедингів із меншою розмірністю, якщо на ваших даних вона працює порівнянно, і зберігати вектори як 8-бітні цілі там, де втрата повноти прийнятна, — це рівно вчетверо менше.
Фільтрація — там, де індекс воює з вами
Майже кожен реальний запит має причеплену умову: лише цей робочий простір, лише опубліковані документи, лише в наявності, лише цією мовою, не видалені. У реляційній базі це нічим не примітно. Тут це найскладніше на сторінці, бо індекс збудовано над геометрією всієї колекції й він нічого не знає про вашу умову. Є три способи їх помирити, і кожен ламається по-своєму.
| Підхід | Як працює | Де ламається |
|---|---|---|
| Пост-фільтр | Знайти в індексі k кандидатів, потім відкинути ті, що не проходять умову. | Вибіркова умова спорожняє результат. Просите 10, підходить 2% — дістаєте 0: класичний баг «пошук нічого не повертає». |
| Пре-фільтр | Спершу розвʼязати умову, потім шукати лише в множині, що підійшла. | Якщо множина велика, це майже повний перебір, і індекс перестає окупатися. |
| Фільтрований пошук | Умова обчислюється під час обходу графа, тож обхід рухається лише дозволеними вузлами. | Найкраща відповідь і те, що роблять добрі рушії, — але зі зростанням вибірковості фільтра повнота тихо падає. |
Практичне правило — робити межі з високою вибірковістю структурними, а не фільтром. Якщо кожен запит обмежений одним тенантом, робочим простором чи мовою, дайте кожному власну колекцію або партицію — і проблема зникає: ви шукаєте в малому індексі, а не фільтруєте великий. Лишайте фільтри для умов, що справді змінюються від запиту до запиту, а будь-який фільтр, що вибирає менше кількох відсотків колекції, вважайте сигналом, що дані від початку варто було розділити.
Записи, видалення й міграція, яку ніхто не планує
Векторні індекси збудовані для читання. Графовий індекс може приймати вставки під час обслуговування, але кожна вставка додає звʼязки до наявної структури, і граф, який увібрав мільйони вставок, вимірювано гірший за ті самі дані, проіндексовані з нуля, — повнота повзе вниз без жодної помилки. З видаленнями гірше: більшість рушіїв позначає запис як вилучений замість того, щоб полагодити граф, тож видалений вектор і далі займає памʼять і далі обходиться, а колекція з великим оборотом поволі наповнюється надгробками. І те, і те лікується періодичною перебудовою — експлуатаційною задачею, яку хтось має мати за свою й планувати.
- Наповнюйте пакетно, а не по одному вставленню: побудувати індекс один раз над усім набором і швидше, і краще звʼязано.
- Вважайте видалення запитом, який буде вшанований у результатах негайно, а в памʼяті — пізніше, і перевірте, що саме гарантує ваш рушій.
- Плануйте перебудови за оборотом, а не за календарем: колекція, де замінено 20% записів, дозріла — байдуже, яке число.
- Тримайте вихідний текст і метадані у своїй основній базі, а векторне сховище — як похідний індекс, який можна знести й відбудувати.
- Зберігайте назву й версію моделі ембедингів на кожному записі, бо одного дня в колекції одночасно опиняться два покоління.
Чи потрібна вам окрема база взагалі
Чесний вибір за замовчуванням для більшості продуктів — розширення в базі, яку ви вже тримаєте. Postgres із pgvector підтримує ті самі родини індексів, дає транзакції, зʼєднання й одну історію бекапів і дозволяє фільтру бути звичайним WHERE, який обчислює планувальник, обізнаний з іншими вашими колонками. Цього перестає вистачати на масштабі, до якого більшість проєктів ніколи не доходить, — приблизно тоді, коли вектори перестають комфортно вміщатися в памʼять поряд із рештою роботи бази або коли потрібен шардований, незалежно масштабований пошук із репліками на колекцію.
Розширення у вашій наявній базі
- Одна система для бекапу, моніторингу, захисту й оплати, а вектори — усередині ваших наявних транзакцій.
- Фільтри — це звичайний SQL по звичайних колонках, із зʼєднаннями до решти ваших даних.
- Немає розриву узгодженості: рядок і його вектор пишуться разом або ніяк.
- Впирається в стелю, коли вектори конкурують за памʼять із рештою навантаження.
Спеціалізована векторна база
- Масштабує шар пошуку окремо: шардування, репліки й тюнінг індексу — керунки першого класу.
- Фільтрований пошук реалізовано всередині обходу, а не прикручено навколо нього.
- Друге сховище, яке треба тримати синхронним, із власними режимами відмов, бекапами й контролем доступу.
- Виправдана приблизно від десяти мільйонів векторів або коли навантаження пошуку має масштабуватися окремо від записів.
І остання річ, що рятує проєкти: векторний пошук не завжди найкращий. Він сильний на перефразуванні й слабкий на точних токенах — артикулах, кодах помилок, іменах, рідкісних абревіатурах, — саме на тих запитах, де користувачі чекають буквального збігу й найменш поблажливі. Поєднання лексичного індексу з векторним і злиття двох списків результатів надійно перемагає кожен окремо — і це часто найдешевше доступне покращення якості. Якщо ваша оцінка показує, що векторний індекс програє звичайному пошуку за ключовими словами на ваших власних запитах, — вірте оцінці. Як проводити цю оцінку, належить сторінці про RAG, що володіє якістю пошуку як вимірюваною властивістю.
Антипатерни, які варто назвати
- Реліз без жодного виміру повноти: ніхто не відрізнить проблему налаштувань від проблеми моделі.
- Пост-фільтр по вибірковій умові — і порожній результат, поданий як «пошук зламався».
- Метрика відстані, що не відповідає моделі ембедингів, — дає правдоподібну на вигляд нісенітницю.
- Векторне сховище як єдина копія тексту: перебудова означає відновлення даних, яких у вас уже немає.
- Окремий кластер заради двохсот тисяч векторів, де колонка в наявній базі була б і швидшою в запитах, і безкоштовною в експлуатації.
- Багатотенантність, забезпечена фільтром, а не межею: одна забута умова — це розкриття даних.
Коли це застосовувати
Застосовуйте, коли
- Пошук за змістом, а не за словами: статті підтримки, документація, каталоги товарів, де користувачі перефразовують.
- Пошук, що живить мовну модель, де кілька найкращих результатів стають контекстом, з якого будується відповідь.
- Рекомендації й дедуплікація за схожістю, де запитом є «щось таке, як оце», і немає ключового слова для збігу.
- Колекції, достатньо великі, щоб точний перебір перестав бути миттєвим, — приблизно понад кількасот тисяч векторів.
Уникайте, коли
- Запити з точними токенами — номери замовлень, артикули, коди помилок, — де лексичний індекс і швидший, і правильний.
- Колекції, достатньо малі для точного перебору: індекс додає параметри, графік перебудов і наближеність — ні за що.
- Як систему обліку. Це похідний індекс; джерело істини належить базі з транзакціями й бекапами.
- До того, як зʼявився спосіб міряти якість пошуку: без нього кожне рішення про налаштування — справа смаку.
Було корисно?
Поділіться з тим, хто працює над тією ж задачею.