相似度与距离度量
问题
向量检索中有哪些常用的相似度计算方法?它们各自适用什么场景?
答案
一、三种主要度量方式
| 度量 | 公式 | 值域 | 含义 |
|---|---|---|---|
| 余弦相似度 | [-1, 1] | 方向相似性 | |
| 欧氏距离 | [0, ∞) | 空间距离 | |
| 点积 | (-∞, +∞) | 方向 + 幅度 |
二、余弦相似度
最常用的 Embedding 相似度度量,只关注向量方向,不关注大小:
import numpy as np
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# 示例:语义相似的句子余弦相似度高
v1 = embed("如何退款") # [0.12, 0.85, ...]
v2 = embed("退货退款流程") # [0.11, 0.83, ...]
v3 = embed("Python 教程") # [0.72, 0.05, ...]
cosine_similarity(v1, v2) # ≈ 0.92(语义相近)
cosine_similarity(v1, v3) # ≈ 0.15(语义不相关)
为什么余弦相似度最常用?
大多数 Embedding 模型在训练时已对输出向量做了归一化(L2 norm = 1),此时余弦相似度等价于点积,计算更高效。
三、欧氏距离
衡量两个向量在空间中的绝对距离:
- 距离越小 → 越相似
- 对向量的幅度敏感:即使方向一致,长度不同也会导致距离大
- 适合向量已归一化的场景(归一化后等价于余弦距离)
四、点积(Inner Product / Dot Product)
- 同时考虑方向和幅度
- 向量归一化后,点积 = 余弦相似度
- MaxSim(ColBERT 等 late-interaction 模型)使用点积
五、三者关系
当向量已归一化()时:
面试重点
大多数 Embedding 模型输出已归一化,三种度量在排序结果上完全等价。面试中说清楚"归一化后等价"即可。
六、选择建议
| 场景 | 推荐度量 | 理由 |
|---|---|---|
| 语义检索(默认) | 余弦相似度 | 不受向量长度干扰 |
| 归一化向量 | 点积 | 计算最快(无需除法) |
| 推荐系统 | 点积 | 向量幅度可表示热度/权重 |
| 图像特征匹配 | 欧氏距离 | 空间距离有物理意义 |
常见面试问题
Q1: 余弦相似度和点积有什么区别?什么时候等价?
答案:
- 余弦相似度只衡量方向,点积同时衡量方向和幅度
- 当向量 L2 归一化后,二者完全等价
- 大多数 Embedding 模型默认输出归一化向量,所以实践中常用点积(更快)
Q2: 为什么向量数据库默认使用余弦相似度?
答案:
- 语义检索关注的是语义方向,而非向量绝对大小
- 余弦相似度天然忽略幅度,更符合语义匹配直觉
- 即使模型输出未归一化,余弦相似度也能正确工作
Q3: 向量检索中如何提高计算效率?
答案:
- 归一化后用点积替代余弦相似度(省去归一化计算)
- 降维:PCA 或 Matryoshka Embedding 减少维度
- 量化:将 float32 量化为 int8(参考 Embedding 优化)
- 近似搜索:HNSW、IVF 等索引算法(参考 向量数据库)