Skip to content
You are viewing the corvid 0.3.0 release snapshot — frozen at the 0.3.0 engine release.Current documentation

corvid-go

corvid-go is the Go binding: it links the engine’s published FFI artifacts (the platform cdylib and corvid.h) over cgo and carries an idiomatic Go API on top — Db, Collection, a fluent Query builder, and Field(...) predicates. Deliberately different from the node/python bindings (Rust-source builds): Go users expect a system/shared library, not a Rust toolchain — make deps fetches and sha256-verifies the pinned release archive, and the requirement stops at “a C compiler”, which cgo already needs.

When to choose this binding: your service is written in Go and you want corvid embedded without CGO-free purism getting in the way — errors are Go errors (*corvid.CorvidError, never panics), Db and Collection are safe for concurrent use, and the engine loads as a shared library your binary links at runtime.

From the pinned release artifacts (default):

Terminal window
make deps # fetch + verify corvid v0.2.1 into deps/current
go test ./... # the golden suite (256 fixture lines)

Requirements: Go ≥ 1.26, a C compiler (CGO enabled — the default when one is present), curl + shasum/sha256sum. Or, if corvid is installed as a system library, point cgo at it with CGO_CFLAGS / CGO_LDFLAGS (see the repo README).

The v0.2.1 C ABI has no map-key iterator — a stored map is readable only by known key. Consequences in this binding (either-correct-or-loud):

  • Get/Scan/Page decode map documents through a candidate-key set fed by everything written through the binding; a map with unknown keys fails wrapping corvid.ErrMapKeyEnumeration rather than guessing.
  • GetFields(key, fields...) and Query.Select(fields...) (projection — the only shape in which Run materializes Row.Doc) never need the oracle and work on any database. Without Select, Row.Doc is nil: carry the key, read the document explicitly.

The upstream corvid_value_map_keys ABI append will collapse this into a plain decode.

Six runnable programs under the repo’s examples/ directory (go run ./examples/<name>), executed on every CI leg with deterministic output: quickstart, hybrid (the flagship below), vector-index (in-memory / on-disk / binary-quantized HNSW vs the exact scan), text-search (BM25 incl. CJK bigram segmentation), graph (neighbors/traverse + delete cascade), and geo (radius / bbox / nearest). The quickstart and hybrid sources are embedded below — imported from the repo so they cannot drift from what CI executes (scripts/sync-binding-examples.sh; the drift gate reddens docs CI if they diverge).

func main() {
db, err := corvid.OpenMemory()
if err != nil {
panic(err)
}
defer func() { must(db.Close()) }()
docs, err := db.Collection("docs")
if err != nil {
panic(err)
}
defer docs.Close()
must(docs.Insert([]byte("p1"), map[string]any{
"title": "rust embedded database", "kind": "doc",
"v": []float32{1.0, 0.0},
}))
must(docs.Insert([]byte("p2"), map[string]any{
"title": "python web frameworks", "kind": "doc",
"v": []float32{0.0, 1.0},
}))
must(docs.Insert([]byte("p3"), map[string]any{
"title": "rust again database", "kind": "doc",
"v": []float32{0.9, 0.1},
}))
// kNN: the 3 nearest documents to (1, 0) under cosine. Row.Doc is
// materialized only under Select (the v0.2.1 ABI has no map-key
// iterator) — select the field the printout needs.
rows, err := docs.Query().
Vector("v", []float32{1.0, 0.0}, 3, corvid.MetricCosine).
Select("title").
Run()
if err != nil {
panic(err)
}
for rank, r := range rows {
fmt.Printf("%d. %s score=%.6f %v\n", rank+1, r.Key, r.Score, r.Doc)
}
}
func main() {
db, err := corvid.OpenMemory()
if err != nil {
panic(err)
}
defer func() { must(db.Close()) }()
docs, err := db.Collection("docs")
if err != nil {
panic(err)
}
defer docs.Close()
must(docs.Insert([]byte("s1"), map[string]any{
"kind": "doc", "body": "rust embedded database",
"v": []float32{1.0, 0.0},
}))
must(docs.Insert([]byte("s2"), map[string]any{
"kind": "doc", "body": "python web frameworks",
"v": []float32{0.0, 1.0},
}))
must(docs.Insert([]byte("s3"), map[string]any{
"kind": "doc", "body": "rust again database",
"v": []float32{0.9, 0.1},
}))
must(docs.Insert([]byte("m1"), map[string]any{"kind": "meta"})) // filtered out below
// The flagship query: filter + vector + text, RRF + MMR + limit.
rows, err := docs.Query().
Filter(corvid.Field("kind").Eq("doc")).
Vector("v", []float32{1.0, 0.0}, 2, corvid.MetricCosine).
Text("body", "rust database", 2).
FuseRRF(60).
RerankMMR(1.0).
Limit(2).
Select("body").
Run()
if err != nil {
panic(err)
}
for rank, r := range rows {
fmt.Printf("%d. %s score=%.6f %v\n", rank+1, r.Key, r.Score, r.Doc)
}
}

The fused scores are RRF rank sums: s1 is rank 1 of both sources (1/61 + 1/61 = 2/61 ≈ 0.032787), s3 rank 2 of both (2/62 ≈ 0.032258).

Goengine
nil / bool / stringNull / Bool / Text
int64Int (full i64)
float64Float — NaN and ±inf cross bit-exactly
[]byteBytes
[]float32Vector
[]any / map[string]anyArray / Map

Keys are []byte. Errors are *corvid.CorvidError (implements error + Code()); Query/Predicate builders are single-goroutine, build-once, consumed-by-the-terminal; Close on every handle, with runtime finalizers as backstops only.

The binding replays the engine’s golden suite — the same 256-line fixture files the C ABI smoke harness runs, vendored byte-identical and verified against each release — through its public API on every CI run (golden_test.go), then executes the six-example tour under go run (and golangci-lint). The plan (architecture ruling, lifetime mapping, pointer discipline) lives in the repo.

Next: the reference section.