Keyword Search
Keyword Search 是基于关键词匹配的传统检索方式(BM25/TF-IDF)。它擅长精确匹配,但不理解语义。通常和语义搜索组合使用。
#type / concept
#status / evergreen
#tech / ai
[!info] related notes
- 所属 MOC: RAG Engineering MOC
- 相关: Semantic Search, Hybrid Search
Keyword Search
一句话定义
Keyword Search 是基于关键词匹配的传统检索方式。BM25 算法根据词频和文档频率计算相关性分数。它擅长精确匹配,但不理解语义——“膝盖疼”找不到”膝关节不适”。
核心原理
BM25 算法
BM25(q, d) = Σ IDF(qi) * (f(qi, d) * (k1 + 1)) / (f(qi, d) + k1 * (1 - b + b * |d|/avgdl))
其中:
- IDF: 逆文档频率(稀有词权重更高)
- f(qi, d): 词 qi 在文档 d 中的频率
- |d|: 文档长度
- avgdl: 平均文档长度
Python 实现
from rank_bm25 import BM25Okapi
class KeywordSearch:
def __init__(self, documents: list[str]):
# 分词
tokenized = [doc.split() for doc in documents]
self.bm25 = BM25Okapi(tokenized)
self.documents = documents
def search(self, query: str, top_k: int = 10) -> list[tuple[str, float]]:
tokenized_query = query.split()
scores = self.bm25.get_scores(tokenized_query)
top_indices = scores.argsort()[-top_k:][::-1]
return [(self.documents[i], scores[i]) for i in top_indices]
PostgreSQL 全文搜索
-- 创建全文搜索索引
ALTER TABLE documents ADD COLUMN tsv tsvector;
UPDATE documents SET tsv = to_tsvector('chinese', content);
CREATE INDEX idx_tsv ON documents USING gin(tsv);
-- 搜索
SELECT * FROM documents
WHERE tsv @@ to_tsquery('chinese', '膝盖 & 疼痛')
ORDER BY ts_rank(tsv, to_tsquery('chinese', '膝盖 & 疼痛')) DESC
LIMIT 10;
语义搜索 vs 关键词搜索
| 查询 | 语义搜索 | 关键词搜索 |
|---|---|---|
| ”膝盖疼” | ✅ 找到”膝关节不适” | ❌ 找不到 |
| ”ERROR_001” | ❌ 可能匹配错误 | ✅ 精确匹配 |
| ”如何退款” | ✅ 找到”退款流程” | ⚠️ 需要包含”退款” |
常见坑
- 只用关键词搜索: 不理解同义词和语义
- 不做分词: 中文需要专门的分词器
- 不更新索引: 文档修改后索引没更新