Files
memo/docs/orders/03-indexer.md
T

58 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Проект: /root/WORK/memo (Kotlin/JVM). Заказ по индексации markdown-файлов в базу.
Создать РОВНО ОДИН новый файл: memo-core/src/main/kotlin/memo/core/Indexer.kt
Дополнить существующий: memo-core/src/test/kotlin/memo/core/CoreSmokeTest.kt (добавить ОДИН новый тест-метод в конец класса, существующие не трогать)
## Indexer.kt
package memo.core
class Indexer(private val db: Db, private val embedder: Embedder) {
/** Индексирует один файл. Возвращает true, если файл был (пере)проиндексирован,
* false — если пропущен (не изменился с прошлой индексации). */
fun indexFile(path: java.io.File): Boolean
/** Индексирует все .md файлы в дереве каталога root (рекурсивно). Возвращает число
* реально переиндексированных файлов. */
fun indexTree(root: java.io.File): Int
}
Правила:
1. Перед индексацией файла сравнить с записью в таблице files по колонке path:
- если записи нет — индексировать;
- если mtime и size совпадают с сохранёнными — вернуть false, ничего не делать (НЕ считать хэш);
- если mtime/size изменились — посчитать sha-256 содержимого; если хэш совпал с сохранённым —
обновить в files поля mtime/size/indexed_at (файл тронули, содержимое то же) и вернуть false;
- иначе — полная переиндексация файла.
2. Полная переиндексация файла: удалить из chunks все строки с этим path; удалить из chunks_fts строки
с rowid из удалённых chunks (DELETE FROM chunks_fts WHERE rowid IN (...)); то же для chunks_vec.
Затем разбить текст через chunkMarkdown (см. memo-core/src/main/kotlin/memo/core/Chunker.kt),
для каждого чанка: посчитать эмбеддинг embedder.embed(chunk.text), вставить строку в chunks,
взять last_insert_rowid() и вставить те же rowid в chunks_fts (колонки text, heading)
и в chunks_vec (колонка embedding). Всё — в одной транзакции (conn.beginTransaction/commit/rollback).
3. В files писать: path (абсолютный), mtime (доля секунды, REAL), size, hash (hex sha-256), indexed_at (epoch секунды).
4. indexTree: обход рекурсивно, только файлы с расширением .md, скрытые каталоги (начинающиеся с '.')
и каталоги .memo не обходить. Возвращать число переиндексированных файлов.
## Тест: добавить в CoreSmokeTest.kt метод
fun indexerSkipsUnchangedFile()
- создать временный каталог, в нём файл note.md с содержимым "# Заголовок\nтело заметки\n## Второй\nещё текст";
- создать Db на временном index.db (не забыть db.init()) и Embedder на модели
(путь брать так же, как в существующем тесте embedderProduces768 — через MEMO_MODEL_DIR);
- первый indexFile(...) должен вернуть true;
- второй indexFile(...) сразу же — обязан вернуть false (файл не менялся);
- дописать в файл "\n## Третий\nновый текст\n", второй indexFile обязан вернуть true;
- в конце: assertTrue, что SELECT count(*) FROM chunks без условия больше нуля (запрос через db.conn).
После: ./gradlew :memo-core:test --rerun-tasks — все тесты зелёные.
Коммит: git add -A && git commit -m "core: индексатор файлов с пропуском неизменённых"
СТРОГИЕ ЗАПРЕТЫ:
- Не выводить план текстом; сразу создавай/правь файлы.
- Не трогать Chunker.kt, Embedder.kt, Db.kt, build.gradle.kts и любые другие файлы.
- Не менять существующие тесты.
- Не добавлять зависимости.