共计 1816 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要语义检索?
传统关键词检索(Keyword Search)如 TF-IDF 或 BM25 存在明显的语义鸿沟问题——它们只能匹配字面相同的词汇,却无法理解查询语句的真实意图。比如搜索 ” 苹果 ” 时,传统方法无法区分水果公司还是水果本身,而语义检索(Semantic Search)通过将文本转化为向量(Vector),在向量空间计算相似度,真正实现了 ” 用意思找结果 ”。

传统 VS 向量检索对比
| 对比维度 | TF-IDF/BM25 | 向量检索(Vector Search) |
|---|---|---|
| 匹配方式 | 词频统计 | 语义向量距离计算 |
| 语义理解 | 无 | 深度语义理解 |
| 同义词处理 | 需人工配置同义词库 | 自动识别 |
| 实现复杂度 | 简单 | 需模型训练 |
| 典型应用 | 文档快速过滤 | 问答系统 / 推荐系统 |
数学基础:余弦相似度公式
$$
\text{similarity} = \cos(\theta) = \frac{A \cdot B}{|A| |B|}
$$
核心实现四步走
1. 环境准备
# 安装关键库(建议 Python 3.8+)pip install sentence-transformers faiss-cpu torch
# GPU 用户安装 faiss-gpu
2. 文本向量化
from sentence_transformers import SentenceTransformer
# 加载预训练模型(中文推荐 paraphrase-multilingual-MiniLM-L12-v2)model = SentenceTransformer('paraphrase-MiniLM-L6-v2', device='cuda') # GPU 加速
# 文本预处理示例
def preprocess(text):
import re
text = re.sub(r'[\s+\\(),;:"]',' ', text) # 基础清洗
return text.strip()
# 生成向量
sentences = ["苹果发布新手机", "这个苹果很好吃"]
embeddings = model.encode([preprocess(s) for s in sentences])
print(f"向量维度:{embeddings.shape}") # 输出 (2, 384)
3. 构建 FAISS 索引
import faiss
# 创建索引(L2 距离更适合语义检索)dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
# 添加数据(需 numpy.float32 类型)index.add(embeddings.astype('float32'))
# 保存索引
faiss.write_index(index, "my_index.index")
4. 语义查询实战
# 加载索引
index = faiss.read_index("my_index.index")
# 查询示例
query = "好吃的红苹果"
query_vec = model.encode(preprocess(query))
# 参数说明:nprobe=10 表示搜索 10 个最近邻的聚类中心
D, I = index.search(query_vec.astype('float32'), k=3, nprobe=10)
print(f"最相似结果索引:{I}, 距离:{D}")
性能优化三板斧
- 精度与速度的平衡
- 使用
PQ(Product Quantization) 压缩向量 -
示例:
index = faiss.IndexPQ(d, M, 8)M 建议设为维度 1 /4 -
分布式设计
- 分片索引:按业务维度拆分
-
使用 Faiss 的
IndexShards进行合并查询 -
批处理技巧
- 合并查询请求减少 GPU-CPU 数据传输
- 设置
faiss.GpuMultipleClonerOptions的 shard 选项
中文场景避坑指南
- 停用词陷阱:
- 不要盲目去除 ” 的、是 ” 等词,可能影响语义完整性
-
解决方案:在向量化后处理而非文本预处理阶段过滤
-
维度灾难:
- 现象:当维度 >1000 时检索质量下降
- 应对:
- 使用 PCA 降维(
faiss.PCAMatrix) - 选择维度适中的模型(如 MiniLM 的 384 维)
- 使用 PCA 降维(
思考与延伸
- 业务评估指标:
- 如何定义检索 ” 准确 ”?点击率、转化率还是人工评分?
-
建议结合 A / B 测试观察业务指标变化
-
多模态扩展:
- 能否用 CLIP 模型实现图搜文?
- 跨模态向量空间对齐的挑战
在实际项目中,我发现语义检索的效果高度依赖领域数据质量。建议初期先用小规模数据验证技术路线,再逐步扩展到全量数据。遇到性能瓶颈时,80% 的情况通过调整 nprobe 参数和量化方式就能解决。
正文完
