向量搜尋
為 entry 附加 OpenAI embedding、重用內部 embedding cache,並依餘弦相似度排序儲存鍵值。
前置需求
向量操作需要 OPENAI_API_KEY。store.New 成功建立 OpenAI client 時會初始化 embedder;否則一般儲存功能仍可用,而向量操作會回傳設定錯誤。
| 設定 | 值 |
|---|---|
| Model | text-embedding-3-small |
| 預設 dimension | 256 |
| Dimension override | TORIIDB_EMBED_DIM |
| HTTP endpoint | https://api.openai.com/v1/embeddings |
附加向量
在頂層 SET 加上 VECTOR:
SET article:1 Redis-style embedded storage VECTOR
SET article:2 JSON document database VECTOR
SetVector 會先執行一般 Set,因此 value 立即可用;接著啟動背景工作:
- 檢查內部 embedding cache。
- Cache miss 時在不持有資料庫鎖的情況下呼叫 OpenAI。
- 將具決定性的 embedding 寫入 cache。
- 只有 entry 仍存在且 value 仍等於嵌入文字時才附加 vector。
- 更新 entry file,並寫出含 encoded vector 的 AOF
SET記錄。
Close 會先等待這些工作完成,再壓縮資料庫。之後的一般 SET 會清除 vector。
Embedding 快取
Cache key 使用以下保留格式:
__torii:embed:<sha256(model|dimension|text)>
Payload 會記錄 base64 little-endian float32 vector、dimension 與 model。因為相同 model、dimension、text 的 embedding 被視為 deterministic,cache entry 不設定 TTL。
掃描型操作會隱藏 __torii:* key;點查詢仍可用於除錯。
語意搜尋
VSEARCH embedded database
VSEARCH embedded database MATCH article:* LIMIT 5
VSEARCH embedded database LIMIT 5 MATCH article:*
MATCH 與 LIMIT 可用任一順序放在尾端。未提供正數 limit 時,VSearch 使用 10。
Query text 除非已快取,否則會同步產生 embedding。搜尋在讀鎖下掃描目前資料庫,並略過:
- 保留的 internal key。
- 已過期 entry。
- 沒有 vector 的 entry。
- Vector length 與 query vector 不同的 entry。
- 不符合選用 Go
path.Matchpattern 的 key。 - 無法定義 cosine similarity 的 zero vector。
Min-heap 會保留前 k 個 candidate,結果依相似度遞減回傳。
相似度與向量讀取
VSIM article:1 article:2
VGET article:1
VSIM 計算兩個 stored vector 的 cosine similarity。任一 key 或 vector 不存在時回傳 (nil);dimension 不同時回報錯誤。
VGET 回傳 JSON float array。Go API 會回傳 defensive copy,呼叫端無法修改 entry 中儲存的 vector。
一致性注意事項
- Vector attachment 為非同步;
SET ... VECTOR成功後可能不會立即可搜尋。 - Embedding 完成前若 value 已改變,舊結果會被丟棄。
- 背景 embedding 失敗不會移除已儲存的文字。
- 搜尋只比較 dimension 完全一致的 vector。
- Query embedding request 為同步,可能回傳網路或 API 錯誤。
Go API 範例
ctx := context.Background()
if err := db.SetVector(ctx, "article:1", "embedded JSON database", store.SetDefault, nil); err != nil {
log.Fatal(err)
}
keys, err := db.VSearch(ctx, "local semantic storage", "article:*", 5)
if err != nil {
log.Fatal(err)
}
fmt.Println(keys)