📚 知识库检索方法详解:稀疏 vs 稠密
🔸 一、稀疏检索(Sparse Retrieval)
1. TF-IDF
- 原理:Term Frequency-Inverse Document Frequency,衡量词语在文档中出现的重要程度。
- TF:词频
- IDF:逆文档频率(常见词权重低)
- 最终打分 = TF × IDF
- 使用方式:
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(docs)
2. BM25
- 原理:改进版 TF-IDF,引入词频饱和惩罚和文档长度归一,提升效果。
- 使用方式(用
rank_bm25
):
from rank_bm25 import BM25Okapi
tokenized_corpus = [doc.split() for doc in docs]
bm25 = BM25Okapi(tokenized_corpus)
scores = bm25.get_scores(query.split())
3. 工具:Elasticsearch / Lucene / Solr
- 原理:基于倒排索引(Inverted Index)结构,支持高效的关键词检索
- 使用方式:
- 建立索引:上传文档 JSON 到 Elasticsearch
- 搜索:发送 query DSL 请求(GET)
🔹 二、稠密检索(Dense Retrieval)
1. DPR(Dense Passage Retrieval)
- 原理:用双塔结构的 BERT 模型分别编码 query 与 passage,计算向量余弦相似度。
- 使用方式:
from transformers import DPRQuestionEncoder, DPRContextEncoder, DPRQuestionEncoderTokenizer, DPRContextEncoderTokenizerctx_model = DPRContextEncoder.from_pretrained("facebook/dpr-ctx_encoder-single-nq-base")
ctx_tokenizer = DPRContextEncoderTokenizer.from_pretrained("facebook/dpr-ctx_encoder-single-nq-base")
ctx_embedding = ctx_model(**ctx_tokenizer("some passage", return_tensors="pt")).pooler_output
2. SimCSE / BGE / E5
- 原理:将文本转为高质量语义向量,支持余弦相似度检索。
- 使用方式:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-small-en")
embeddings = model.encode(docs)
3. ColBERT
- 原理:Late interaction,通过 token-level 相似度计算提高精度。
- query 和 document 保留所有 token 的向量
- 使用 MaxSim 聚合
4. 工具:Faiss / Milvus / Qdrant
- Faiss(Facebook):适合本地运行的大规模向量检索
- Milvus / Qdrant / Weaviate:适合云端向量存储 + REST API 检索
import faiss
index = faiss.IndexFlatL2(embedding_dim)
index.add(embeddings)
D, I = index.search(query_embedding, k=5)
✅ 三、总结对比
类别 | 方法 | 原理简介 | 工具平台 |
---|
稀疏检索 | TF-IDF | 基于词频和逆文档频率加权 | Lucene, Elastic |
稀疏检索 | BM25 | 改进 TF-IDF,引入长度归一 | RankBM25 |
稠密检索 | DPR | BERT 双塔结构 | Faiss, Milvus |
稠密检索 | SimCSE/BGE/E5 | 编码器转语义向量 | SentenceTransf. |
稠密检索 | ColBERT | token 粒度匹配,Late Interaction | ColBERT Faiss |