Keyword Search

Keyword Search 是基于关键词匹配的传统检索方式(BM25/TF-IDF)。它擅长精确匹配,但不理解语义。通常和语义搜索组合使用。

#type / concept #status / evergreen #tech / ai

[!info] related notes

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”❌ 可能匹配错误✅ 精确匹配
”如何退款”✅ 找到”退款流程”⚠️ 需要包含”退款”

常见坑

  1. 只用关键词搜索: 不理解同义词和语义
  2. 不做分词: 中文需要专门的分词器
  3. 不更新索引: 文档修改后索引没更新

参考资料

创建于 2026/6/30 更新于 2026/7/15