Перейти до змісту

Full-text пошук

BamDude індексує фіксований набір полів архівної метадати у full-text-структуру: SQLite-інстали отримують FTS5 virtual-таблицю (archive_fts), PostgreSQL-інстали — tsvector-колонку з GIN-індексом. Обидва бекенди обслуговують той самий GET /api/v1/archives/search?q=... endpoint. Пошук вмикається автоматично міграцією m001; ручної настройки не треба.

Що індексується

Індекс покриває шість колонок print_archives:

Поле Що туди йде
print_name Print name з 3MF або відредагований override від користувача.
filename Оригінальний 3MF filename.
tags Користувацькі теги (comma-separated string).
notes Free-form notes, прикріплені до архіву.
designer Author / designer string з 3MF metadata.
filament_type Material code (PLA, PETG, ABS, ...).

Все. AMS color names, printer name, project name, plate-level metadata, library files не в індексі — див. Обмеження нижче.

Два бекенди, один endpoint

На SQLite пошук виконує archive_fts MATCH :term. На PostgreSQL — search_vector @@ to_tsquery('simple', :term) з ts_rank ordering. Route автодетектить діалект через is_postgres(). Якщо FTS сам падає (corrupt index, malformed query, який parser відкидає), route тихо фолбекається на повільніший LIKE scan по тих самих колонках, тож пошук ніколи не дає 500 — просто повільніше.

Тригер пошуку

Search-box живе в Archives toolbar. Frontend синхронізує URL query, тож результати пошуку shareable / bookmarkable.

Глобального / keyboard shortcut для archive-пошуку поки немає — / shortcut підвʼязаний лише до spool-list search-box на сторінці Inventory. На Archives використовуй click-and-type у хедері сторінки.

Синтаксис

Поведінка route залежить від того, який DB-бекенд у тебе, але в обох однаковий observable feel для типових кейсів:

Шаблон Що робить Бекенд-замітки
vase Plain word match. SQLite автододає *, тож еквівалент vase*. PostgreSQL токенізує в vase:*. У будь-якому разі prefix matching — default.
vase* Explicit prefix. Матчить vase, vasely, vases. SQLite: handled natively. PostgreSQL: токенізується так само як vase.
"calibration cube" Phrase match. Обидва слова мусять зʼявитися сусідньо і в порядку. FTS5 підтримує phrase queries прямо.
vase OR cup Будь-яке слово. FTS5 підтримує OR; PostgreSQL tsquery трактує пробіл як &, тож на PG-інсталі вживай помірковано.
phone -case Виключити слово. Матчить архіви, де згадується phone, але не case. FTS5 native.

На PostgreSQL роби queries простими

На PG route ділить твій query за whitespace і джойнить через & (AND), потім додає :* до кожного слова для prefix matching (напр. vase calibration → vase:* & calibration:*). Boolean OR і exclusion (-) не претранслюються в tsquery syntax — вони матчатимуть літерально як частину слова. Якщо query фолбекається на LIKE — отримаєш partial-substring matching по всіх шести колонках, що permissive-ніше, але повільніше.

Ranking і форма результатів

Бекенд Ranking
SQLite (FTS5) ORDER BY rank — built-in BM25-style ranking FTS5.
PostgreSQL ORDER BY ts_rank(search_vector, query) DESC. Per-field ваги: print_name = A, filename = B, tags = B, designer = C, filament_type = C, notes = D. Тож хіт у print name виграє хіт у notes.

Trashed архіви (deleted_at IS NOT NULL) фільтруються після FTS-lookup. Тобто trashed-рядки все ще займають слоти в LIMIT 50-вікні; якщо query повертає 0 результатів, але ти впевнений, що щось матчить — restore з Library Trash (або archive-еквівалентa — та сама deleted_at колонка на archives).

Комбінування з фільтрами

Окрім free-form q, search endpoint приймає:

Param Призначення
printer_id Обмежити одним принтером.
project_id Обмежити одним project-ом.
status completed / failed / printing.
limit Default 50, max enforce-ється upstream.
offset Пагінація.

Filter chips на Archives-сторінці також fee-дять регулярний GET /api/v1/archives/?search=... listing endpoint, який використовує той самий FTS-шлях внутрішньо.

Manual index rebuild

Тригери, що підтримують archive_fts (SQLite), і BEFORE INSERT/UPDATE trigger (PostgreSQL) тримають індекс синхронізованим автоматично — кожен insert, update, delete на print_archives propagate-иться. Ребілдити майже ніколи не доводиться.

Коли ребілдити:

  • Після failure-нутої schema-міграції, що зачепила print_archives.
  • Після імпорту архівів через прямий SQL (минути ORM — означає, що тригери можуть фаєрити нерелайно залежно від driver).
  • Якщо search явно повертає неправильні результати, що не відображають поточний стан рядків.

Як ребілдити:

POST /api/v1/archives/search/rebuild-index

Permission: archives:update_all. Повертає {"message": "Search index rebuilt with N entries"}.

На SQLite це чистить archive_fts і re-INSERT-ить кожен рядок з print_archives. На PostgreSQL виконує UPDATE print_archives SET print_name = print_name, що фаєрить BEFORE INSERT/UPDATE trigger на кожен рядок і ребілдить search_vector in place.

Локає archives-таблицю на короткий час

На 100k-archive install rebuild займає кілька секунд і тримає lock на print_archives. Не ребілдь під час printing-burst.

Обмеження

Що НЕ searchable Чому
Library files Library використовує окремий ORM-level filter, без FTS index. Library list endpoint-и приймають search param, але це LIKE по filename/folder.
Projects Те саме — listed через project list endpoint, без full-text index.
Settings, users, permission-и Не індексуються — by design, щоб secret-и не потрапляли в FTS dump-и.
AMS color names Кольори живуть у color_catalog таблиці і джойняться під час render-у; вони не денормалізовані на print_archives.
Printer names Та сама причина — printer name це джойн, не колонка на print_archives. Фільтруй через printer_id.
Plate-level metadata Зберігається як JSON всередині print_archives.extra_data; FTS5/tsvector не індексують nested JSON.

Якщо треба фільтрувати по чомусь, чого нема в FTS-індексі — комбінуй search з printer_id / project_id / status query-параметрами, або використовуй регулярний Archives list endpoint з його filter chips.

Permission-и

Дія Permission
Search archives archives:read
Rebuild index archives:update_all

API reference

GET /api/v1/archives/search?q=benchy
GET /api/v1/archives/search?q=benchy&printer_id=2&status=completed
POST /api/v1/archives/search/rebuild-index

List endpoint (GET /api/v1/archives/?search=...) приймає той самий search term і ходить через той самий FTS-шлях внутрішньо, тож будь-який syntax, що працює на /search, працює і на listing.