hupe1980/vecgo

πŸ§¬πŸ” Vecgo is a pure Go, embeddable, hybrid vector database designed for high-performance production workloads. It combines commit-oriented durability with HNSW + DiskANN indexing for best-in-class performance.

Go

20

173 commits

updated Jan 19, 2026

See the code

README

πŸ§¬πŸ” Vecgo

CI Go Reference goreportcard License

Vecgo is a pure Go, embeddable, hybrid vector database designed for high-performance production workloads. It combines commit-oriented durability with HNSW + DiskANN indexing for best-in-class performance.

⚠️ This is experimental and subject to breaking changes.

✨ Key Differentiators

  • ⚑ Faster & lighter than external services β€” no network overhead, no sidecar, 15MB binary
  • πŸ”§ More capable than simple libraries β€” durability, MVCC, hybrid search, cloud storage
  • 🎯 Simpler than CGO wrappers β€” pure Go toolchain, static binaries, cross-compilation
  • πŸ—οΈ Modern architecture β€” commit-oriented durability (append-only versioned commits), no WAL complexity

πŸ“Š Performance

Vecgo is optimized for high-throughput, low-latency vector search with:

  • FilterCursor β€” zero-allocation push-based iteration
  • Zero-Copy Vectors β€” direct access to mmap'd memory
  • SIMD Distance β€” AVX-512/AVX2/NEON/SVE2 runtime detection

Run benchmarks locally to see performance on your hardware:

cd benchmark_test && go test -bench=. -benchmem -timeout=15m

See benchmark_test/baseline.txt for reference results.

🎯 Features

πŸ“Š Index Types

IndexDescriptionUse Case
HNSWHierarchical Navigable Small World graphIn-memory L0 (16-way sharded, lock-free search, arena allocator)
DiskANN/VamanaDisk-resident graph with quantizationLarge-scale on-disk segments with PQ/RaBitQ
FreshDiskANNStreaming updates for VamanaLock-free reads, soft deletion, background consolidation
FlatExact nearest-neighbor with SIMDExact search, small segments

πŸ—œοΈ Quantization

Quantization reduces in-memory index size for DiskANN segments. Full vectors remain on disk for reranking.

MethodRAM ReductionRecallBest For
Product Quantization (PQ)8-64Γ—90-95%Large-scale, high compression
Optimized PQ (OPQ)8-64Γ—93-97%Best recall with compression
Scalar Quantization (SQ8)4Γ—95-99%General purpose, balanced
Binary Quantization (BQ)32Γ—70-85%Pre-filtering, coarse search
RaBitQ~30Γ—80-90%Better BQ alternative (SIGMOD '24)
INT48Γ—90-95%Memory-constrained

πŸ“– See Performance Tuning Guide for detailed quantization configuration.

🏒 Enterprise Features

  • ☁️ Cloud-Native Storage β€” S3/GCS/Azure via pluggable BlobStore interface
  • πŸ”’ Commit-Oriented Durability β€” Atomic commits with immutable segments
  • πŸ”€ Hybrid Search β€” BM25 + vector similarity with RRF fusion
  • πŸ“Έ Snapshot Isolation β€” Lock-free reads via MVCC
  • ⏰ Time-Travel Queries β€” WithTimestamp() / WithVersion() to query historical state
  • 🏷️ Typed Metadata β€” Schema-enforced metadata with filtering
  • πŸ“Š Query Statistics β€” WithStats() + Explain() for debugging
  • 🎯 Segment Pruning β€” Triangle inequality, Bloom filters, numeric range stats
  • πŸš€ SIMD Optimized β€” AVX-512/AVX2/NEON/SVE2 runtime detection

πŸš€ Quick Start

πŸ“¦ Installation

go get github.com/hupe1980/vecgo

Platform Requirements: Vecgo requires a 64-bit architecture (amd64 or arm64). SIMD optimizations use AVX-512/AVX2 on x86-64 and NEON/SVE2 on ARM64.

πŸ’» Basic Usage

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/hupe1980/vecgo"
    "github.com/hupe1980/vecgo/metadata"
)

func main() {
    ctx := context.Background()

    // Create a new index (128 dimensions, L2 distance)
    db, err := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.Create(128, vecgo.MetricL2))
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    // Insert with fluent builder API
    vector := make([]float32, 128)
    rec := vecgo.NewRecord(vector).
        WithMetadata("category", metadata.String("electronics")).
        WithMetadata("price", metadata.Float(99.99)).
        WithPayload([]byte(`{"desc": "Product description"}`)).
        Build()
    
    id, err := db.InsertRecord(ctx, rec)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Inserted ID: %d\n", id)

    // Or use the simple API
    id, err = db.Insert(ctx, vector, nil, nil)

    // Commit to disk (data is durable after this)
    if err := db.Commit(ctx); err != nil {
        log.Fatal(err)
    }

    // Search β€” returns IDs, scores, metadata, and payload by default
    query := make([]float32, 128)
    results, err := db.Search(ctx, query, 10)
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range results {
        fmt.Printf("ID: %d, Score: %.4f\n", r.ID, r.Score)
    }

    // High-throughput mode (IDs + scores only)
    results, _ = db.Search(ctx, query, 10, vecgo.WithoutData())
}

πŸ”„ Re-open Existing Index

// Dimension and metric are auto-loaded from manifest
db, err := vecgo.Open(ctx, vecgo.Local("./data"))

☁️ Cloud Storage (Writer/Reader Separation)

import (
    "github.com/hupe1980/vecgo"
    "github.com/hupe1980/vecgo/blobstore/s3"
)

// === Writer Node (build index locally, then sync to S3) ===
db, _ := vecgo.Open(ctx, vecgo.Local("/data/vecgo"), vecgo.Create(128, vecgo.MetricL2))
db.Insert(ctx, vector, nil, nil)
db.Close()
// Sync: aws s3 sync /data/vecgo s3://my-bucket/vecgo/

// === Reader Nodes (stateless, horizontally scalable) ===
store, _ := s3.New(ctx, "my-bucket", s3.WithPrefix("vecgo/"))

// Remote() is automatically read-only
db, err := vecgo.Open(ctx, vecgo.Remote(store))

// Writes return ErrReadOnly
_, err = db.Insert(ctx, vec, nil, nil)  // err == vecgo.ErrReadOnly

// With explicit cache directory for faster repeated queries
db, err := vecgo.Open(ctx, vecgo.Remote(store),
    vecgo.WithCacheDir("/fast/nvme"),
    vecgo.WithBlockCacheSize(4 << 30),  // 4GB
)
// Define schema for type safety
schema := metadata.Schema{
    "category": metadata.FieldTypeString,
    "price":    metadata.FieldTypeFloat,
}

db, _ := vecgo.Open(ctx, vecgo.Local("./data"),
    vecgo.Create(128, vecgo.MetricL2),
    vecgo.WithSchema(schema),
)

// Search with filter
filter := metadata.NewFilterSet(
    metadata.Filter{Key: "category", Operator: metadata.OpEqual, Value: metadata.String("electronics")},
    metadata.Filter{Key: "price", Operator: metadata.OpLessThan, Value: metadata.Float(100.0)},
)

results, _ := db.Search(ctx, query, 10, vecgo.WithFilter(filter))

πŸ”€ Hybrid Search (Vector + BM25)

// Insert with text for BM25 indexing
doc := metadata.Document{
    "text": metadata.String("machine learning neural networks"),
}
db.Insert(ctx, vector, doc, nil)

// Hybrid search with RRF fusion
results, _ := db.HybridSearch(ctx, vector, "neural networks", 10)

⏰ Time-Travel Queries

Query historical snapshots without affecting the current state:

// Open at a specific point in time
yesterday := time.Now().Add(-24 * time.Hour)
db, _ := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.WithTimestamp(yesterday))

// Or open at a specific version ID
db, _ := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.WithVersion(42))

// Query as if it were that moment in time
results, _ := db.Search(ctx, query, 10)

How it works:

  • Old manifests are preserved (each points to immutable segments)
  • Compaction still runs β€” creates NEW optimized segments
  • Old segments retained until Vacuum() removes expired manifests
  • Storage: ~current_data Γ— (1 + retained_versions Γ— churn_rate)

Use cases:

  • πŸ” Debug production issues: "What did the index look like before the bad deployment?"
  • πŸ“Š A/B testing: Compare recall against historical versions
  • πŸ”„ Recovery: Roll back to a known-good state

Managing retention:

// Configure retention policy
policy := vecgo.RetentionPolicy{KeepVersions: 10}
db, _ := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.WithRetentionPolicy(policy))

// Reclaim disk space from expired versions
db.Vacuum(ctx)

πŸ“Š Query Statistics & Explain

Understand query execution for debugging and optimization:

var stats vecgo.QueryStats
results, _ := db.Search(ctx, query, 10, vecgo.WithStats(&stats))

// Summary explanation
fmt.Println(stats.Explain())
// Output: "searched 3 segments (1 pruned by stats, 0 by bloom), 
//          scanned 1200 vectors in 2.1ms, recalled 847 candidates (0.7 hit rate)"

// Detailed statistics
fmt.Printf("Segments searched: %d\n", stats.SegmentsSearched)
fmt.Printf("Segments pruned (stats): %d\n", stats.SegmentsPrunedByStats)
fmt.Printf("Segments pruned (bloom): %d\n", stats.SegmentsPrunedByBloom)
fmt.Printf("Vectors scanned: %d\n", stats.VectorsScanned)
fmt.Printf("Candidates recalled: %d\n", stats.CandidatesRecalled)
fmt.Printf("Latency: %v\n", stats.Latency)
fmt.Printf("Graph hops: %d\n", stats.GraphHops)
fmt.Printf("Cost estimate: %.2f\n", stats.CostEstimate())

🎯 Segment Pruning & Manifest Stats

Vecgo automatically prunes irrelevant segments using advanced statistics:

Pruning StrategyDescription
Triangle InequalitySkip segments where `
Bloom FiltersSkip segments missing required categorical values
Numeric Range StatsSkip segments with min/max outside filter range
Categorical CardinalityPrioritize high-entropy segments for broad queries

These statistics are automatically computed during Commit() and stored in the manifest (v3 format).

// Get current statistics
dbStats := db.Stats()
fmt.Printf("Manifest version: %d\n", dbStats.ManifestID)
fmt.Printf("Total vectors: %d\n", dbStats.TotalVectors)
fmt.Printf("Segment count: %d\n", dbStats.SegmentCount)

πŸ“¦ Insert Modes

Vecgo offers three insert modes optimized for different workloads:

ModeMethodSearchableBest For
SingleInsert()βœ… ImmediatelyReal-time updates
BatchBatchInsert()βœ… ImmediatelyMedium batches (10-100)
DeferredBatchInsertDeferred()❌ After flushBulk loading
// 1. SINGLE INSERT β€” Real-time updates (HNSW-indexed immediately)
//    Use when: you need vectors searchable immediately
id, err := db.Insert(ctx, vector, metadata, payload)

// 2. BATCH INSERT β€” Indexed batch (HNSW-indexed immediately)
//    Use when: you have medium batches and need immediate search
ids, err := db.BatchInsert(ctx, vectors, metadatas, payloads)

// 3. DEFERRED INSERT β€” Bulk loading (NO HNSW indexing)
//    Use when: you're bulk loading and don't need immediate search
//    Vectors become searchable after Commit() triggers flush
ids, err := db.BatchInsertDeferred(ctx, vectors, metadatas, payloads)
db.Commit(ctx) // Flush to disk, now searchable via DiskANN

When to use Deferred mode:

  • Initial data loading (embeddings from a corpus)
  • Periodic bulk updates (nightly reindex)
  • Migration from another database

When NOT to use Deferred mode:

  • Real-time RAG (documents must be searchable immediately)
  • Interactive applications with instant feedback
// Batch delete
err = db.BatchDelete(ctx, ids)

πŸ’Ύ Durability Model

Vecgo uses commit-oriented durability β€” append-only versioned commits:

sequenceDiagram
    participant App as Application
    participant MT as MemTable (RAM)
    participant Seg as Segment (Disk)
    participant Man as Manifest

    App->>MT: Insert(vector, metadata)
    Note over MT: Buffered in memory<br/>❌ NOT durable
    
    App->>MT: Insert(vector, metadata)
    
    App->>Seg: Commit()
    MT->>Seg: Write immutable segment
    Seg->>Man: Update manifest atomically
    Note over Seg,Man: βœ… DURABLE after Commit()
StateSurvives Crash?
After Insert(), before Commit()❌ No
After Commit()βœ… Yes
After Close()βœ… Yes (auto-commits pending)

Why commit-oriented?

  • 🧹 Simpler code β€” no WAL rotation, recovery, or checkpointing
  • ⚑ Faster batch inserts β€” no fsync per insert
  • ☁️ Cloud-native β€” pure segment writes, ideal for S3/GCS
  • πŸš€ Instant startup β€” no recovery/replay, just read manifest

πŸ“š Documentation

οΏ½ Examples

ExampleDescription
basicCreate index, insert, search, commit
modernFluent API, schema-enforced metadata, scan iterator
ragRetrieval-Augmented Generation workflow
cloud_tieredWriter/reader separation with S3
bulk_loadHigh-throughput ingestion with BatchInsertDeferred
time_travelQuery historical versions by time or version ID
explainQuery statistics, cost estimation, performance debugging
observabilityPrometheus metrics integration

οΏ½πŸ“„ Algorithm References

🀝 Contributing

Contributions welcome! Please open an issue or pull request.

πŸ“œ License

Licensed under the Apache License 2.0. See LICENSE for details.

ann
bq
diskann
embeddings
golang
hnsw
int4
mmap
mvcc
opq
pq
rabitq
rrf
s3
simd
sq8
vamana
vector
vectorstore
zero-copy

Contributors

hupe1980

173 commits

hupe1980/vecgo

πŸ§¬πŸ” Vecgo is a pure Go, embeddable, hybrid vector database designed for high-performance production workloads. It combines commit-oriented durability with HNSW + DiskANN indexing for best-in-class performance.

Go

20

173 commits

updated Jan 19, 2026

See the code

README

πŸ§¬πŸ” Vecgo

CI Go Reference goreportcard License

Vecgo is a pure Go, embeddable, hybrid vector database designed for high-performance production workloads. It combines commit-oriented durability with HNSW + DiskANN indexing for best-in-class performance.

⚠️ This is experimental and subject to breaking changes.

✨ Key Differentiators

  • ⚑ Faster & lighter than external services β€” no network overhead, no sidecar, 15MB binary
  • πŸ”§ More capable than simple libraries β€” durability, MVCC, hybrid search, cloud storage
  • 🎯 Simpler than CGO wrappers β€” pure Go toolchain, static binaries, cross-compilation
  • πŸ—οΈ Modern architecture β€” commit-oriented durability (append-only versioned commits), no WAL complexity

πŸ“Š Performance

Vecgo is optimized for high-throughput, low-latency vector search with:

  • FilterCursor β€” zero-allocation push-based iteration
  • Zero-Copy Vectors β€” direct access to mmap'd memory
  • SIMD Distance β€” AVX-512/AVX2/NEON/SVE2 runtime detection

Run benchmarks locally to see performance on your hardware:

cd benchmark_test && go test -bench=. -benchmem -timeout=15m

See benchmark_test/baseline.txt for reference results.

🎯 Features

πŸ“Š Index Types

IndexDescriptionUse Case
HNSWHierarchical Navigable Small World graphIn-memory L0 (16-way sharded, lock-free search, arena allocator)
DiskANN/VamanaDisk-resident graph with quantizationLarge-scale on-disk segments with PQ/RaBitQ
FreshDiskANNStreaming updates for VamanaLock-free reads, soft deletion, background consolidation
FlatExact nearest-neighbor with SIMDExact search, small segments

πŸ—œοΈ Quantization

Quantization reduces in-memory index size for DiskANN segments. Full vectors remain on disk for reranking.

MethodRAM ReductionRecallBest For
Product Quantization (PQ)8-64Γ—90-95%Large-scale, high compression
Optimized PQ (OPQ)8-64Γ—93-97%Best recall with compression
Scalar Quantization (SQ8)4Γ—95-99%General purpose, balanced
Binary Quantization (BQ)32Γ—70-85%Pre-filtering, coarse search
RaBitQ~30Γ—80-90%Better BQ alternative (SIGMOD '24)
INT48Γ—90-95%Memory-constrained

πŸ“– See Performance Tuning Guide for detailed quantization configuration.

🏒 Enterprise Features

  • ☁️ Cloud-Native Storage β€” S3/GCS/Azure via pluggable BlobStore interface
  • πŸ”’ Commit-Oriented Durability β€” Atomic commits with immutable segments
  • πŸ”€ Hybrid Search β€” BM25 + vector similarity with RRF fusion
  • πŸ“Έ Snapshot Isolation β€” Lock-free reads via MVCC
  • ⏰ Time-Travel Queries β€” WithTimestamp() / WithVersion() to query historical state
  • 🏷️ Typed Metadata β€” Schema-enforced metadata with filtering
  • πŸ“Š Query Statistics β€” WithStats() + Explain() for debugging
  • 🎯 Segment Pruning β€” Triangle inequality, Bloom filters, numeric range stats
  • πŸš€ SIMD Optimized β€” AVX-512/AVX2/NEON/SVE2 runtime detection

πŸš€ Quick Start

πŸ“¦ Installation

go get github.com/hupe1980/vecgo

Platform Requirements: Vecgo requires a 64-bit architecture (amd64 or arm64). SIMD optimizations use AVX-512/AVX2 on x86-64 and NEON/SVE2 on ARM64.

πŸ’» Basic Usage

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/hupe1980/vecgo"
    "github.com/hupe1980/vecgo/metadata"
)

func main() {
    ctx := context.Background()

    // Create a new index (128 dimensions, L2 distance)
    db, err := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.Create(128, vecgo.MetricL2))
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    // Insert with fluent builder API
    vector := make([]float32, 128)
    rec := vecgo.NewRecord(vector).
        WithMetadata("category", metadata.String("electronics")).
        WithMetadata("price", metadata.Float(99.99)).
        WithPayload([]byte(`{"desc": "Product description"}`)).
        Build()
    
    id, err := db.InsertRecord(ctx, rec)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Inserted ID: %d\n", id)

    // Or use the simple API
    id, err = db.Insert(ctx, vector, nil, nil)

    // Commit to disk (data is durable after this)
    if err := db.Commit(ctx); err != nil {
        log.Fatal(err)
    }

    // Search β€” returns IDs, scores, metadata, and payload by default
    query := make([]float32, 128)
    results, err := db.Search(ctx, query, 10)
    if err != nil {
        log.Fatal(err)
    }

    for _, r := range results {
        fmt.Printf("ID: %d, Score: %.4f\n", r.ID, r.Score)
    }

    // High-throughput mode (IDs + scores only)
    results, _ = db.Search(ctx, query, 10, vecgo.WithoutData())
}

πŸ”„ Re-open Existing Index

// Dimension and metric are auto-loaded from manifest
db, err := vecgo.Open(ctx, vecgo.Local("./data"))

☁️ Cloud Storage (Writer/Reader Separation)

import (
    "github.com/hupe1980/vecgo"
    "github.com/hupe1980/vecgo/blobstore/s3"
)

// === Writer Node (build index locally, then sync to S3) ===
db, _ := vecgo.Open(ctx, vecgo.Local("/data/vecgo"), vecgo.Create(128, vecgo.MetricL2))
db.Insert(ctx, vector, nil, nil)
db.Close()
// Sync: aws s3 sync /data/vecgo s3://my-bucket/vecgo/

// === Reader Nodes (stateless, horizontally scalable) ===
store, _ := s3.New(ctx, "my-bucket", s3.WithPrefix("vecgo/"))

// Remote() is automatically read-only
db, err := vecgo.Open(ctx, vecgo.Remote(store))

// Writes return ErrReadOnly
_, err = db.Insert(ctx, vec, nil, nil)  // err == vecgo.ErrReadOnly

// With explicit cache directory for faster repeated queries
db, err := vecgo.Open(ctx, vecgo.Remote(store),
    vecgo.WithCacheDir("/fast/nvme"),
    vecgo.WithBlockCacheSize(4 << 30),  // 4GB
)
// Define schema for type safety
schema := metadata.Schema{
    "category": metadata.FieldTypeString,
    "price":    metadata.FieldTypeFloat,
}

db, _ := vecgo.Open(ctx, vecgo.Local("./data"),
    vecgo.Create(128, vecgo.MetricL2),
    vecgo.WithSchema(schema),
)

// Search with filter
filter := metadata.NewFilterSet(
    metadata.Filter{Key: "category", Operator: metadata.OpEqual, Value: metadata.String("electronics")},
    metadata.Filter{Key: "price", Operator: metadata.OpLessThan, Value: metadata.Float(100.0)},
)

results, _ := db.Search(ctx, query, 10, vecgo.WithFilter(filter))

πŸ”€ Hybrid Search (Vector + BM25)

// Insert with text for BM25 indexing
doc := metadata.Document{
    "text": metadata.String("machine learning neural networks"),
}
db.Insert(ctx, vector, doc, nil)

// Hybrid search with RRF fusion
results, _ := db.HybridSearch(ctx, vector, "neural networks", 10)

⏰ Time-Travel Queries

Query historical snapshots without affecting the current state:

// Open at a specific point in time
yesterday := time.Now().Add(-24 * time.Hour)
db, _ := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.WithTimestamp(yesterday))

// Or open at a specific version ID
db, _ := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.WithVersion(42))

// Query as if it were that moment in time
results, _ := db.Search(ctx, query, 10)

How it works:

  • Old manifests are preserved (each points to immutable segments)
  • Compaction still runs β€” creates NEW optimized segments
  • Old segments retained until Vacuum() removes expired manifests
  • Storage: ~current_data Γ— (1 + retained_versions Γ— churn_rate)

Use cases:

  • πŸ” Debug production issues: "What did the index look like before the bad deployment?"
  • πŸ“Š A/B testing: Compare recall against historical versions
  • πŸ”„ Recovery: Roll back to a known-good state

Managing retention:

// Configure retention policy
policy := vecgo.RetentionPolicy{KeepVersions: 10}
db, _ := vecgo.Open(ctx, vecgo.Local("./data"), vecgo.WithRetentionPolicy(policy))

// Reclaim disk space from expired versions
db.Vacuum(ctx)

πŸ“Š Query Statistics & Explain

Understand query execution for debugging and optimization:

var stats vecgo.QueryStats
results, _ := db.Search(ctx, query, 10, vecgo.WithStats(&stats))

// Summary explanation
fmt.Println(stats.Explain())
// Output: "searched 3 segments (1 pruned by stats, 0 by bloom), 
//          scanned 1200 vectors in 2.1ms, recalled 847 candidates (0.7 hit rate)"

// Detailed statistics
fmt.Printf("Segments searched: %d\n", stats.SegmentsSearched)
fmt.Printf("Segments pruned (stats): %d\n", stats.SegmentsPrunedByStats)
fmt.Printf("Segments pruned (bloom): %d\n", stats.SegmentsPrunedByBloom)
fmt.Printf("Vectors scanned: %d\n", stats.VectorsScanned)
fmt.Printf("Candidates recalled: %d\n", stats.CandidatesRecalled)
fmt.Printf("Latency: %v\n", stats.Latency)
fmt.Printf("Graph hops: %d\n", stats.GraphHops)
fmt.Printf("Cost estimate: %.2f\n", stats.CostEstimate())

🎯 Segment Pruning & Manifest Stats

Vecgo automatically prunes irrelevant segments using advanced statistics:

Pruning StrategyDescription
Triangle InequalitySkip segments where `
Bloom FiltersSkip segments missing required categorical values
Numeric Range StatsSkip segments with min/max outside filter range
Categorical CardinalityPrioritize high-entropy segments for broad queries

These statistics are automatically computed during Commit() and stored in the manifest (v3 format).

// Get current statistics
dbStats := db.Stats()
fmt.Printf("Manifest version: %d\n", dbStats.ManifestID)
fmt.Printf("Total vectors: %d\n", dbStats.TotalVectors)
fmt.Printf("Segment count: %d\n", dbStats.SegmentCount)

πŸ“¦ Insert Modes

Vecgo offers three insert modes optimized for different workloads:

ModeMethodSearchableBest For
SingleInsert()βœ… ImmediatelyReal-time updates
BatchBatchInsert()βœ… ImmediatelyMedium batches (10-100)
DeferredBatchInsertDeferred()❌ After flushBulk loading
// 1. SINGLE INSERT β€” Real-time updates (HNSW-indexed immediately)
//    Use when: you need vectors searchable immediately
id, err := db.Insert(ctx, vector, metadata, payload)

// 2. BATCH INSERT β€” Indexed batch (HNSW-indexed immediately)
//    Use when: you have medium batches and need immediate search
ids, err := db.BatchInsert(ctx, vectors, metadatas, payloads)

// 3. DEFERRED INSERT β€” Bulk loading (NO HNSW indexing)
//    Use when: you're bulk loading and don't need immediate search
//    Vectors become searchable after Commit() triggers flush
ids, err := db.BatchInsertDeferred(ctx, vectors, metadatas, payloads)
db.Commit(ctx) // Flush to disk, now searchable via DiskANN

When to use Deferred mode:

  • Initial data loading (embeddings from a corpus)
  • Periodic bulk updates (nightly reindex)
  • Migration from another database

When NOT to use Deferred mode:

  • Real-time RAG (documents must be searchable immediately)
  • Interactive applications with instant feedback
// Batch delete
err = db.BatchDelete(ctx, ids)

πŸ’Ύ Durability Model

Vecgo uses commit-oriented durability β€” append-only versioned commits:

sequenceDiagram
    participant App as Application
    participant MT as MemTable (RAM)
    participant Seg as Segment (Disk)
    participant Man as Manifest

    App->>MT: Insert(vector, metadata)
    Note over MT: Buffered in memory<br/>❌ NOT durable
    
    App->>MT: Insert(vector, metadata)
    
    App->>Seg: Commit()
    MT->>Seg: Write immutable segment
    Seg->>Man: Update manifest atomically
    Note over Seg,Man: βœ… DURABLE after Commit()
StateSurvives Crash?
After Insert(), before Commit()❌ No
After Commit()βœ… Yes
After Close()βœ… Yes (auto-commits pending)

Why commit-oriented?

  • 🧹 Simpler code β€” no WAL rotation, recovery, or checkpointing
  • ⚑ Faster batch inserts β€” no fsync per insert
  • ☁️ Cloud-native β€” pure segment writes, ideal for S3/GCS
  • πŸš€ Instant startup β€” no recovery/replay, just read manifest

πŸ“š Documentation

οΏ½ Examples

ExampleDescription
basicCreate index, insert, search, commit
modernFluent API, schema-enforced metadata, scan iterator
ragRetrieval-Augmented Generation workflow
cloud_tieredWriter/reader separation with S3
bulk_loadHigh-throughput ingestion with BatchInsertDeferred
time_travelQuery historical versions by time or version ID
explainQuery statistics, cost estimation, performance debugging
observabilityPrometheus metrics integration

οΏ½πŸ“„ Algorithm References

🀝 Contributing

Contributions welcome! Please open an issue or pull request.

πŸ“œ License

Licensed under the Apache License 2.0. See LICENSE for details.

ann
bq
diskann
embeddings
golang
hnsw
int4
mmap
mvcc
opq
pq
rabitq
rrf
s3
simd
sq8
vamana
vector
vectorstore
zero-copy

Contributors

hupe1980

173 commits

Languages

Go

73.3%

Assembly

19.2%

C

7.3%