向量数据库核心概念
深入理解向量数据库的工作原理,掌握向量化、相似度计算和索引算法的核心知识。
向量化(Vectorization)
向量化是将非结构化数据转换为数值向量的过程,这是使用向量数据库的第一步。
什么是 Embedding
Embedding(嵌入)是机器学习中的一种技术,将高维稀疏的数据映射到低维稠密的向量空间。在这个向量空间中,语义相似的数据点距离较近。
关键特性:
- 语义保持:语义相似的文本,其向量距离也近
- 维度固定:无论输入长度如何,输出维度固定
- 可计算:向量间可以进行数学运算
文本向量化示例
from sentence_transformers import SentenceTransformer
# 加载预训练模型
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
# 文本向量化
texts = [
"猫在沙发上睡觉",
"小狗在院子里玩耍",
"猫咪正在打盹"
]
embeddings = model.encode(texts)
print(f"向量维度: {embeddings.shape}")
# 输出: 向量维度: (3, 384)
# 查看第一个文本的向量(前5个值)
print(f"第一个文本的向量: {embeddings[0][:5]}")
# 输出: [ 0.0234 -0.1567 0.7891 ... ]
嵌入模型选择
| 模型 | 维度 | 语言 | 特点 | 适用场景 |
|---|---|---|---|---|
| text-embedding-3-small | 1536 | 多语言 | OpenAI,性价比高 | 通用场景 |
| text-embedding-3-large | 3072 | 多语言 | OpenAI,高性能 | 高精度需求 |
| all-MiniLM-L6-v2 | 384 | 英文 | 轻量快速 | 资源受限 |
| paraphrase-multilingual-MiniLM-L12-v2 | 384 | 多语言 | 支持中文 | 中文场景 |
| BGE-large-zh | 1024 | 中文 | 中文最优 | 中文专业场景 |
| M3E-base | 768 | 中文 | 开源中文模型 | 中文开源方案 |
多模态向量化
除了文本,图像、音频也可以向量化:
# 图像向量化示例(使用 CLIP)
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
image = Image.open("cat.jpg")
inputs = processor(images=image, return_tensors="pt")
image_features = model.get_image_features(**inputs)
print(f"图像向量维度: {image_features.shape}")
# 输出: torch.Size([1, 512])
相似度度量
相似度度量是向量数据库的核心,决定了如何比较两个向量的相似程度。
余弦相似度(Cosine Similarity)
最常用且效果最好的相似度度量方法。
公式:
cos(θ) = (A · B) / (||A|| × ||B||)
其中:
- A · B 表示向量点积
- ||A|| 表示向量 A 的欧几里得范数(模长)
特点:
- 范围 [-1, 1],通常归一化后范围 [0, 1]
- 只考虑方向,不考虑长度
- 对文本语义相似度衡量效果最佳
import numpy as np
def cosine_similarity(a, b):
"""计算余弦相似度"""
dot_product = np.dot(a, b)
norm_a = np.linalg.norm(a)
norm_b = np.linalg.norm(b)
return dot_product / (norm_a * norm_b)
# 示例
vec1 = np.array([1, 2, 3])
vec2 = np.array([1, 2, 3])
vec3 = np.array([-1, -2, -3])
print(cosine_similarity(vec1, vec2)) # 1.0(完全相同)
print(cosine_similarity(vec1, vec3)) # -1.0(完全相反)
欧几里得距离(Euclidean Distance)
衡量向量空间中的直线距离。
公式:
d(A, B) = √Σ(Ai - Bi)²
特点:
- 范围 [0, +∞)
- 考虑向量的绝对位置
- 适合物理空间或几何数据的相似度计算
def euclidean_distance(a, b):
"""计算欧几里得距离"""
return np.sqrt(np.sum((a - b) ** 2))
# 距离越小越相似
dist = euclidean_distance(vec1, vec2)
similarity = 1 / (1 + dist) # 转换为相似度
点积(Dot Product)
最简单的相似度计算方法。
公式:
A · B = Σ(Ai × Bi)
特点:
- 无固定范围
- 同时考虑方向和长度
- 归一化后等价于余弦相似度
def dot_product(a, b):
"""计算点积"""
return np.dot(a, b)
相似度度量对比
| 度量方法 | 是否考虑长度 | 范围 | 最佳场景 |
|---|---|---|---|
| 余弦相似度 | 否 | [-1, 1] | 文本语义搜索 |
| 欧几里得距离 | 是 | [0, +∞) | 几何/物理数据 |
| 点积 | 是 | 无限制 | 已归一化向量 |
实践建议:
- 文本搜索优先使用余弦相似度
- 如果向量已经归一化,点积和余弦相似度等价
- 欧几里得距离在特定场景(如图像特征)可能效果更好
近似最近邻(ANN)算法
当向量数量达到百万、亿级别时,精确搜索的 O(n) 时间复杂度无法接受。ANN 算法通过牺牲少量精度换取显著的搜索速度提升。
算法对比
| 算法 | 时间复杂度 | 空间复杂度 | 精度 | 特点 |
|---|---|---|---|---|
| Flat | O(n) | O(n) | 100% | 暴力搜索,仅适合小规模 |
| IVF | O(√n) | O(n) | 90-99% | 倒排索引,平衡选择 |
| HNSW | O(log n) | O(n) | 95-99% | 图索引,速度最快 |
| PQ | O(1) | O(n/k) | 70-90% | 量化压缩,内存友好 |
HNSW(Hierarchical Navigable Small World)
目前最流行的 ANN 算法,基于图索引结构。
核心思想
构建一个多层图结构:
- 上层:稀疏的长连接,类似"高速公路"
- 下层:密集的短连接,类似"街道"
搜索时从顶层开始快速定位大致区域,然后在下层精确搜索。
构建过程
1. 每个新节点随机决定插入到哪几层
- 第0层概率: 1
- 第1层概率: 1/2
- 第2层概率: 1/4
- ...(概率逐层减半)
2. 在每一层中:
- 找到与新节点最接近的 M 个邻居
- 建立双向连接
3. 层数越高,节点越稀疏
搜索过程
1. 从顶层随机节点开始
2. 在当前层贪婪搜索:
- 找到距离查询点最近的节点
3. 下降到下一层:
- 以上一层的结果为起点
4. 在最底层返回 K 个最近邻
HNSW 参数调优
| 参数 | 说明 | 建议值 |
|---|---|---|
| M | 每层最大连接数 | 16-64,越大精度越高 |
| efConstruction | 构建时的搜索范围 | 100-500,越大构建越慢但精度越高 |
| ef | 查询时的搜索范围 | 大于 top_k,越大精度越高 |
# HNSW 索引配置示例(Milvus)
index_params = {
"metric_type": "COSINE",
"index_type": "HNSW",
"params": {
"M": 16, # 最大连接数
"efConstruction": 200 # 构建搜索范围
}
}
# 查询参数
search_params = {
"metric_type": "COSINE",
"params": {"ef": 64} # 查询搜索范围
}
IVF(Inverted File Index)
基于聚类的索引方法。
核心思想
- 使用 K-means 将向量空间划分为 nlist 个簇
- 每个向量归属到最近的簇中心
- 查询时只搜索最近的 nprobe 个簇
构建过程
1. 随机选择 nlist 个中心点
2. 迭代优化中心点位置(K-means)
3. 将每个向量分配到最近的中心点
4. 建立倒排列表:中心点 → 向量列表
搜索过程
1. 计算查询向量与所有中心点的距离
2. 选择距离最近的 nprobe 个中心点
3. 只在这些中心点对应的向量中搜索
4. 返回 top_k 个最近邻
IVF 参数调优
| 参数 | 说明 | 建议值 |
|---|---|---|
| nlist | 聚类中心数 | 4×√n,n 为向量总数 |
| nprobe | 查询时搜索的簇数 | 10-100,越大精度越高 |
# IVF 索引配置示例
index_params = {
"metric_type": "L2",
"index_type": "IVF_FLAT",
"params": {"nlist": 128} # 聚类中心数
}
search_params = {
"metric_type": "L2",
"params": {"nprobe": 10} # 搜索簇数
}
PQ(Product Quantization)
乘积量化,用于压缩向量存储。
核心思想
将高维向量分割成多个子向量,对每个子向量单独量化,大幅降低存储空间。
量化过程
原始向量: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8] (8维)
↓ 分割为 4 个子向量
子向量1: [0.1, 0.2]
子向量2: [0.3, 0.4]
子向量3: [0.5, 0.6]
子向量4: [0.7, 0.8]
↓ 每个子向量量化到最近的码本中心
量化结果: [code1, code2, code3, code4] (每个code 1字节)
PQ 参数
| 参数 | 说明 | 建议值 |
|---|---|---|
| m | 分割段数 | 向量维度/4 |
| nbits | 每段量化位数 | 8 |
压缩比:原始 1024 维 float32 向量需要 4KB,PQ 压缩后仅需 256 字节(m=32, nbits=8)。
索引选择建议
| 数据规模 | 推荐索引 | 理由 |
|---|---|---|
| < 10万 | FLAT | 精确搜索,无需索引 |
| 10万-100万 | IVF_FLAT | 平衡速度和精度 |
| 100万-1000万 | HNSW | 快速搜索,高精度 |
| > 1000万 | IVF_PQ 或 HNSW | 考虑内存使用 |
| 内存受限 | PQ 系列 | 压缩存储 |
向量数据库架构
核心组件
┌─────────────────────────────────────────────────────────┐
│ 向量数据库系统 │
├─────────────┬─────────────┬─────────────┬───────────────┤
│ 接入层 │ 存储层 │ 索引层 │ 查询层 │
├─────────────┼─────────────┼─────────────┼───────────────┤
│ • REST API │ • 原始数据 │ • HNSW │ • 相似度计算 │
│ • SDK │ • 向量数据 │ • IVF │ • 结果排序 │
│ • 协议适配 │ • 元数据 │ • PQ │ • 过滤聚合 │
└─────────────┴─────────────┴─────────────┴───────────────┘
数据组织
Collection(集合):逻辑上的数据表,包含:
- 向量字段(固定维度)
- 标量字段(元数据,用于过滤)
- 索引配置
Partition(分区):集合的物理分片,用于:
- 数据隔离(多租户)
- 查询优化(分区裁剪)
- 数据管理(按时间归档)
写入流程
1. 数据验证
- 检查向量维度
- 验证标量字段类型
2. 向量编码(如果使用 PQ)
- 分割向量
- 量化到码本
3. 索引更新
- 插入到图结构(HNSW)
- 或分配到聚类中心(IVF)
4. 数据持久化
- 写入日志(WAL)
- 刷盘到存储
查询流程
1. 请求解析
- 解析查询向量
- 解析过滤条件
- 解析 top_k
2. 索引检索(ANN)
- 在索引中搜索候选集
- 返回多于 top_k 的候选结果
3. 精确计算
- 对候选集计算精确相似度
- 应用过滤条件
4. 结果排序与返回
- 按相似度排序
- 截取 top_k
- 返回结果
性能优化
索引优化
-
选择合适的索引类型
- 小规模数据:无需索引或 FLAT
- 大规模数据:HNSW(速度优先)或 IVF(内存优先)
-
参数调优
- HNSW:增大 M 和 efConstruction 提升精度
- IVF:增大 nprobe 提升精度
查询优化
-
使用过滤条件
- 先过滤标量字段,减少向量搜索范围
- 利用分区裁剪
-
批量查询
- 合并多个查询请求,摊平网络开销
-
结果缓存
- 缓存热门查询结果
硬件优化
-
内存配置
- 确保热数据可放入内存
- 使用内存映射文件处理超大数据
-
GPU 加速
- 部分数据库支持 GPU 加速(如 Faiss)
- 适合批量查询场景
常见问题
Q: 向量维度越高越好吗?
不是。维度越高:
- 优点:表达能力更强,语义更精确
- 缺点:存储成本增加,计算量增大,可能出现过拟合
建议:
- 一般文本:384-768 维
- 高精度需求:1024-1536 维
- 资源受限:256-384 维
Q: 如何处理动态数据(增删改)?
不同数据库策略不同:
- Pinecone:自动处理,无需关心
- Milvus:支持增量更新,删除为软删除
- HNSW:增量插入友好,但删除需要重建
Q: 向量数据库和传统数据库的向量扩展有什么区别?
| 特性 | 专用向量数据库 | 传统数据库扩展 |
|---|---|---|
| 性能 | 专为向量优化 | 通用设计 |
| 扩展性 | 分布式架构 | 单机或主从 |
| 功能 | 丰富的 ANN 算法 | 通常只支持基础算法 |
| 适用规模 | 亿级以上 | 百万级以下 |