Skip to content

Project Overview

GoVector is a lightweight, embeddable vector database written in pure Go, positioned as "the SQLite of vectors". It targets local AI, desktop applications, and edge computing scenarios, providing:

  • Qdrant-compatible REST API
  • HNSW graph index implementing approximate nearest neighbor retrieval (ANN) with O(log N) search complexity
  • BoltDB-based Protobuf persistence supporting automatic discovery and loading of collections after restart
  • Built-in SQ8 8-bit scalar quantization, significantly reducing disk usage
  • Dual-mode operation: embedded library (zero network overhead) and standalone microservice (Qdrant-compatible)

The project has passed comprehensive audits with test coverage above 92%, maintaining sub-millisecond latency at million-scale, far exceeding traditional brute-force indexes.

Project Structure

The repository follows a function-domain layered organization:

  • cmd: Command-line entry and benchmarks
  • cmd/govector: Standalone service entry
  • cmd/bench: Large-scale performance benchmarks
  • core: Core engine (collection, index, storage, models, quantization)
  • api: Qdrant-compatible HTTP API layer
  • example: Embedded usage examples
  • scripts: Build and release scripts
  • Root directory: README, go.mod, Makefile, etc.
graph TB
subgraph "Command Line"
S["cmd/govector/main.go"]
B["cmd/bench/main.go"]
end
subgraph "Core Engine core"
C["core/collection.go"]
H["core/hnsw_index.go"]
ST["core/storage.go"]
M["core/models.go"]
Q["core/quantization.go"]
end
subgraph "API Layer"
A["api/server.go"]
end
subgraph "Examples"
E["example/embedded/main.go"]
end
S --> A
A --> C
C --> H
C --> ST
ST --> Q
E --> C
B --> C

Core Components

  • Collection: Encapsulates vector collections with fixed dimension and specified distance metric; uniformly provides Upsert/Search/Delete; thread-safe; supports dual-write consistency for persistence and in-memory index.
  • HNSWIndex: Graph index based on coder/hnsw, supporting cosine, euclidean, dot product; provides batch insert, approximate search, delete, filter-based ID retrieval.
  • Storage: Local persistence based on bbolt, using Protobuf to serialize points; supports collection metadata, batch read/write, delete, list collections; optional SQ8 quantization.
  • API Server: Provides /collections, /points, /search and other Qdrant-style REST interfaces; supports loading collections from storage on startup; graceful shutdown.
  • Models and Filters: PointStruct, ScoredPoint, Filter, Condition, supporting exact match, range, prefix, contains, regex and other filters.
  • Quantization: SQ8 quantizer interface and implementation, compress/decompress vectors, reducing disk usage.

Architecture Overview

GoVector adopts a layered design of "storage engine + index engine + API layer": - Storage layer: BoltDB + Protobuf, ensuring data persistence and cross-version compatibility - Index layer: Flat index (memory) and HNSW graph index (memory + graph), selectable based on needs - API layer: HTTP service exposing Qdrant-style interfaces, supporting both embedded and standalone service modes - Quantization layer: Optional SQ8 quantization to reduce disk usage

graph TB
subgraph "Client"
U["Application/SDK"]
end
subgraph "API Layer"
HTTP["HTTP service
/collections /points /search"] end subgraph "Core Engine" COL["Collection
Upsert/Search/Delete"] IDX["HNSWIndex/FlatIndex"] ST["Storage
BoltDB + Protobuf"] QUAN["SQ8 Quantization"] end U --> HTTP HTTP --> COL COL --> IDX COL --> ST ST --> QUAN

Detailed Component Analysis

API Server Workflow (Startup and Request Processing)

sequenceDiagram
participant CLI as "Command line"
participant Srv as "API Server"
participant Col as "Collection"
participant Idx as "VectorIndex (HNSW/Flat)"
participant St as "Storage"
CLI->>Srv : Start service (bind address)
Srv->>St : Load collection metadata
St-->>Srv : Return collection config
Srv->>Col : Rebuild collection instance
Note over Srv : Service ready
CLI->>Srv : POST /collections
Srv->>Col : Create collection (optional HNSW params)
Col->>St : Save collection metadata
Srv-->>CLI : Return creation result
CLI->>Srv : PUT /collections/{name}/points
Srv->>Col : Upsert (persist first, then update index)
Col->>St : Write points (optional quantization)
Col->>Idx : Update index
Srv-->>CLI : Return success
CLI->>Srv : POST /collections/{name}/points/search
Srv->>Col : Search (optional filter)
Col->>Idx : Approximate search (oversampling + post-filter)
Idx-->>Col : Result set
Col-->>Srv : Format return
Srv-->>CLI : Return TopK results

HNSW Index Class Diagram

classDiagram
class HNSWIndex {

    -graph : Graph[string]
    -points : map[string]*PointStruct
    -metric : Distance
    -params : HNSWParams
    -mu : RWMutex
    +Upsert(points) error
    +Search(query, filter, topK) []ScoredPoint
    +Delete(id) error
    +Count() int
    +GetIDsByFilter(filter) []string
    +DeleteByFilter(filter) []string

}
class Collection {

    +Name : string
    +VectorLen : int
    +Metric : Distance
    -index : VectorIndex
    -storage : *Storage
    +Upsert(points) error
    +Search(query, filter, topK) []ScoredPoint
    +Delete(points, filter) int
    +Count() int

}
class Storage {

    -db : *bbolt.DB
    -closed : bool
    -quantizer : Quantizer
    -useQuant : bool
    +UpsertPoints(name, points) error
    +LoadCollection(name) map[string]*PointStruct
    +SaveCollectionMeta(name, meta) error
    +DeletePoints(name, ids) error

}
Collection --> HNSWIndex : "uses"
Collection --> Storage : "persists"
HNSWIndex --> Storage : "access metadata by ID"

Query Flow (with Filter Strategy)

flowchart TD
Start(["Start: Search"]) --> CheckDim["Validate query vector dimension"]
CheckDim --> Lock["Read lock protect index"]
Lock --> NeedFilter{"Need filter?"}
NeedFilter --> |No| Fetch["HNSW approximate search (oversampling)"]
NeedFilter --> |Yes| OverFetch["Expand retrieval count (oversampling)"]
OverFetch --> Fetch
Fetch --> FilterLoop["Iterate candidates and apply filter"]
FilterLoop --> ScoreCalc["Recalculate score by metric"]
ScoreCalc --> TopK["Get TopK results"]
TopK --> Unlock["Release read lock"]
Unlock --> End(["End: Return results"])

Embedded Usage Example (Zero Network Overhead)

  • Initialize local storage
  • Create collection (auto-persist metadata)
  • Direct Upsert points (Go structs, no HTTP overhead)
  • Execute filtered search
  • Get native Go object results directly

Dependency Analysis

  • External Dependencies
  • coder/hnsw: HNSW graph index implementation
  • go.etcd.io/bbolt: Embedded key-value database
  • google.golang.org/protobuf: Message serialization
  • Internal Modules
  • core: Core engine
  • api: HTTP API
  • cmd/govector: Service entry
  • cmd/bench: Benchmarks
  • example/embedded: Embedded examples
graph LR
GM["go.mod"] --> HNSW["coder/hnsw"]
GM --> BBOLT["go.etcd.io/bbolt"]
GM --> PBUF["google.golang.org/protobuf"]
SVR["cmd/govector/main.go"] --> API["api/server.go"]
API --> CORE["core/*"]
BENCH["cmd/bench/main.go"] --> CORE
EMB["example/embedded/main.go"] --> CORE

Performance Considerations

  • Large-scale benchmarks (128 dimensions, Cosine, TopK=10)
  • Flat index: 100K scale build ~186ms, average latency ~54.46ms, QPS ~18
  • HNSW index: 100K scale build ~20.9s, average latency ~0.08ms, QPS ~11,812
  • HNSW index: 1M scale build ~4min 17s, average latency ~0.11ms, QPS ~8,709
  • Key Optimization Points
  • HNSW parameters are tunable (M, EfConstruction, EfSearch, K)
  • Oversampling + post-filter strategy balances accuracy and performance for filtered scenarios
  • SQ8 quantization significantly reduces disk usage, suitable for large-scale data
  • Dual-write consistency between storage and index ensures high reliability

Troubleshooting Guide

  • Service fails to start
  • Check database path permissions and writability
  • Check storage initialization error logs
  • Request 404/400/500
  • Confirm collection exists and name is correct
  • Check request body JSON format and fields
  • Check vector dimension matches collection configuration
  • Abnormal search results
  • Confirm filter condition syntax is correct
  • HNSW parameters are reasonable (EfSearch, K)
  • Data inconsistency
  • Upsert failure attempts to rollback storage write
  • Check storage closure status and concurrent access

Conclusion

GoVector implements the "SQLite for vectors" concept as a production-ready embedded vector database: pure Go, no CGO, cross-platform, easy to deploy; balances performance and reliability through HNSW index and BoltDB persistence; provides Qdrant-compatible API and embedded library modes, meeting diverse needs of local AI, desktop applications, and edge computing. With SQ8 quantization and comprehensive test coverage, it can run stably and continuously evolve across different data scales.

[No chapter source - this section is summary content]

Appendix

  • Quick Start
  • Embedded library: Refer to example project
  • Standalone service: Command-line startup, bind port and database path
  • Benchmarks: One-click large-scale performance test
  • Build and Release
  • Makefile provides build/run/release/clean targets
  • Cross-compilation and packaging done by scripts

  • Makefile:9-35