文件

搜尋與檢索

了解 KuraDB 如何準備 query、執行 keyword 與 semantic retrieval,並建立安全的 API result。

Strategy 選擇

GET /api/search 接受可選的 target parameter:

target 執行工作 Response key
省略或空值 並行執行 keyword 與 semantic branch keyword, semantic
keyword 只執行 keyword branch keyword
semantic 只執行 semantic branch semantic

兩個 branch 使用相同的 loaded database 與 request context。若任何已選 branch 回傳 error,handler 會回傳 HTTP 500,而不是 partial data。

Keyword retrieval

Keyword branch 會呼叫 segmenter.Tokenize,其流程如下:

  1. Trim 完整 query。
  2. 使用內嵌的 gse zh_s dictionary 與 stop-word data。
  3. 執行 search-mode segmentation。
  4. Trim token、轉為 lowercase、移除空值,並依遇到順序去重。

SearchKeyword 會為每個 token 建立 case-insensitive SQLite LIKE predicate。Row 必須符合 dismiss = FALSE,並至少命中一個 token。

Ranking 具確定性:

  1. 依 matched-token count 降冪。
  2. 依 row ID 升冪。
  3. 套用 request limit,預設 10。

Semantic query embedding

Semantic branch 先使用完整 query string 查詢 openai.Cache。Cache miss 時,會向 OpenAI 傳送單項 batch。成功的 vector 會存入記憶體,並透過 cache 的 OnSet callback 非同步持久化至 global.db

啟動時只預載 byte length 等於 openai.Dim() * 4 的 query-cache blob。Preload 會繞過 OnSet,因此不會重寫同一 entry。

每個 database bucket 都儲存 chunk vector,以及每個 source 的一個 derived vector。

階段一:Source candidate

KuraDB 會計算 query 與每個同維度 source vector 的 cosine similarity。Candidate 數量為:

min(max(number of sources / 20, 20), number of sources)

大型 source set 約保留 5%;若數量足夠,至少保留 20 個。

階段二:Chunk ranking

KuraDB 收集 candidate source 的 chunk ID,再為每個 chunk 計算同維度 cosine similarity。工作最多拆分至 CPU count - 1 個 worker,每個 worker 目標至少 200 chunks。Hit 依 score 降冪排序,再截斷為 topK

若沒有 source vector,search 會 fallback 為直接排序所有 chunk vector。

Score 過濾與 hydration

API layer 會移除 score 低於 0.3 的 semantic hit,接著以 dismiss = FALSE 從 SQLite 取得其餘 ID、恢復 vector ranking order,並丟棄已無法解析為 active row 的 ID。

即使記憶體 state 同時發生變更,此 final hydration 仍維持 SQLite 的權威性。

分組

兩個 flat result set 都依首次出現的 source 分組。External representation 為:

[
  {
    "source": "/path/to/document.md",
    "matches": [
      {"chunk": 1, "content": "..."},
      {"chunk": 2, "content": "..."}
    ]
  }
]

已選 branch 無結果時表示為 []

私有 ranking data

Handler 在 serialization 前會刻意移除內部 field:

內部 field 保持私有的原因
Row ID Storage implementation detail
Semantic score Threshold 與 ranking 可能調整
Keyword hit count 內部 ranking signal
Chunk total 不屬於 consumer contract
Overall total API 不提供 pagination metadata

Consumer 應只依賴 sourcematcheschunkcontent

一致性行為

EN