從關鍵字匹配到語義理解:搜尋技術的演進之路

深入淺出解析 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」

計算過程:

  1. 將查詢和文檔都轉換成 TF-IDF 向量
  2. 計算查詢向量與各文檔向量的相似度(點積或餘弦相似度)
  3. 根據相似度排序

結果

  • 文檔 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-IDFBM25Dense Retrieval
年代1970s1990s2018+
匹配方式字面字面(改進)語義
同義詞
多語言
上下文理解
計算成本中等
準確率60-70%70-80%85-95%
代表應用早期搜尋引擎ElasticsearchChatGPT, Google

🎯 實戰建議:如何選擇?

使用 BM25 的場景

✅ 精確關鍵字匹配很重要(如法律文件、程式碼搜尋) ✅ 計算資源有限 ✅ 需要極快的搜尋速度(毫秒級) ✅ 文檔語言單一且術語固定

使用 Dense Retrieval 的場景

✅ 需要理解自然語言查詢 ✅ 處理多語言內容 ✅ 用戶查詢多樣化(長尾查詢) ✅ 準確率優先於速度

現代最佳實踐:結合 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)背後的原理。


0%