mirror of
https://gitverse.ru/kpa39l/email-local-archive.git
synced 2026-09-29 09:15:11 +00:00
5.7 KiB
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 по UIDidx_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/из сканирования.