数据模型¶
GoVector 的数据模型设计与 Qdrant 兼容,同时提供高效的向量数据存储和检索功能。本文档描述了核心数据结构、它们的关系以及使用最佳实践。
📊 核心数据结构¶
点(Point)¶
点表示带有元数据的单个向量记录。
{
"id": "doc_1",
"vector": [0.1, 0.2, 0.3, /* ... */],
"payload": {
"category": "tech",
"author": "John",
"timestamp": 1620000000,
"tags": ["AI", "vector"]
}
}
字段¶
- id:(必填) 点的唯一标识符
- vector:(必填) 表示向量嵌入的浮点数组
- payload:(可选) 用于过滤和附加上下文的键值元数据
带分数的点(Scored Point)¶
带分数的点是搜索操作返回的结果,包含相似度分数。
字段¶
- id:匹配点的唯一标识符
- score:基于距离度量的相似度分数(对于 Cosine/Dot,值越大越相似;对于 Euclidean,值越小越相似)
- payload:匹配点的元数据
过滤器(Filter)¶
过滤器定义基于点的 payload 进行过滤的条件。
{
"must": [
{
"key": "category",
"type": "exact",
"match": {"value": "tech"}
},
{
"key": "timestamp",
"type": "range",
"range": {"gte": 1620000000, "lte": 1630000000}
}
],
"must_not": [
{
"key": "tags",
"type": "contains",
"match": {"value": "deprecated"}
}
]
}
字段¶
- must:必须满足的条件
- must_not:必须不满足的条件
条件(Condition)¶
条件定义单个过滤条件。
类型¶
- exact:精确值匹配
- range:数值范围比较(gt, gte, lt, lte)
- prefix:字符串前缀匹配
- contains:数组或字符串包含匹配
- regex:字符串正则表达式匹配
🚀 数据生命周期¶
写入(Upsert)¶
- 验证:检查向量维度是否匹配集合配置
- 版本控制:生成版本号用于并发控制
- 持久化:将点序列化为 Protocol Buffers 并写入 BoltDB
- 索引:更新内存索引以实现快速检索
搜索(Search)¶
- 验证:检查查询向量维度
- 索引搜索:使用 HNSW 或 Flat 索引查找近似最近邻
- 过滤:对搜索结果应用 payload 过滤器
- 评分:为过滤后的结果重新计算精确分数
- 结果返回:返回前 K 个结果
删除(Delete)¶
- 目标识别:通过 ID 或过滤器确定要删除的点
- 持久化:从 BoltDB 中移除点
- 索引:从内存索引中移除点
- 结果返回:返回删除的点数
🔧 序列化¶
GoVector 使用 Protocol Buffers 进行向量数据的高效序列化:
- PointStruct:序列化为字节并存储在 BoltDB 中
- 值类型:支持 string、int64、double、bool 和 bytes
- 向后兼容性:使用 proto3 语法确保版本兼容性
📈 距离度量¶
GoVector 支持三种用于相似度计算的距离度量:
| 度量 | 描述 | 相似度解释 |
|---|---|---|
| Cosine | 测量向量之间夹角的余弦值 | 值越大 = 越相似 |
| Euclidean | 测量向量之间的直线距离 | 值越小 = 越相似 |
| Dot | 测量向量的点积 | 值越大 = 越相似 |
注意:余弦相似度是默认度量,推荐用于大多数用例,尤其是使用归一化向量时。
💡 最佳实践¶
点设计¶
- ID:使用稳定、有意义的标识符(例如业务主键)
- 向量:确保维度匹配集合配置;为余弦相似度归一化向量
- Payload:保持元数据简洁;使用适当的类型进行过滤
过滤器使用¶
- Must vs MustNot:优先使用
must缩小结果范围,谨慎使用must_not - 条件类型:对精确匹配使用
exact,对数值范围使用range,对字符串前缀使用prefix,对数组使用contains,对复杂字符串模式使用regex - 性能:避免过于复杂的过滤器,尤其是正则表达式
性能优化¶
- 索引选择:对大规模数据使用 HNSW,对小型数据集使用 Flat
- 量化:对大规模数据启 SQ8 量化以减少存储使用
- 批量操作:使用批量写入多个点以提高性能
- TopK:限制结果数量以减少网络开销
🚩 常见问题¶
维度不匹配¶
- 错误:"dimension mismatch"
- 解决方案:确保向量长度匹配集合的配置维度
过滤器不工作¶
- 可能原因:键名不正确、类型不匹配或键不存在
- 解决方案:验证键名和类型;记住不存在的键会通过
must_not条件
查询缓慢¶
- 可能原因:使用 Flat 索引的大型数据集、复杂过滤器或结果过多
- 解决方案:使用 HNSW 索引,简化过滤器,减少 topK 值
📖 示例用法¶
创建点¶
point := core.PointStruct{
ID: "doc_1",
Vector: []float32{0.1, 0.2, 0.3, /* ... */},
Payload: core.Payload{
"category": "tech",
"author": "John",
},
}
使用过滤器¶
filter := &core.Filter{
Must: []core.Condition{
{
Key: "category",
Type: core.MatchTypeExact,
Match: core.MatchValue{Value: "tech"},
},
},
MustNot: []core.Condition{
{
Key: "author",
Type: core.MatchTypeExact,
Match: core.MatchValue{Value: "Jane"},
},
},
}
带过滤器搜索¶
results, err := collection.Search(queryVector, filter, 10)
for _, result := range results {
fmt.Printf("ID: %s, Score: %.4f, Category: %s\n",
result.ID, result.Score, result.Payload["category"])
}
🎯 结论¶
GoVector 的数据模型提供了一种灵活高效的方式来存储和检索向量数据。通过遵循点设计、过滤器使用和性能优化的最佳实践,您可以构建高性能的向量搜索应用程序,满足您的需求。