跳转至

存储引擎

GoVector 的存储引擎负责将向量数据持久化到磁盘并将其加载回内存。本文档解释存储引擎的工作原理以及如何针对您的用例进行优化。

📋 存储概述

GoVector 使用多种技术组合实现高效存储:

  • BoltDB - 用于持久存储的嵌入式键值存储
  • Protocol Buffers - 用于向量数据的高效序列化格式
  • SQ8 量化 - 用于内存优化的可选 8 位标量量化

🔧 存储架构

数据流

flowchart TD
    A[Go 结构体] --> B[Protocol Buffers]
    B --> C[可选 SQ8 量化]
    C --> D[BoltDB 存储]
    D --> E[BoltDB 检索]
    E --> F[可选解量化]
    F --> G[Protocol Buffers]
    G --> H[Go 结构体]

组件

  1. Protocol Buffers:将 Go 结构体序列化为紧凑的二进制格式
  2. BoltDB:将序列化数据存储在事务性键值存储中
  3. SQ8 量化:在启用时将向量压缩为 8 位整数

🚀 持久化

保存集合

// 保存集合到磁盘
if err := collection.Save("/path/to/collection"); err != nil {
    log.Fatalf("保存集合失败: %v", err)
}

加载集合

// 从磁盘加载集合
loadedCollection, err := core.LoadCollection("/path/to/collection")
if err != nil {
    log.Fatalf("加载集合失败: %v", err)
}

📊 存储格式

集合目录结构

/path/to/collection/
├── metadata.json       # 集合配置
├── points.db           # 点的 BoltDB 数据库
└── index/             # 索引文件(HNSW 图)

元数据格式

{
  "name": "my-collection",
  "vector_len": 768,
  "metric": "Cosine",
  "index_type": "HNSW",
  "quantize": false,
  "hnsw_config": {
    "m": 16,
    "ef_construction": 200,
    "ef_search": 10
  }
}

💡 性能优化

对于写入性能

  • 批处理操作:对多个点使用批量写入
  • 禁用量化:对于写入密集型工作负载,考虑禁 SQ8 量化
  • SSD 存储:使用 SSD 以获得更快的写入操作

对于读取性能

  • 启用量化:SQ8 量化减少磁盘 I/O 和内存使用
  • 内存映射:BoltDB 使用内存映射以获得更快的读取
  • 缓存预热:加载集合后,执行几次搜索操作以预热缓存

对于存储效率

  • 启 SQ8 量化:减少约 75% 的向量存储
  • 优化 Payload:保持 payload 小,避免存储大型对象
  • 定期压缩:BoltDB 自动压缩数据,但大量删除可能需要手动压缩

📈 存储需求

向量存储

向量大小 精度 每 1M 向量的存储
768 维 Float32(4 字节) ~3GB
768 维 SQ8(1 字节) ~750MB
384 维 Float32(4 字节) ~1.5GB
384 维 SQ8(1 字节) ~375MB

开销

  • BoltDB:事务功能约 10-15% 的开销
  • Protocol Buffers:最小开销(< 5%)
  • 索引文件:HNSW 索引根据 M 参数增加约 20-30% 的开销

🚩 常见问题

保存/加载缓慢

  • 原因:集合大小过大或磁盘速度慢
  • 解决方案:使用 SSD 存储,启 SQ8 量化,考虑较小的批处理大小

数据库损坏

  • 原因:意外关闭或磁盘错误
  • 解决方案:定期备份,使用日志文件系统(ext4、APFS),实现适当的错误处理

磁盘使用高

  • 原因:大型向量或 payload,未启量化
  • 解决方案:启 SQ8 量化,优化 payload 大小,考虑使用较小的向量

🔗 相关文档