共计 2578 个字符,预计需要花费 7 分钟才能阅读完成。
为什么需要向量数据库?
传统关系型数据库在处理结构化数据时表现出色,但当面对高维向量数据(比如图像特征、文本嵌入)时就会遇到瓶颈:

- 无法高效执行相似度搜索(” 找到与这张图片最相似的 10 张图片 ”)
- 缺乏专门的索引结构优化向量查询
- 对向量运算的原生支持有限
以电商推荐系统为例,当我们把商品描述转换为 300 维的嵌入向量后,传统数据库根本无法高效完成 ” 找相似商品 ” 这种核心需求。
核心概念解析
向量嵌入(Embedding)
- 将现实世界对象(文本、图像等)通过 AI 模型转换为固定长度的数值向量
- 例如用 BERT 将 ” 智能手机 ” 转换为 768 维向量:[0.24, -0.56, …, 0.78]
- 关键特性:语义相似的物品在向量空间中距离更近
相似度计算
-
余弦相似度:测量向量之间的夹角
public static float CosineSimilarity(float[] a, float[] b) { float dot = 0, magA = 0, magB = 0; for (int i = 0; i < a.Length; i++) {dot += a[i] * b[i]; magA += a[i] * a[i]; magB += b[i] * b[i]; } return dot / (MathF.Sqrt(magA) * MathF.Sqrt(magB)); } -
欧式距离:直接计算向量间的直线距离
public static float EuclideanDistance(float[] a, float[] b) { float sum = 0; for (int i = 0; i < a.Length; i++) sum += MathF.Pow(a[i] - b[i], 2); return MathF.Sqrt(sum); }
近似最近邻(ANN)
- 精确计算所有向量距离的复杂度是 O(N),不可扩展
- ANN 算法(如 HNSW、IVF)通过牺牲少量精度换取百倍速度提升
实现简易内存向量数据库
数据结构设计
public class VectorItem<T>
{public string Id { get; set;}
public float[] Vector { get; set;}
public T Metadata {get; set;} // 可存储原始对象
}
public class SimpleVectorDB<T>
{private readonly List<VectorItem<T>> _items = new();
private readonly Func<float[], float[], float> _similarityFunc;
// 支持注入不同的相似度算法
public SimpleVectorDB(Func<float[], float[], float> similarityFunc)
{_similarityFunc = similarityFunc;}
}
核心方法实现
// 添加向量
public void Add(string id, float[] vector, T metadata)
{if (vector == null) throw new ArgumentNullException(nameof(vector));
if (_items.Any(x => x.Id == id))
throw new ArgumentException($"ID {id} already exists");
_items.Add(new VectorItem<T>
{
Id = id,
Vector = vector.ToArray(), // 创建副本
Metadata = metadata
});
}
// 相似度查询(暴力搜索)public IEnumerable<(VectorItem<T> Item, float Score)> Search(float[] queryVector,
int limit = 10)
{
return _items
.Select(item => (item, _similarityFunc(queryVector, item.Vector)))
.OrderByDescending(x => x.Item2) // 按相似度降序
.Take(limit);
}
完整使用示例
// 初始化使用余弦相似度
var db = new SimpleVectorDB<Product>(CosineSimilarity);
// 添加示例商品(实际中可能来自 AI 模型)var products = new[]
{new Product("iPhone13", "智能手机", new[] {0.8f, 0.2f, 0.1f}),
new Product("GalaxyS22", "安卓手机", new[] {0.7f, 0.3f, 0.1f}),
new Product("MacBookPro", "笔记本电脑", new[] {0.1f, 0.9f, 0.0f})
};
foreach (var p in products)
db.Add(p.Id, p.Vector, p);
// 查询与 "智能手机" 最相似的商品
var queryVec = new[] {0.9f, 0.1f, 0.0f};
var results = db.Search(queryVec);
foreach (var r in results)
Console.WriteLine($"{r.Item.Id}: {r.Score}");
/* 输出示例:iPhone13: 0.98
GalaxyS22: 0.95
MacBookPro: 0.18
*/
性能优化思考
- 内存问题:
- 100 万个 512 维向量 ≈ 2GB 内存(float32)
-
可考虑使用
Memory<T>和Span<T>减少拷贝 -
查询加速:
- 引入简单的倒排索引(如按第一个维度分桶)
-
实现并行计算(
Parallel.For) -
持久化方案:
- 使用 MemoryMappedFile 处理大型数据集
- 实现简单的 LSM 树结构
何时需要专业向量数据库?
当出现以下情况时建议考虑 Milvus 等专业方案:
- 数据量超过 100 万条
- 需要分布式架构
- 要求 99.9% 的查询延迟 <100ms
- 需要高级索引类型(HNSW、IVF-PQ)
下一步学习建议
- 尝试用 SIMD 指令优化相似度计算
- 学习 HNSW 索引的 C# 实现(如 SparnnSharp)
- 在 Azure 上部署 Milvus 服务
- 用 ONNX Runtime 集成向量生成模型
实践挑战
- 扩展当前实现支持批量导入 / 导出功能
- 为向量添加过期时间(TTL)特性
- 实现基于 REST API 的远程查询接口
小贴士:在生产环境中,建议先使用专业向量数据库的原生 SDK,等充分理解原理后再考虑自研方案。
正文完
