架構
了解 KuraDB 如何分離生命週期管理、唯讀查詢、索引寫入、持久儲存與可重建快取。
系統概覽
graph TB
CLI["kura CLI"] --> Registry["Registry<br/>db.json"]
CLI --> Daemon["背景 daemon"]
Daemon --> API["Gin 唯讀 API"]
Daemon --> Watcher["檔案系統 watcher"]
Watcher --> Parser["文件 parser"]
Parser --> PerDB["每個資料庫的 SQLite<br/>file_data"]
PerDB --> Embedder["Embedding scheduler"]
Embedder --> OpenAI["OpenAI embeddings"]
Embedder --> Vector["記憶體內 vector cache"]
API --> Keyword["關鍵字搜尋"]
API --> Semantic["語意搜尋"]
Keyword --> PerDB
Semantic --> QueryCache["記憶體 + 全域 SQLite<br/>query_cache"]
Semantic --> Vector
Vector --> PerDB
Registry --> Daemon
執行期組成
| 層級 | 主要程式碼 | 職責 |
|---|---|---|
| 入口與生命週期 | cmd/app |
分派 CLI 命令、daemonize、初始化子系統、處理關閉 |
| HTTP API | internal/api |
暴露本機唯讀 route,並驗證資料庫選擇 |
| 持久化 | internal/database |
開啟 SQLite store、維護 registry,並執行所有內容寫入 |
| 檔案匯入 | internal/filesystem |
輪詢 inbox、偵測變更、解析支援檔案、dismiss 已移除項目 |
| Embedding | internal/openai |
讀取憑證、呼叫 OpenAI、編碼向量、快取 query embedding |
| 向量檢索 | internal/vector |
維護可重建 bucket,並執行兩階段 cosine 搜尋 |
| Tokenization | internal/utils/segmenter |
使用 gse 對關鍵字查詢斷詞及去重 |
| 程序狀態 | internal/runtime |
寫入 PID metadata、檢查存活狀態、停止 daemon |
啟動順序
runServer 使用 --daemon 啟動目前執行檔,將輸出導向 daemon.log,並等待 endpoint 檔案。runServerDaemon 接著依權威順序初始化:
- 建立或更新
runtime.uid。 - 初始化 KuraDB keychain context。
- 載入 database registry。
- 建立 OpenAI embedder。
- 開啟
global.db,並預載符合預期維度的 query embedding。 - 初始化 tokenizer 與 process-wide vector cache。
- 開啟每個已註冊資料庫的 SQLite 檔案。
- 從已 embedding 且未 dismiss 的 row 重建各 vector bucket。
- 為每個已載入資料庫啟動一個 watcher 與一個 embedding scheduler。
- 啟動本機 HTTP server,等待
SIGINT或SIGTERM。
儲存拓撲
KuraDB 在 ~/.config/kuradb/ 下使用多個本機狀態檔案:
| Store | 權威性 | 內容 |
|---|---|---|
db.json |
持久 registry | 資料庫名稱與建立時間 |
config.json |
持久設定 | 可選的固定 HTTP port |
global.db |
持久快取 store | Query 文字與 embedding blob |
{db}/data.db |
Source of truth | 解析後 chunk、soft-delete 狀態與 embedding |
{db}/record.json |
Watcher snapshot | 檔案大小、mtime、類型與 child snapshot |
runtime.uid |
暫時程序狀態 | UID、PID 與啟動時間 |
endpoint |
暫時服務發現 | 目前本機 HTTP base URL |
daemon.log |
操作日誌 | Daemon stdout 與 stderr |
vector.Cache 與 openai.Cache 是加速器,不是權威 store;兩者都必須可由 SQLite 重建。
並行模型
每個已載入資料庫都擁有獨立的 watcher 與 embedder goroutine。當 /api/search 未指定 target 時,HTTP keyword 與 semantic branch 會並行執行。SQLite 透過 go-sqlkit 提供八條 read connection 與獨立 write connection。Vector cache map 使用 process、database bucket 與 query-cache mutex 隔離並行存取。
信任邊界與不變條件
- HTTP surface 只包含 GET query route;不得以 mutation endpoint 繞過 ingestion。
- 內容寫入必須經過 watcher → parser →
databaseHandler.Upsert→ SQLite。 - Keyword 與 semantic read 必須排除
dismiss = TRUE的 row。 - 所有載入的 embedding blob 都必須符合 process-wide
openai.Dim()預期。 - API response 會暴露 source、chunk 與 content,但不暴露內部 ID、score、hit count 或 total。
- 圖片及其他被略過的 binary format 不會進入文字 embedding pipeline。
- 新註冊的資料庫只能在重新啟動後使用。
關閉流程
終止 signal 會取消共用 context。HTTP server 會移除 endpoint,並執行五秒的 graceful shutdown。Watcher 與 embedder 會離開 select loop,runtime.uid 會被清除,最後關閉所有 per-database 與 global SQLite connector。