项目概述¶
GoVector 是一款用纯 Go 编写的轻量级、可嵌入向量数据库,定位为“向量界的 SQLite”。它面向本地 AI、桌面应用与边缘计算场景,提供:
- 与 Qdrant 兼容的 REST API
- HNSW 图索引实现近似最近邻检索(ANN),支持 O(log N) 搜索复杂度
- 基于 BoltDB 的 Protobuf 持久化,支持重启后自动发现与加载集合
- 内置 SQ8 8 位标量量化,显著降低磁盘占用
- 双模式运行:嵌入式库(零网络开销)与独立微服务(Qdrant 兼容)
项目已通过全面审计,测试覆盖率达 92% 以上,在百万级规模下仍能保持亚毫秒级延迟,远超传统暴力索引。
项目结构¶
仓库采用按功能域分层的组织方式:
- cmd:命令行入口与基准测试
- cmd/govector:独立服务入口
- cmd/bench:大规模性能基准
- core:核心引擎(集合、索引、存储、模型、量化)
- api:Qdrant 兼容 HTTP API 层
- example:嵌入式使用示例
- scripts:构建与发布脚本
- 根目录:README、go.mod、Makefile 等
graph TB
subgraph "命令行"
S["cmd/govector/main.go"]
B["cmd/bench/main.go"]
end
subgraph "核心引擎 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 层"
A["api/server.go"]
end
subgraph "示例"
E["example/embedded/main.go"]
end
S --> A
A --> C
C --> H
C --> ST
ST --> Q
E --> C
B --> C
核心组件¶
- 集合 Collection:封装固定维度、指定距离度量的向量集合;统一提供 Upsert/Search/Delete;线程安全;支持持久化与内存索引双写一致性。
- HNSWIndex:基于 coder/hnsw 的图索引,支持余弦、欧氏、点积;提供批量插入、近似搜索、删除、按过滤器取 ID 等能力。
- Storage:基于 bbolt 的本地持久化,使用 Protobuf 序列化点;支持集合元数据、批量读写、删除、列表集合;可选 SQ8 量化。
- API Server:提供 /collections、/points、/search 等 Qdrant 风格 REST 接口;支持启动时从存储加载集合;优雅关闭。
- 模型与过滤:PointStruct、ScoredPoint、Filter、Condition 等,支持精确匹配、范围、前缀、包含、正则等多种过滤。
- 量化:SQ8 量化器接口与实现,压缩/解压向量,降低磁盘占用。
架构总览¶
GoVector 采用“存储引擎 + 索引引擎 + API 层”的分层设计: - 存储层:BoltDB + Protobuf,保证数据持久化与跨版本兼容 - 索引层:扁平索引(内存)与 HNSW 图索引(内存+图),按需选择 - API 层:HTTP 服务暴露 Qdrant 风格接口,支持嵌入式与独立服务两种模式 - 量化层:可选 SQ8 量化,减少磁盘占用
graph TB
subgraph "客户端"
U["应用/SDK"]
end
subgraph "API 层"
HTTP["HTTP 服务
/collections /points /search"]
end
subgraph "核心引擎"
COL["Collection
Upsert/Search/Delete"]
IDX["HNSWIndex/FlatIndex"]
ST["Storage
BoltDB + Protobuf"]
QUAN["SQ8 量化"]
end
U --> HTTP
HTTP --> COL
COL --> IDX
COL --> ST
ST --> QUAN
详细组件分析¶
API 服务工作流(启动与请求处理)¶
sequenceDiagram
participant CLI as "命令行"
participant Srv as "API Server"
participant Col as "Collection"
participant Idx as "VectorIndex(HNSW/Flat)"
participant St as "Storage"
CLI->>Srv : 启动服务(绑定地址)
Srv->>St : 加载集合元数据
St-->>Srv : 返回集合配置
Srv->>Col : 重建集合实例
Note over Srv : 服务就绪
CLI->>Srv : POST /collections
Srv->>Col : 创建集合(可选HNSW参数)
Col->>St : 保存集合元数据
Srv-->>CLI : 返回创建结果
CLI->>Srv : PUT /collections/{name}/points
Srv->>Col : Upsert(先落盘再更新索引)
Col->>St : 写入点(可选量化)
Col->>Idx : 更新索引
Srv-->>CLI : 返回成功
CLI->>Srv : POST /collections/{name}/points/search
Srv->>Col : Search(可选过滤)
Col->>Idx : 近似搜索(过采样+后过滤)
Idx-->>Col : 结果集
Col-->>Srv : 格式化返回
Srv-->>CLI : 返回 TopK 结果
HNSW 索引类图¶
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 : "使用"
Collection --> Storage : "持久化"
HNSWIndex --> Storage : "通过ID访问元数据"
查询流程(含过滤策略)¶
flowchart TD
Start(["开始: Search"]) --> CheckDim["校验查询向量维度"]
CheckDim --> Lock["读锁保护索引"]
Lock --> NeedFilter{"是否需要过滤?"}
NeedFilter --> |否| Fetch["HNSW 近似搜索(过采样)"]
NeedFilter --> |是| OverFetch["扩大取回数量(过采样)"]
OverFetch --> Fetch
Fetch --> FilterLoop["遍历候选并应用过滤"]
FilterLoop --> ScoreCalc["按度量重新计算分数"]
ScoreCalc --> TopK["取 TopK 结果"]
TopK --> Unlock["释放读锁"]
Unlock --> End(["结束: 返回结果"])
嵌入式使用示例(零网络开销)¶
- 初始化本地存储
- 创建集合(自动持久化元数据)
- 直接 Upsert 点(Go 结构体,无 HTTP 开销)
- 执行带过滤的搜索
- 直接获得原生 Go 对象结果
依赖分析¶
- 外部依赖
- coder/hnsw:HNSW 图索引实现
- go.etcd.io/bbolt:嵌入式键值数据库
- google.golang.org/protobuf:消息序列化
- 内部模块
- core:核心引擎
- api:HTTP API
- cmd/govector:服务入口
- cmd/bench:基准测试
- example/embedded:嵌入式示例
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
性能考量¶
- 大规模基准(128 维,Cosine,TopK=10)
- Flat 索引:10 万规模构建约 186ms,平均延迟 ~54.46ms,QPS 约 18
- HNSW 索引:10 万规模构建约 20.9s,平均延迟 ~0.08ms,QPS 约 11,812
- HNSW 索引:100 万规模构建约 4 分 17 秒,平均延迟 ~0.11ms,QPS 约 8,709
- 关键优化点
- HNSW 参数可调(M、EfConstruction、EfSearch、K)
- 过采样 + 后过滤策略平衡过滤场景下的准确性与性能
- SQ8 量化显著降低磁盘占用,适合大规模数据
- 存储与索引双写一致性,确保高可靠
故障排查指南¶
- 服务启动失败
- 检查数据库路径权限与可写性
- 查看存储初始化错误日志
- 请求 404/400/500
- 确认集合存在且名称正确
- 检查请求体 JSON 格式与字段
- 检查向量维度与集合配置一致
- 搜索结果异常
- 确认过滤条件语法正确
- HNSW 参数是否合理(EfSearch、K)
- 数据不一致
- Upsert 失败会尝试回滚存储写入
- 检查存储关闭状态与并发访问
结论¶
GoVector 将“向量版 SQLite”的理念落地为生产可用的嵌入式向量数据库:纯 Go、CGO 无关、跨平台、易部署;通过 HNSW 索引与 BoltDB 持久化,兼顾性能与可靠性;提供 Qdrant 兼容 API 与嵌入式库两种使用模式,满足本地 AI、桌面应用与边缘计算的多样化需求。配合 SQ8 量化与完善的测试覆盖,可在不同规模数据下稳定运行并持续演进。
[无章节来源——本节为总结性内容]
附录¶
- 快速开始
- 嵌入式库:参考示例工程
- 独立服务:命令行启动,绑定端口与数据库路径
- 基准测试:一键运行大规模性能测试
- 构建与发布
- Makefile 提供 build/run/release/clean 等目标
-
交叉编译与打包由脚本完成