從關鍵字匹配到語義理解:搜尋技術的演進之路
深入淺出解析 TF-IDF、BM25 與現代語義搜尋的原理與差異
為什麼現代搜尋能「讀懂」你的意思?
想像你在圖書館找書,問館員:「有沒有教我做網站的書?」
傳統搜尋引擎會找書名有「做」、「網站」這些字的書。 現代 AI 搜尋會理解你其實想找「網頁開發」、「Web Development」、「前端教學」相關的書。
這兩者的差異,就是關鍵字匹配與語義理解的差異。本文將帶你走過搜尋技術 50 年的演進之路。
📚 第一代:TF-IDF(詞頻-逆文檔頻率)
核心思想:統計詞的重要性
TF-IDF 誕生於 1970 年代,是最經典的文本檢索演算法。它的邏輯非常直觀:
TF(Term Frequency,詞頻)
- 一個詞在文檔中出現越多次,這個詞對該文檔越重要
- 計算:
TF = 詞在文檔中出現次數 / 文檔總詞數
IDF(Inverse Document Frequency,逆文檔頻率)
- 一個詞在越少文檔中出現,這個詞越有鑑別力
- 常見詞如「的」、「是」出現在所有文檔中,沒有鑑別能力
- 計算:
IDF = log(總文檔數 / 包含該詞的文檔數)
TF-IDF 分數 = TF × IDF
實際例子
假設查詢:「what is nlp」
文檔 1:「what is life! candy is life!」 文檔 2:「nlp is an acronym for natural language processing」 文檔 3:「I like to do good research on nlp」
計算過程:
- 將查詢和文檔都轉換成 TF-IDF 向量
- 計算查詢向量與各文檔向量的相似度(點積或餘弦相似度)
- 根據相似度排序
結果:
- 文檔 1 得分:0.165(因為有 “what” 和 “is”)
- 文檔 2 得分:0.0825
- 文檔 3 得分:0.0413
TF-IDF 的局限性
雖然文檔 2 和文檔 3 才真正在討論 NLP,但因為文檔 1 有更多查詢詞的字面匹配,反而得分最高。
核心問題:
- ❌ 無法理解同義詞(「學習」≠「教學」)
- ❌ 無法處理拼寫變化(「color」≠「colour」)
- ❌ 只看字面,不懂語義
- ❌ 詞序資訊丟失
🚀 第二代:BM25(Best Matching 25)
改進點:引入飽和機制
BM25 是 1990 年代對 TF-IDF 的重大改進,目前仍是 Elasticsearch 等搜尋引擎的預設演算法。
核心公式
score(D, Q) = Σ IDF(qi) · [f(qi,D) · (k₁ + 1)] / [f(qi,D) + k₁ · (1 - b + b · |D|/avgdl)]看起來複雜?讓我們拆解:
分子:f(qi, D) · (k₁ + 1)
f(qi, D):查詢詞在文檔中出現次數- 詞出現越多次,分數越高
分母:f(qi, D) + k₁ · (1 - b + b · |D|/avgdl)
- 這是關鍵!引入了飽和效應和長度正規化
k₁:調節詞頻影響(通常 1.2-2.0)b:長度懲罰參數(通常 0.75)|D|/avgdl:文檔長度與平均長度的比值
BM25 的三大優勢
1. 詞頻飽和(Term Frequency Saturation)
TF-IDF 的問題:
「Python」出現 1 次 → 得分 1.0
「Python」出現 10 次 → 得分 10.0
「Python」出現 100 次 → 得分 100.0(線性增長)BM25 的改進:
「Python」出現 1 次 → 得分 1.0
「Python」出現 10 次 → 得分 2.8
「Python」出現 100 次 → 得分 3.2(飽和!)詞頻達到一定程度後,分數增長趨緩,避免「關鍵字堆砌」作弊。
2. 文檔長度正規化
場景對比:
短文檔:
「Python 教學 Python 教學 Python」(5 個詞)
"Python" 出現 3 次
密度 = 3/5 = 60%長文檔:
「這是一篇很長的文章講解 Python 的各種應用
包括數據分析機器學習網頁開發 Python 很棒
...(共 100 個詞)」
"Python" 出現 3 次
密度 = 3/100 = 3%BM25 會給短文檔更高的分數,因為詞的密度更高。
3. IDF 權重保留
與 TF-IDF 一樣,BM25 仍然使用 IDF 來降低常見詞的權重,提高罕見詞的重要性。
BM25 實際應用
from rank_bm25 import BM25Okapi
import jieba
# 文檔集合
corpus = [
"Django 是 Python 的網頁框架",
"Python 是一種程式語言 Python 很好用",
"React 是前端框架"
]
# 分詞
tokenized_corpus = [list(jieba.cut(doc)) for doc in corpus]
# 建立 BM25 模型
bm25 = BM25Okapi(tokenized_corpus)
# 查詢
query = "Python 框架"
tokenized_query = list(jieba.cut(query))
# 計算分數
scores = bm25.get_scores(tokenized_query)
print(scores)
# 輸出:[2.1, 1.8, 0.0]
# 文檔 1 得分最高!BM25 的局限性
雖然 BM25 比 TF-IDF 更強大,但仍然是字面匹配:
查詢:「如何學習程式設計?」
文檔 A:「程式設計入門教學」
文檔 B:「Python 學習指南」
結果:文檔 A 得分更高(有「程式設計」)
實際:文檔 B 可能更相關(語義上在教學習)🧠 第三代:Dense Retrieval(密集檢索)
範式轉變:從字面到語義
2018 年 BERT 的出現,開啟了語義搜尋的新時代。核心思想:
不再比對「字」,而是比對「意義」
工作原理
步驟 1:文本編碼(Encoding)
使用神經網路(Neural Encoder)將文本轉換成向量:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
# 文檔編碼
doc1 = "Django 是 Python 的網頁框架"
doc1_vector = model.encode(doc1)
# 輸出:[0.23, -0.45, 0.67, 0.12, ...] (384 維向量)
doc2 = "如何學習程式設計"
doc2_vector = model.encode(doc2)
# 輸出:[0.18, -0.32, 0.71, 0.09, ...]步驟 2:語義搜尋
計算查詢向量與文檔向量的餘弦相似度:
query = "Python 網頁開發教學"
query_vector = model.encode(query)
# 計算相似度
from sklearn.metrics.pairwise import cosine_similarity
similarity1 = cosine_similarity([query_vector], [doc1_vector])
similarity2 = cosine_similarity([query_vector], [doc2_vector])
print(f"與文檔 1 的相似度: {similarity1[0][0]:.3f}")
print(f"與文檔 2 的相似度: {similarity2[0][0]:.3f}")
# 輸出:
# 與文檔 1 的相似度: 0.847(高!)
# 與文檔 2 的相似度: 0.623為什麼 Dense Retrieval 更強大?
1. 理解同義詞
查詢:「如何學習 Python」
文檔:「Python 教學指南」
TF-IDF/BM25:
- 沒有共同詞(「學習」≠「教學」)
- 得分:低 ❌
Dense Retrieval:
- 理解「學習」和「教學」語義相近
- 得分:高 ✅2. 跨語言理解
查詢(中文):「機器學習入門」
文檔(英文):"Introduction to Machine Learning"
TF-IDF/BM25:
- 完全沒有共同詞
- 得分:0 ❌
Dense Retrieval(多語言模型):
- 理解兩者語義相同
- 得分:高 ✅3. 處理長尾查詢
查詢:「我的 Django 專案無法連接資料庫」
文檔:「解決 Django 資料庫連線問題」
TF-IDF/BM25:
- 只匹配到「Django」和「資料庫」
- 得分:中等
Dense Retrieval:
- 理解整個查詢的語義(故障排除)
- 得分:高 ✅📊 三代技術對比
| 特性 | TF-IDF | BM25 | Dense Retrieval |
|---|---|---|---|
| 年代 | 1970s | 1990s | 2018+ |
| 匹配方式 | 字面 | 字面(改進) | 語義 |
| 同義詞 | ❌ | ❌ | ✅ |
| 多語言 | ❌ | ❌ | ✅ |
| 上下文理解 | ❌ | ❌ | ✅ |
| 計算成本 | 低 | 低 | 中等 |
| 準確率 | 60-70% | 70-80% | 85-95% |
| 代表應用 | 早期搜尋引擎 | Elasticsearch | ChatGPT, Google |
🎯 實戰建議:如何選擇?
使用 BM25 的場景
✅ 精確關鍵字匹配很重要(如法律文件、程式碼搜尋) ✅ 計算資源有限 ✅ 需要極快的搜尋速度(毫秒級) ✅ 文檔語言單一且術語固定
使用 Dense Retrieval 的場景
✅ 需要理解自然語言查詢 ✅ 處理多語言內容 ✅ 用戶查詢多樣化(長尾查詢) ✅ 準確率優先於速度
混合搜尋(Hybrid Search)
現代最佳實踐:結合 BM25 和 Dense Retrieval
# 混合搜尋流程
def hybrid_search(query):
# 1. BM25 檢索(快速初篩)
bm25_results = bm25.get_top_k(query, k=100)
# 2. Dense Retrieval(語義精排)
query_vector = encoder.encode(query)
semantic_scores = compute_similarity(query_vector, bm25_results)
# 3. 融合分數
final_scores = 0.3 * bm25_scores + 0.7 * semantic_scores
return top_k_results(final_scores, k=10)優勢:
- BM25 確保關鍵詞不被遺漏
- Dense Retrieval 提升語義相關性
- 兩者互補,達到最佳效果
🔮 未來趨勢
1. 多模態檢索
不僅搜尋文字,還能搜尋圖片、影片、音訊:
查詢:「海邊日落的照片」
結果:返回相關圖片(即使圖片沒有文字標籤)2. 零樣本檢索
模型能理解從未見過的領域和概念,無需額外訓練。
3. 個性化檢索
根據使用者歷史行為,動態調整搜尋結果。
🏁 總結
搜尋技術的演進,是從字面匹配到語義理解的過程:
TF-IDF(1970s)
- 開創了資訊檢索的統計方法
- 局限:只看字面
BM25(1990s)
- 引入飽和和長度正規化
- 仍是現代搜尋引擎的基石
- 局限:無法理解語義
Dense Retrieval(2018+)
- 神經網路賦予搜尋「理解」能力
- RAG 系統的核心技術
- 未來:多模態、個性化、零樣本
理解這些技術的演進,不僅能幫助你選擇正確的搜尋方案,更能讓你深刻理解現代 AI 系統(如 ChatGPT、RAG)背後的原理。