core: гибридный поиск (BM25 + вектор + RRF)
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
Проект: /root/WORK/memo (Kotlin/JVM). Заказ по слежению за файлами.
|
||||
|
||||
Создать РОВНО ДВА новых файла:
|
||||
memo-watch/build.gradle.kts (плагин kotlin("jvm") + зависимость на :memo-core)
|
||||
memo-watch/src/main/kotlin/memo/watch/Watcher.kt
|
||||
memo-watch/src/main/kotlin/memo/watch/WatchMain.kt
|
||||
и ОДИН тестовый:
|
||||
memo-watch/src/test/kotlin/memo/watch/WatcherTest.kt
|
||||
|
||||
## Watcher.kt
|
||||
|
||||
package memo.watch
|
||||
|
||||
class Watcher(
|
||||
private val collections: List<java.io.File>, // каталоги-коллекции
|
||||
private val index: (java.io.File) -> Unit, // функция индексации одной коллекции
|
||||
private val debounceMillis: Long = 500,
|
||||
private val reconcileMillis: Long = 10 * 60 * 1000,
|
||||
) : AutoCloseable {
|
||||
|
||||
/** Запускает фоновый поток: WatchService на каждый каталог рекурсивно,
|
||||
* debounce, плюс периодическая полная реконсиляция по mtime. */
|
||||
fun start()
|
||||
|
||||
/** Останавливает поток, закрывает WatchService. Идемпотентно. */
|
||||
override fun close()
|
||||
|
||||
/** Количество выполненных вызовов index(...) — для тестов. */
|
||||
val indexCalls: Int
|
||||
}
|
||||
|
||||
Требования:
|
||||
1. Регистрировать каждый каталог через FileSystems.getDefault().newWatchService() с ENTRY_CREATE,
|
||||
ENTRY_MODIFY, ENTRY_DELETE и при регистрации рекурсивно обойти подкаталоги (WatchService не рекурсивен).
|
||||
Каталоги, начинающиеся с '.', не обходить и не регистрировать.
|
||||
2. События собирать в Set<File> (какие коллекции затронуты). Поток: take() с таймаутом debounceMillis;
|
||||
при накоплении — по истечении debounce вызвать index(коллекция) для каждой затронутой коллекции.
|
||||
Не вызывать index десятки раз на одно сохранение файла.
|
||||
3. Раз в reconcileMillis — полная реконсиляция: обойти все файлы *.md во всех коллекциях,
|
||||
сравнить (path, mtime, size) со таблицей files, при расхождении вызвать index(коллекция).
|
||||
Реализацию сравнения НЕ дублировать: у :memo-core уже есть Indexer.indexFile, который сам
|
||||
пропускает неизменённые файлы и возвращает Boolean. Использовать его: index(коллекция) должен
|
||||
внутри вызывать Indexer.indexTree(коллекция).
|
||||
4. Все исключения в рабочем потоке не должны убивать поток: ловить, печатать в stderr, продолжать.
|
||||
5. close(): interrupt + закрыть WatchService, поток завершается не дольше 2 секунд.
|
||||
|
||||
## WatchMain.kt
|
||||
|
||||
fun main(args: Array<String>)
|
||||
- Аргумент: корень, содержащий коллекции (или одну коллекцию).
|
||||
- Определение коллекций — как в CLI (каталог с *.md на глубине до 2).
|
||||
- Создаёт Db(коллекция/.memo/index.db), .init(), Indexer(db, embedder) — по одному на коллекцию,
|
||||
Watcher с index = { коллекция -> indexer.indexTree(коллекция) }.
|
||||
- Печатает `наблюдаю: <коллекция>` по строке на каждую, затем блокируется навсегда до SIGINT.
|
||||
- Модель: MEMO_MODEL_DIR, иначе /root/WORK/memo/models/siglip2.
|
||||
|
||||
## WatcherTest.kt — ровно 3 теста, имена ровно такие
|
||||
|
||||
1. `modifyTriggersSingleIndexCall` — временный каталог с note.md; Watcher с index-счётчиком и
|
||||
debounce 200 мс; start(); правка файла; подождать 1.5 с; indexCalls == 1 (не больше!);
|
||||
close(). (Перед стартом дать watcher 300 мс прогреться.)
|
||||
2. `unchangedFileDoesNotTriggerIndex` — после прогрева ничего не менять 1.5 с → indexCalls == 0.
|
||||
3. `closeIsIdempotentAndStopsThread` — start(); close(); close(); повторный вызов не бросает исключение.
|
||||
|
||||
Тесты должны быть устойчивыми: ждать не фиксированным sleep, а опросом условия с таймаутом
|
||||
(например, до 5 с с шагом 100 мс), чтобы не флапать на медленной машине.
|
||||
|
||||
После: ./gradlew :memo-watch:test --rerun-tasks — зелёные; ./gradlew build -x test компилируется.
|
||||
Коммит: git add -A && git commit -m "watch: слежение за файлами (WatchService + debounce + реконсиляция)"
|
||||
|
||||
СТРОГИЕ ЗАПРЕТЫ:
|
||||
- Не выводить план текстом; сразу создавай файлы.
|
||||
- Не трогать memo-core и memo-cli.
|
||||
- Не добавлять зависимости, кроме :memo-core.
|
||||
Reference in New Issue
Block a user