Pure-Go vector search — a clean-room, zero-dependency, zero-CGO reimplementation of the
ideas in sqlite-vector. No C extension, no
Elastic License — MIT, so it drops into open or closed products freely and cross-compiles to
arm64 (Rockchip / edge) with GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build.
Built for the ANetOS smart frame's local memory store (see ANetOS Docs/AS015): one
user.db holding prefs + chat + vectors, ≤64 MB with rolling deletion.
- Encodings (wire-compatible blobs, little-endian):
FLOAT32,FLOAT16(IEEE-754 half),BFLOAT16,INT8(per-vector scale),BIT(1 bit/dim). F32/F16/BF16 are byte-identical to sqlite-vector, so embeddings interoperate. - Distances:
L2,SQUARED_L2,COSINE,DOT,L1,HAMMING(for BIT). - Brute-force top-k, no ANN index:
Add/Deletetake effect on the very nextSearch(true rolling-delete semantics — the reason sqlite-vector skips ANN too). - SQLite persistence (optional subpackage
sqlitevec, pure-Gomodernc.org/sqlite): vectors in a BLOB column, index rebuilt on open,PruneToBudgetholds a byte cap.
import vec "github.com/ANetResearch/anet-sqlite-v"
ix, _ := vec.NewFromConfig("dimension=768,type=FLOAT16,distance=COSINE")
ix.Add(1, embedding) // []float32, len 768
ix.Add(2, other)
hits := ix.Search(query, 10) // []Result{RowID, Distance}, nearest first
ix.Delete(1) // reflected on next Search immediatelySingle SQLite file (prefs+chat+vectors), 64 MB rolling:
import "github.com/ANetResearch/anet-sqlite-v/sqlitevec"
s, _ := sqlitevec.Open("user.db", "mem", "dimension=768,type=FLOAT16,distance=COSINE")
s.Add("chat", "we went to the beach with grandma", ts, emb)
hits, _ := s.Search(queryEmb, 8) // []Hit{RowID, Distance, Kind, Text}
s.PruneToBudget(64 << 20) // delete oldest by ts + reclaim, keep ≤64 MB| impl | ms/query | stored |
|---|---|---|
| sqlite-vector (C + AVX2) | 19.3 | 30.7 MB |
| anet-sqlite-v FLOAT32 (pure Go, no SIMD) | 23.0 | 30.7 MB |
| anet-sqlite-v FLOAT16 | 23.0 | 15.4 MB |
| anet-sqlite-v INT8 | 23.0 | 7.7 MB |
| anet-sqlite-v BIT (Hamming) | 1.9 | 1.0 MB |
Pure Go is ~1.2× slower than hand-optimized C+AVX2 — while storing F16/BF16 at half the
bytes and scanning at F32 speed (decoded cache). For the 64 MB / few-thousand-vector edge case
both are sub-5 ms. Run it: go run ./cmd/bench -n 10000.
At 64 MB, FLOAT16 holds ~30k × 768-dim vectors; brute force is plenty fast — no ANN needed.
- No CGO / no C extension: usable with pure-Go
modernc.org/sqlite(which cannot load C extensions — that's the gap this fills). No-lmlink fix, no-mavx2gotcha, no SIMD-dispatch stub returning scalar; arm64 just works. - TurboQuant (2/3/4-bit approximate) is not ported — at this scale exact scan wins and quantized scan needs full rebuild after edits (bad for rolling delete).
- License: MIT (vs sqlite-vector's Elastic 2.0).