内积检索是什么
内积(点积)等于两向量模长之积再乘上夹角余弦:方向越一致、模长越大,得分越高。这让内积同时受方向和长度影响,所以直接用它排序时,长文档向量常常只是因为模长大就排到前面。工程上的通行做法是先把向量归一化到单位长度,此时内积与余弦完全等价,分数落在 -1 到 1;或者使用本身就会归一化的度量配置。各库对内积的表达方式不同,有的返回相似度(越大越相似),有的返回负内积当距离(越小越相似)。
基本信息
| 定义 | a·b = ‖a‖‖b‖cosθ |
|---|---|
| 取值范围 | 未归一化时无上界,归一化后为 -1~1 |
| FAISS | IndexFlatIP 按内积检索,需自行归一化 |
| Qdrant | distance=Dot,返回相似度,越大越相似 |
| pgvector | 运算符 <#> 返回负内积,ORDER BY 取最小值 |
典型使用场景
- 自建轻量检索:FAISS IndexFlatIP 配归一化向量,等价余弦且计算更省
- 已归一化的向量库选型:直接用内积度量避免重复计算范数
- 排查排序异常:计算同一对的余弦与内积,若排序不一致说明存在未归一化向量
- 跨库迁移:从 Qdrant 的 Dot 迁到 pgvector 时,注意符号与排序方向相反
- 权重化召回:需要按文档重要度加权时,刻意保留模长差异作为权重来源
内积与模长
内积与模长
import numpy as np
a = np.array([0.3, 0.4, 0.5], dtype='float32')
b = np.array([0.1, 0.9, 0.2], dtype='float32')
ip = float(a @ b) # 内积
cos = ip / (np.linalg.norm(a) * np.linalg.norm(b)) # 余弦 = 内积 / 模长积
print(ip, cos)
print(float((a / np.linalg.norm(a)) @ (b / np.linalg.norm(b)))) # 归一化后两者相等各库内积语义对照
| 库 | 表达方式 | 排序方向 |
|---|---|---|
| FAISS | IndexFlatIP | 得分越大越相似 |
| Qdrant | distance=Dot | 相似度越大越相似 |
| pgvector | <#> 负内积 | 值越小越相似,注意负号 |
| Elasticsearch | dot_product 相似度 | 得分越大越相似 |
把内积分数直接展示给用户时先确认符号与量纲:pgvector 的 <#> 输出是负值,未归一化的内积则没有固定上界,两种都不适合当作“相似度百分比”。