Architecture Overview¶
GoVector is a lightweight, embeddable vector database written in pure Go, designed to provide high-performance vector similarity search capabilities for local AI applications, desktop applications, and edge computing scenarios. It provides a Qdrant-compatible REST API, uses HNSW graph indexing for approximate nearest neighbor search, and achieves persistent storage through BoltDB.
The core design philosophy of the system is:
- Layered decoupling: Clear four-layer architecture with explicit and independent responsibilities for each layer
- Interface abstraction: Transparent switching of index strategies through VectorIndex interface
- Extensibility: Supports multiple distance metrics, filter conditions, and storage backends
- Reliability: Transaction-based persistence using bbolt ensures data consistency
Project Structure¶
GoVector uses a modular directory structure, organizing code by functional layers:
graph TB
subgraph "Application Layer"
CMD[Command Line Entry
cmd/govector/main.go]
API[HTTP API Layer
api/server.go]
end
subgraph "Business Logic Layer"
CORE[Core Business Logic
core/collection.go]
MODELS[Data Models
core/models.go]
end
subgraph "Index Layer"
INDEX[Index Interface
core/index.go]
HNSW[HNSW Index
core/hnsw_index.go]
FLAT[Flat Index
core/flat_index.go]
end
subgraph "Storage Layer"
STORAGE[Storage Engine
core/storage.go]
QUANT[Quantizer
core/quantization.go]
end
CMD --> API
API --> CORE
CORE --> INDEX
INDEX --> HNSW
INDEX --> FLAT
CORE --> STORAGE
STORAGE --> QUANT
Core Components¶
Four-Layer Architecture Design¶
GoVector adopts a classic four-layer architecture pattern:
- API Layer: Provides RESTful HTTP interface, handles client requests
- Business Logic Layer: Encapsulates Collection abstraction, manages lifecycle of vector collections
- Index Layer: Implements VectorIndex interface, supports HNSW and Flat index strategies
- Storage Layer: bbolt-based persistent storage, supports vector quantization compression
Key Data Models¶
The system uses the following core data structures:
classDiagram
class Collection {
+string Name
+int VectorLen
+Distance Metric
+VectorIndex index
+Storage storage
+Upsert(points) error
+Search(query, filter, topK) []ScoredPoint
+Delete(points, filter) int
+Count() int
}
class VectorIndex {
<>
+Upsert(points) error
+Search(query, filter, topK) []ScoredPoint
+Delete(id) error
+Count() int
+GetIDsByFilter(filter) []string
+DeleteByFilter(filter) []string
}
class HNSWIndex {
+Graph graph
+map~string, PointStruct~ points
+Distance metric
+HNSWParams params
+Upsert(points) error
+Search(query, filter, topK) []ScoredPoint
+Delete(id) error
+Count() int
}
class FlatIndex {
+map~string, PointStruct~ points
+Distance metric
+Upsert(points) error
+Search(query, filter, topK) []ScoredPoint
+Delete(id) error
+Count() int
}
class Storage {
+bbolt.DB db
+Quantizer quantizer
+bool useQuant
+EnsureCollection(name) error
+UpsertPoints(name, points) error
+LoadCollection(name) map[string]*PointStruct
+DeletePoints(name, ids) error
}
class Server {
+string addr
+map~string, Collection~ collections
+Storage store
+http.Server httpServer
+Start() error
+Stop(ctx) error
+AddCollection(col)
}
Collection ..|> VectorIndex : implements
HNSWIndex ..|> VectorIndex : implements
FlatIndex ..|> VectorIndex : implements
Collection --> Storage : uses
Server --> Collection : manages
Server --> Storage : uses
Architecture Overview¶
Complete Data Flow¶
The complete data flow from client request to data persistence is as follows:
sequenceDiagram
participant Client as Client
participant API as API Layer
participant Collection as Business Logic Layer
participant Index as Index Layer
participant Storage as Storage Layer
Note over Client,Storage : Write Flow (Upsert)
Client->>API : PUT /collections/{name}/points
API->>Collection : handleUpsert()
Collection->>Collection : Validate vector dimension
Collection->>Storage : UpsertPoints()
Storage->>Storage : Serialize and store
Collection->>Index : Upsert()
Index->>Index : Update in-memory index
API-->>Client : Return operation result
Note over Client,Storage : Query Flow (Search)
Client->>API : POST /collections/{name}/points/search
API->>Collection : handleSearch()
Collection->>Index : Search()
Index->>Index : HNSW approximate search
Index->>Index : Post-filter (payload)
Index-->>Collection : Return TopK results
Collection-->>API : Return query results
API-->>Client : Return matching vectors
Architecture Design Principles¶
- Layered decoupling: Each layer has clear responsibility boundaries, communication through interfaces
- Interface abstraction: VectorIndex interface allows transparent switching of different index strategies
- Extensibility: Supports multiple distance metrics (Cosine, Euclidean, Dot product)
- Reliability: Transaction-based operations using bbolt ensure data consistency
- Performance optimization: HNSW index provides approximate but efficient search capability
Detailed Component Analysis¶
API Layer Analysis¶
The API layer is responsible for handling HTTP requests, providing Qdrant-compatible REST API:
flowchart TD
Start([HTTP request arrives]) --> ParsePath["Parse path parameters
/collections/{name}"]
ParsePath --> CheckCollection{"Collection exists?"}
CheckCollection --> |No| NotFound["Return 404 Not Found"]
CheckCollection --> |Yes| ParseBody["Parse request body JSON"]
ParseBody --> ValidateJSON{"JSON format valid?"}
ValidateJSON --> |No| BadRequest["Return 400 Bad Request"]
ValidateJSON --> |Yes| ProcessOp["Process specific operation"]
ProcessOp --> Upsert["Upsert operation"]
ProcessOp --> Search["Search operation"]
ProcessOp --> Delete["Delete operation"]
ProcessOp --> Create["Create Collection operation"]
ProcessOp --> DeleteCol["Delete Collection operation"]
Upsert --> CallCollection["Call Collection method"]
Search --> CallCollection
Delete --> CallCollection
Create --> CreateCollection["Create new collection"]
DeleteCol --> RemoveCollection["Remove collection"]
CallCollection --> Success["Return 200 OK"]
CreateCollection --> Success
RemoveCollection --> Success
NotFound --> End([Response end])
BadRequest --> End
Success --> End
Business Logic Layer Analysis¶
The Collection class is the core of business logic, encapsulating all operations for vector collections:
classDiagram
class Collection {
+string Name
+int VectorLen
+Distance Metric
+VectorIndex index
+Storage storage
+RWMutex mu
+NewCollection(name, dim, metric, store, useHNSW)
+NewCollectionWithParams(name, dim, metric, store, useHNSW, params)
+Upsert(points) error
+Search(query, filter, topK) []ScoredPoint
+Delete(points, filter) int
+Count() int
}
class UpsertProcess {
+Validate vector dimension
+Set version number
+Persist to disk
+Update in-memory index
+Error rollback
}
class SearchProcess {
+Validate query vector dimension
+Read lock protection
+Delegate to index layer
}
class DeleteProcess {
+Determine delete target IDs
+Delete disk data first
+Then delete from in-memory index
+Count successful deletions
}
Collection --> UpsertProcess : contains
Collection --> SearchProcess : contains
Collection --> DeleteProcess : contains
Index Layer Analysis¶
The index layer implements the VectorIndex interface, providing two different index strategies:
HNSW Index Implementation¶
HNSW (Hierarchical Navigable Small World) is an efficient graph-structured index:
flowchart TD
HNSWStart([HNSW Initialization]) --> ConfigDist["Configure distance function
Cosine/Euclid/Dot"]
ConfigDist --> SetParams["Set HNSW parameters
M, EfConstruction, EfSearch"]
SetParams --> GraphInit["Initialize hnsw.Graph"]
GraphInit --> UpsertNodes["Batch add nodes"]
UpsertNodes --> UpdateMap["Update metadata map"]
SearchStart([Search start]) --> OverFetch["Over-fetch strategy
fetchK = topK * 10"]
OverFetch --> HNSWSearch["HNSW graph search"]
HNSWSearch --> PostFilter["Post-filter (payload)"]
PostFilter --> CalcScore["Exact score calculation"]
CalcScore --> ReturnResults["Return TopK results"]
DeleteStart([Delete start]) --> DeleteFromGraph["Delete node from graph"]
DeleteFromGraph --> DeleteFromMap["Delete metadata from map"]
DeleteFromMap --> DeleteComplete([Delete complete])
Flat Index Implementation¶
Flat index provides exact but inefficient brute-force search:
Storage Layer Analysis¶
The storage layer provides persistence capability based on bbolt, supporting vector quantization compression:
erDiagram
COLLECTION {
string name PK
int vector_len
enum metric
bool use_hnsw
json hnsw_params
}
POINT {
string id PK
float32[] vector
json payload
uint64 version
}
META_BUCKET {
string name PK
json collection_meta
}
COLLECTION ||--o{ POINT : contains
META_BUCKET ||--|| COLLECTION : metadata_for
Technical Trade-off Analysis¶
Why choose HNSW index over other algorithms?¶
- Performance advantage: HNSW provides O(log N) search complexity, significant performance improvement over flat index's O(n)
- Industrial maturity: HNSW has been verified in multiple production environments with reliable stability
- Tunability: Parameters like M, EfConstruction, EfSearch can be optimized for different scenarios
- Memory efficiency: HNSW's hierarchical structure is more memory-efficient compared to full graph structures
Why use embedded storage?¶
- Simple deployment: No additional database service required, runs as single file
- High reliability: Transaction-based operations using bbolt ensure data consistency
- Cross-platform: Pure Go implementation, supports multi-platform compilation
- Zero dependencies: Avoids complex C/C++ dependency issues
Dependency Analysis¶
External Dependencies¶
GoVector's external dependencies are relatively simple, mainly including three core libraries:
graph TB
GOVECTOR[GoVector Core Code]
subgraph "External Dependencies"
HNSW[coder/hnsw
HNSW graph index implementation]
BBOLT[go.etcd.io/bbolt
Embedded key-value storage]
PROTOBUF[google.golang.org/protobuf
Protocol Buffers]
end
GOVECTOR --> HNSW
GOVECTOR --> BBOLT
GOVECTOR --> PROTOBUF
Internal Module Dependencies¶
graph TD
MAIN[cmd/govector/main.go] --> API[api/server.go]
MAIN --> CORE[core/collection.go]
API --> CORE
CORE --> INDEX[core/index.go]
INDEX --> HNSW[core/hnsw_index.go]
INDEX --> FLAT[core/flat_index.go]
CORE --> STORAGE[core/storage.go]
STORAGE --> QUANT[core/quantization.go]
CORE --> MODELS[core/models.go]
Performance Considerations¶
Index Performance Comparison¶
Based on benchmark data from project documentation:
| Index Type | Scale (N) | Build Time | Avg Latency | Throughput (QPS) | Memory Usage |
|---|---|---|---|---|---|
| Flat | 100K | 186ms | 54.46ms | 18 QPS | 59MB |
| HNSW | 100K | 20.9s | 0.08ms | 11,812 QPS | 311MB |
| HNSW | 1M | 4m 17s | 0.11ms | 8,709 QPS | 3.32GB |
Quantization Compression Effect¶
The system supports SQ8 8-bit scalar quantization, which can significantly reduce storage space:
- Compression ratio: Each dimension reduced from 4 bytes to 1 byte + 8 bytes metadata
- Precision loss: Controlled through minimum and maximum value range, maintaining reasonable precision
- Performance impact: Quantization performed on load, does not affect query performance
Troubleshooting Guide¶
Common Problems and Solutions¶
1. Collection creation failed¶
Symptoms: Error when creating collection Possible causes: - Collection name already exists - Invalid vector dimension - Unsupported distance metric - Storage initialization failed
Solutions: - Check collection name uniqueness - Verify vector dimension must be positive - Confirm distance metric string is correct - Check database file permissions
2. Data persistence exception¶
Symptoms: Data lost after Upsert operation Possible causes: - Storage layer write failed - Memory index updated then rolled back - Database connection interrupted
Solutions: - Check disk space and permissions - Verify database file integrity - Check storage layer error logs
3. Abnormal search results¶
Symptoms: Search results empty or inaccurate Possible causes: - Query vector dimension mismatch - Filter conditions too strict - HNSW parameters improperly configured
Solutions: - Confirm query vector dimension matches collection - Adjust filter conditions - Optimize HNSW parameters (M, EfSearch)
Conclusion¶
GoVector successfully encapsulates complex vector search functionality into an easy-to-use embedded database through a clear four-layer architecture design. Its core advantages include:
- Clear architecture: Layered decoupling makes the system easy to understand and maintain
- Excellent performance: HNSW index provides near-real-time search performance
- Simple deployment: Single-file deployment, zero-dependency operation
- Complete functionality: Supports complete vector search, filtering and persistence
This architecture provides ideal infrastructure for building local AI applications, desktop programs and edge computing scenarios, meeting performance requirements while maintaining development convenience.