近幾日在研究fast gpt 的源碼,對於它的混合檢索比較好奇:全文檢索是怎麼實現的?向量檢索呢?

看了源碼才瞭解到,實際上fastgpt 支持三種向量庫,一是minlvs , 二是 pgsql vector, 三是oceanbase(阿里的)。

向量檢索,以pgvector為例簡單説一下,就是在pg庫里加載了pgvector插件,在postgresql 庫中創建了 modeldata 的表,其中有字段名為 vector,類型也是vector,就存儲切塊後的內容的向量值。是1536維的,據説在精準度和計算量之間達到了一個比較好的平衡。

建立向量索引,以及搜索算法,都是pgvector所支持的,不再細説。

令我好奇的是,其全文檢索是基於mongo db內置的來實現的。從源碼來看,用到了jieba 分詞,將句子分此後,用空格連接,以便兼容mongo db的算法(按照英文習慣,單詞之間用空格分隔)。這説明實際上原始內容存儲到mongo db的數據庫字段裏,也應該是經過分詞後,將每個詞之間採用空格分開的。

那麼,接下來我的疑問便是,其內部究竟是怎麼實現的。為此我求助了騰訊元寶的DeepSeek深度搜索,提示詞如下:

假如在 mongo db 中存儲了文章的內容,並對內容字段建立了全文檢索的索引,那麼加入搜索一個經過中文分詞後的句子“中國 汽車 品牌 世界 最強”,在mongo db 內部是怎麼進行檢索並對檢索結果進行打分的?假如有個記錄的內容是 “中國的汽車品牌 是世界上最強的沒有之一” ,另一個是“日本汽車比不上中國汽車”, 它們各自的得分會是多少?這個得分是按照內容包含了相應的關鍵字就得分呢?還是關鍵字在其中出現次數多也有助於高的得分呢?還是怎麼樣的?

以下便是值得記錄的它的回答:

MongoDB 的全文檢索基於 倒排索引TF-IDF 算法 進行匹配和打分。以下是針對你問題的詳細分析:


一、檢索過程解析

1. 索引構建
  • 對文章內容字段建立全文索引後,MongoDB 會:
  1. 分詞:將文本拆分為詞元(如 ["中國", "汽車", "品牌", "世界", "最強"])。
  2. 構建倒排索引:記錄每個詞元出現的文檔位置及頻率。
"中國" → [文檔1_ID, 文檔2_ID]
"汽車" → [文檔1_ID, 文檔2_ID]
"品牌" → [文檔1_ID]
"世界" → [文檔1_ID]
"最強" → [文檔1_ID]
2. 查詢處理
  • 查詢 中國 汽車 品牌 世界 最強被拆分為獨立詞元。
  • MongoDB 執行 OR 邏輯:匹配包含任意查詢詞元的文檔(除非使用 ""指定短語)。

二、相關性打分機制

得分由 TF-IDF 算法 計算,公式簡化如下:

Score = TF(詞頻) × IDF(逆文檔頻率)
1. TF (詞頻)
  • 詞在文檔中出現的次數越高,得分越高
  • 示例:
  • 文檔1:"中國的汽車品牌是世界上最強的沒有之一"
  • 中國:1, 汽車:1, 品牌:1, 世界:1, 最強:1
  • 文檔2:"日本汽車比不上中國汽車"
  • 中國:1, 汽車:2(其他詞未出現)
2. IDF (逆文檔頻率)
  • 詞在整個集合中的稀有程度。詞越常見,IDF 越低。
  • 公式:
IDF = log(總文檔數 / 包含該詞的文檔數)
  • 假設集合中有 1000 篇文檔:
  • 汽車出現在 800 篇 → IDF = log(1000/800) ≈ 0.1
  • 最強出現在 10 篇 → IDF = log(1000/10) ≈ 2.0
3. 最終得分計算
  • 文檔1
Score = (TF_中國 × IDF_中國) + (TF_汽車 × IDF_汽車) + ...
        ≈ (1×0.2) + (1×0.1) + (1×1.5) + (1×0.3) + (1×2.0) = 4.1
  • 文檔2
Score = (TF_中國 × IDF_中國) + (TF_汽車 × IDF_汽車)
        ≈ (1×0.2) + (2×0.1) = 0.4

結論:文檔1 得分遠高於文檔2,因為它包含更多查詢詞元且包含高 IDF 詞(如“最強”)。


三、其他影響因素

  1. 詞元位置與權重
  • 標題中的詞可能比正文權重更高(取決於索引配置)。
  1. 短語匹配
  • 若查詢用引號包裹 "中國汽車",連續出現的短語會獲得額外加分。
  1. 停用詞過濾
  • “的”、“是”等停用詞會被忽略,不計入打分。
  1. 詞幹提取
  • 英文中“running”會被歸併為“run”,中文需依賴分詞工具(如你的代碼中的 jiebaSplit)。

四、你的示例結果對比

文檔內容

匹配詞元

TF-IDF 得分

原因分析

中國的汽車品牌是世界上最強的沒有之一

中國、汽車、品牌、世界、最強

較高 (如4.1)

命中全部查詢詞元,且包含高 IDF 詞(如“最強”)

日本汽車比不上中國汽車

中國、汽車

較低 (如0.4)

僅命中2個詞元,且“汽車”因常見導致 IDF 低


關鍵結論

  • 命中詞元數量詞元的稀有度(IDF)是得分的核心因素。
  • 代碼中的 score: { $meta: 'textScore' }正是獲取這個 TF-IDF 分數。
  • 中文場景需依賴分詞工具(如你的 jiebaSplit)預處理查詢詞,否則 MongoDB 默認按空格分詞(對中文不友好)。

ok,本篇結束。感謝AI 的回覆。