Files
email-local-archive/references/sqlite-index-architecture.md
2026-09-06 13:51:14 +00:00

5.7 KiB

SQLite-индекс архива писем

Назначение

Быстрый поиск и трекинг по архиву email.md без grep-а по всем папкам. Основа для: contacts_extractor (знает какие письма обработаны), sqlite_search (FTS5), digest (выборка по дате).

Компоненты

Компонент Путь Назначение
Индексатор /opt/hermes/email-assistant/scripts/mail_index.py Сканирует email.md → SQLite
Поиск /opt/hermes/email-assistant/scripts/sqlite_search.py FTS5-поиск по индексу
База /opt/hermes/email/mail_index.db SQLite (WAL mode)

Схема БД

emails — основная таблица

CREATE TABLE IF NOT EXISTS emails (
    path TEXT PRIMARY KEY,              -- относительный путь от EMAIL_ROOT
    uid INTEGER,                        -- числовой UID из пути
    folder TEXT,                        -- INBOX, INBOX/!Scan, Sent...
    date TEXT,                          -- дата из frontmatter (ISO)
    from_addr TEXT,                     -- отправитель
    to_addrs TEXT,                      -- получатели
    subject TEXT,                       -- тема
    body_preview TEXT,                  -- первые 500 символов тела (без HTML)
    contacts_extracted INTEGER DEFAULT 0,  -- 0/1 — обработано contacts_extractor
    contacts_skipped INTEGER DEFAULT 0,    -- 0/1 — нет подписи / LLM error
    first_seen TEXT,                    -- когда проиндексировано
    last_scanned TEXT,                  -- последняя проверка contacts
    file_mtime REAL                     -- mtime файла для инкрементальной проверки
);

email_fts — FTS5 virtual table

CREATE VIRTUAL TABLE IF NOT EXISTS email_fts USING fts5(
    subject, from_addr, to_addrs, body_preview,
    content='emails',
    content_rowid='rowid',
    tokenize='unicode61'
);

Синхронизация через триггеры INSERT/UPDATE/DELETE + FTS5 rebuild.

Индексы

  • idx_emails_folder — быстрая фильтрация по папке
  • idx_emails_uid — lookup по UID
  • idx_emails_contacts — необработанные письма (contacts_extracted=0)
  • idx_emails_date — сортировка по дате

Контракт между mail_index.py и contacts_extractor.py

mail_index.py владеет схемой и создаёт таблицы. contacts_extractor.py — только читает/пишет поля contacts_extracted, contacts_skipped, last_scanned.

-- contacts_extractor берёт необработанные письма:
SELECT rowid, path, uid, folder, from_addr, subject
FROM emails
WHERE contacts_extracted = 0 AND contacts_skipped = 0
ORDER BY folder, uid
LIMIT ?

-- После обработки:
UPDATE emails SET contacts_extracted=1, last_scanned=? WHERE rowid=?
UPDATE emails SET contacts_skipped=1, last_scanned=? WHERE rowid=?

Быстродействие

  • 2073 письма → полная индексация ~9 секунд
  • FTS5-поиск — мгновенно (<100ms)
  • WAL mode — конкурентные чтения не блокируют запись
  • Инкрементальная индексация по mtime — доли секунды

Использование sqlite_search.py

# Простой поиск (AND по умолчанию)
python3 sqlite_search.py 'Стороженко'
python3 sqlite_search.py 'битрикс OR контрагент'
python3 sqlite_search.py '"точечная фраза"'

# Фильтры
python3 sqlite_search.py --folder 'INBOX/!Отчеты'
python3 sqlite_search.py --limit 20

# Специальные префиксы (точно в поле from_addr/subject через LIKE)
python3 sqlite_search.py 'from:example@mail'
python3 sqlite_search.py 'subject:отчёт'

# Вкл. тело письма в FTS5 (медленнее, но находит больше)
python3 sqlite_search.py --body

Операторы FTS5

  • AND — по умолчанию между словами
  • OR — 'битрикс OR контрагент'
  • "точная фраза" — кавычки для точного совпадения
  • -исключить — минус перед словом
  • prefix* — wildcard (звёздочка на конце)

mail_index.py — ключевые параметры

python3 mail_index.py                # полная переиндексация
python3 mail_index.py --incremental  # только новые (по mtime)
python3 mail_index.py --search "..."  # поиск (встроенный, без FTS5)
python3 mail_index.py --stats        # статистика

Важные детали

  • body_preview — только первые 500 символов. Для full-text search с телом используй sqlite_search.py --body (FTS5 на preview).
  • contacts_extracted/contacts_skipped — взаимоисключающие флаги. Если ни один не 1 — письмо не обработано.
  • file_mtime — для инкрементальной индексации. Если mtime файла > last_mtime в БД — переиндексировать.
  • FTS5 rebuild — вызывается после каждой полной индексации для согласованности.
  • Исключает папки contacts/ и state/ из сканирования.