在 Elasticsearch 中通過乘法增強來影響 BM25 排名

新聞
HongKong
4
06:15 PM · Jan 04 ,2026

作者:來自 Elastic Alexander Marquardt

瞭解為什麼加法提升方法會破壞BM25排名,以及乘法評分如何在Elasticsearch中提供受控且可擴展的排名影響。

測試Elastic最前沿、開箱即用的能力。快來看看我們的示例筆記本,開始免費雲試用,或者現在就在本地機器上試用Elastic吧。


BM25是 Elasticsearch 中最廣泛使用的基於文本的評分模型之一。在許多電子商務實現中,它是決定產品相關性的主要組成部分,因為它提供了一個易於理解、可解釋的分數,用來反映商品與用户查詢的匹配程度。除了這種文本相關性之外,商品運營和搜索團隊通常還需要通過業務指標來影響排序,例如利潤率、庫存水平、受歡迎程度、個性化或營銷活動策略,同時又不破壞底層的文本相關性。

實現這一點最直觀的手段是使用帶 boost 的should子句或rank_feature字段。它們在一開始看起來可能有效,但隨着查詢模式變化或商品目錄結構發生變化,這兩種方法都會退化,甚至失效。它們的共同侷限在於:在一個不同查詢之間尺度變化很大的評分系統中,引入了加法調整。像 “+2” 這樣的 boost,可能在某些查詢中壓倒基礎的 BM25 分數,而在另一些查詢中幾乎不起作用。換句話説,加法方法可能會導致脆弱且不可預測的排序行為。

相比之下,使用function_score的乘法增強提供了一種穩定、數學上成比例的方式來塑造 BM25 分數,而不會扭曲其底層結構。你的應用邏輯決定哪些因素值得提升;function_score 以一種可預測、可解釋的方式表達這種意圖,保留了 BM25 相關性信號的幾何結構(高層次的相對排序),通過受控的方式微調排名,而不是淹沒核心的文本相關性。

本文基於之前的兩篇文章,這兩篇文章展示了乘法增強的實際用法:(1)使用 Elasticsearch 中的 function score query 通過利潤和受歡迎度來增強電子商務搜索,以及 (2)如何通過個性化的、基於羣組的排序來提升電子商務搜索相關性。在這裏,我們從這些示例中抽身,回到其背後的架構原則:為什麼通過 function_score 進行乘法增強,是在 Elasticsearch 中影響基於 BM25 排名時最可靠、最具擴展性的方法之一。

為什麼保留基礎 BM25 排名很重要

在許多基於 Elasticsearch 的應用中(包括電子商務),BM25 仍然是評估文本相關性的核心組成部分。它提供了一個可解釋、透明的信號,方便需要理解為什麼某個產品會排在當前位置的團隊使用。這些特性使 BM25 在強調可解釋性和運行可預測性的環境中特別有吸引力。

正因為如此,大多數團隊希望對 BM25 生成的排名進行塑形,而不是替換它。例如,他們可能希望讓高利潤商品稍微更常出現,降低低庫存商品的曝光度但不將其隱藏,或者突出與特定用户羣體匹配的商品。理想情況下,這種塑形應當保留 BM25 算法生成的排名幾何結構。

問題出現在團隊嘗試通過在基礎 BM25 排名之上疊加獨立評分流來實現這些目標時。這些加法調整並不總是與 BM25 的評分尺度可比,並且會隨着查詢、數據分佈和商品目錄結構的變化而表現不一致。隨着時間推移,排序會變得脆弱、不直觀,且難以調優。一個可靠的影響機制必須與 BM25 的評分幾何結構協同工作,而不是壓倒它。

使用乘法增強的 function_score 查詢正具備這一特性。它允許團隊以成比例、可解釋的方式施加業務影響,同時保持 BM25 底層結構的完整性。

為什麼許多影響排序的方法會削弱(甚至破壞)BM25

團隊通常會從一些看起來很直接的機制入手:帶 boost 的 should 子句、rank_feature 字段,或自定義script_score邏輯。這些工具在各自的設計場景中是有效的,這也是為什麼它們看起來像是添加業務影響的自然手段。但當它們被用來塑造或影響基於 BM25 的文本相關性時,往往會導致不穩定、不透明或脆弱的排序行為。

根本問題在於,這些方法在一個基礎 BM25 值在不同查詢、字段和數據集之間差異很大的系統中,引入了彼此獨立的加法評分貢獻。如果不尊重這種變化性,影響效果就會變得不可預測。

下面是三種最常見的模式,以及它們在實際中為何會失敗。

1)通過 should 子句進行加法增強

帶 boost 的 should 子句看起來很直觀:“提升符合這個業務規則的商品。” 但在底層,這種行為本質上是加法的。

考慮如下形式的查詢:

GET products/_search
{
  "query": {
    "bool": {
      "must": [ { "match": { "description": "running shoes" }}],
      "should": [ { "term": { "brand": { "value": "nike", "boost": 1 }}}]
    }
  }
}

這種查詢會產生如下行為:

final_score = base_BM25 + should_BM25

問題在於 base_BM25 和 should_BM25 並不會一起按比例變化。隨着數據集變化,或發出不同的查詢,BM25 的量級可能會發生巨大變化。例如,在某種情況下,三個商品的基礎 BM25 分數可能是 12、8、4;而在另一種情況下,可能變成 0.12、0.08、0.04。這種變化可能發生在商品目錄更新之後,或查詢結構被修改之後。

一個帶 boost 的 should 子句會向最終分數中加入它自己的 BM25 風格貢獻。在這種情況下,加法貢獻(例如 should_BM25 = +2)會表現得非常不一致:

  • 當 base_BM25 很小(0.12)時,+2 會主導最終分數 —— 大約是 18 倍的提升。
  • 當 base_BM25 很大(12)時,同樣的 +2 幾乎不會改變文檔位置 —— 只有大約 17% 的提升。

這種不穩定性意味着,組合後的 must 分數和 should 分數在不同查詢或不同商品目錄之間並沒有穩定的語義。一個在某個查詢中只是輕微提升品牌的規則,可能在另一個查詢中主導整個排序,又在第三個查詢中幾乎不起作用。這不是調參問題,而是加法評分在結構層面上的固有屬性。

2)使用 rank_feature 來施加業務影響

rank_feature 系列在表示諸如新鮮度或受歡迎度等數值特徵時非常有用。它速度快、存儲緊湊、運維簡單。然而,當它被用來影響文本相關性(BM25)時,會遇到與上一節所述相同的結構性限制。

rank_feature 子句會生成它自己的評分貢獻,然後將其加到 BM25 分數之上:

final_score = base_BM25 + feature_score

就像帶 boost 的 should 子句一樣,這兩個組成部分並不會一起按比例變化。BM25 的取值會隨着查詢中詞項的稀有程度和商品目錄統計而大幅波動,而 feature_score 則遵循被增強的業務屬性本身的尺度(例如受歡迎度或新鮮度),這一尺度通常與 BM25 的尺度毫無關係。結果是,隨着語料或查詢模式的演進,這兩條評分流會逐漸偏離。

其後果與前面討論的 should 子句問題是一樣的:

  • feature score 可能在某個查詢中主導 BM25,而在另一個查詢中幾乎可以忽略不計。
  • 調參變得非常脆弱,因為你在校準兩個彼此獨立的尺度 —— 一個是隨查詢詞項統計變化的 BM25,另一個是隨業務屬性自身分佈變化的 feature score。

儘管 rank_feature 仍然是表示原始數值屬性的優秀機制,但它並不適合用於對 BM25 施加成比例的影響;在這種場景下,目標不是增加第二個分數,而是對已有分數進行温和的塑形。

使用 script_score 進行自定義評分

當帶 boost 的子句或 rank_feature 字段難以調優時,團隊通常會將 script_score 作為最後手段。它提供了完全的自由來操作分數,包括根據任何業務規則加、減、乘或替換 BM25 值。script_score 查詢會用自定義邏輯替換 Elasticsearch 的評分管道。腳本不是對 BM25 分數進行塑形,而是構建一個獨立的評分機制,其行為完全取決於腳本內部的代碼。雖然這很強大,但在系統規模擴大時,會引入三個更為顯著的挑戰。

  1. 不透明性
    評分邏輯隱藏在腳本中,而非以聲明方式表達。當排名行為出現意外變化時,很難判斷問題出在腳本本身、數據變化,還是與 BM25 的交互。商品運營和相關性工程師失去了理解文檔排名變化原因的能力。
  2. 性能與運維成本
    腳本評分繞過了 Elasticsearch 的許多優化和緩存路徑。每個匹配初始查詢的文檔都必須執行腳本,通常導致 CPU 使用率升高和延遲不可預測。
  3. 與 BM25 結合時的脆弱性
    由於 script_score 允許任意計算,很容易產生不再類似 BM25 的評分行為,或者無法保持其相對結構。隨着數據集的發展或查詢模式的變化,自定義邏輯可能以意想不到的方式與 BM25 交互。在開發初期表現合理的腳本,一旦商品目錄增長或數據分佈變化,就可能產生令人意外或不穩定的結果。由於 script_score 允許任意數學操作,不同工程師在系統不同部分可能無意中編碼了衝突的評分模型,使得隨着組織規模擴大,排名變得難以理解。

function_score 如何對 BM25 提供可預測影響

BM25 已經衡量了文檔與查詢的匹配程度。它反映了文本相關性、詞項稀有度、文檔長度以及語料庫的統計特性。當團隊引入商業信號,包括 margin、庫存水平、流行度、個性化或 merchandising 策略時,目標不是替代這種相關性,而是影響它。

這種區別微妙但關鍵。大多數業務需求本質上是比例性的:

  • 略微提升高 margin 商品
  • 減少低庫存商品的曝光,但不隱藏它們
  • 對這個用户羣體的匹配商品略微提升
  • 提升流行度,但不要讓文本相關性丟失

這些自然以百分比調整而非固定加值表示。merchandiser 很少會要求“+2 分的 score”;他們要求的是“稍微增加可見度”,無論 BM25 分數的絕對數值是多少。數學上,這意味着所需的變換是:

final_score = BM25 × boost_factor

boost_factor 可能是 1.05、1.2 或 1.5,取決於信號。乘法提升不會試圖重新發明評分;它只是按比例調整 BM25 輸出。乘法調整有三個特性,與現實世界的排序控制非常契合:

  • 提升保持比例。換句話説,20% 的提升始終是 20% —— 無論 BM25 是 0.12 還是 12。提升的大小不依賴於 BM25 的底層尺度。
  • BM25 保持其作為主要信號的作用。乘法調整輕微改變排序而不覆蓋它。強文本匹配仍然優先;商業邏輯影響排序,但不主導。
  • 因為操作是乘法而非加法,改變查詢或更新語料庫時不需要重新調整數值常量。提升在任何地方都有相同的意義。

Elasticsearch 的 function_score 查詢提供了一個優雅的機制來表達這種模式。通過使用:

  • score_mode: “sum” 來組合 boost factor(構建乘數),以及
  • boost_mode: “multiply” 將提升(乘數)應用到 BM25

你可以以一種穩定且可解釋的方式表達商業意圖,隨着數據和查詢模式的發展仍然有效。function_score 不是在 BM25 旁邊增加第二個分數,而是直接轉換 BM25 —— 輕柔、可預測地調整,符合 merchandisers 和產品負責人對排序調整的思路。

實踐中的例子:乘法提升在真實電商查詢中的表現

為了説明乘法提升在真實排序場景中的作用,查看一個小而具體的例子會很有幫助。這裏的目標不是展示調優或生產級評分,而是展示 function_score 如何以可預測、比例化的方式影響 BM25,與商業意圖保持一致。

考慮一個簡單的目錄,有三雙不同品牌的籃球鞋:Nike、Adidas 和 Reebok。產品描述是有意設計的,使 BM25 分數根據查詢的具體性和字段長度表現出自然差異 —— 就像在真實目錄中一樣。

示例數據集

在以下例子中,我們使用一個小而簡單的樣本數據集,具有以下特徵。

我們可以使用 Kibana Dev Tools 中以下命令創建包含上述產品的索引:

PUT products
{
  "mappings": {
    "properties": {
      "brand":       { "type": "keyword" },
      "description": { "type": "text" }
    }
  }
}
 
POST products/_bulk
{ "index": { "_id": "nike-001" } }
{ "brand": "nike",    "description": "Nike basketball shoes" }
{ "index": { "_id": "adi-001" } }
{ "brand": "adidas",  "description": "New Adidas basketball shoes" }
{ "index": { "_id": "ree-001" } }
{ "brand": "reebok", "description": "Reebok basketball shoes" }

使用這個數據集,我們現在評估三個查詢:

  • 基準 “basketball shoes” 搜索
  • 同樣的查詢,但對 Adidas 提升 50%,對 Nike 提升 25%
  • 一個特定的 “Reebok basketball shoes” 查詢,同時 Adidas 和 Nike 的提升仍然生效

每個場景都展示了乘法提升的不同特性。

1)基準排序:無提升

GET products/_search
{
  "size": 3,
  "_source": ["brand", "description"],
  "query": {
    "match": { "description": "basketball shoes" }
  }
}
⚠️ 本文中的示例在單節點測試集羣(Elasticsearch 8.18.1)上運行,並且索引只有一個 primary shard。如果你使用 Elastic Cloud Serverless,它默認會為你的索引分配三個 primary shard。因此,如果你想重現本文中顯示的相同 BM25 分數,你可以通過在搜索請求中添加 ?search_type=dfs_query_then_fetch 來啓用全局分數計算。這個參數對於重現分數很有用,但通常不需要,並且不推薦在生產系統中使用。包含此參數後,上述查詢將變為:
POST blog_food_products/_search?search_type=dfs_query_then_fetch
{
  "size": 5,
  "_source": ["description", "margin"],
  "query": {
    "match": {
      "description": "McCain Chips"
    }
  }
}
dfs_query_then_fetch會在索引級別而非每個 shard 級別計算 BM25 詞項統計,從而使分數在不同環境中更加一致。

該查詢返回以下結果,其中 Nike 和 Reebok 排在 adidas 之前:

2)使用 function_score 給 Adidas 和 Nike 增加權重

如果市場活動要求 Adidas 籃球鞋增加 50% 權重,Nike 增加 25% 權重,應用層可以這樣構造查詢:

GET products/_search
{
  "size": 3,
  "_source": ["brand", "description"],
  "query": {
    "function_score": {
      "query": {
        "match": { "description": "basketball shoes" }
      },
      "functions": [
        {
          "filter": { "term": { "brand": "adidas" } },
          "weight": 0.5
        },
        {
          "filter": { "term": { "brand": "nike" } },
          "weight": 0.25
        },
        {
          "weight": 1.0
        }
      ],
      "score_mode": "sum",
      "boost_mode": "multiply"
    }
  }
}

乘數是如何構造的:

  • 基礎權重 = 1.0
  • Adidas 額外增加 +0.5 → Adidas 的乘數 = 1.5
  • Nike 額外增加 +0.25 → Nike 的乘數 = 1.25
  • 其他品牌(包括 Reebok)保持基礎權重乘數 = 1.0

應用乘數:

最終得分 = BM25 × 乘數

Product	BM25	Multiplier	Final score
Adidas	0.24686474	1.5	0.37029710
Nike	0.27845407	1.25	0.34806758
Reebok	0.27845407	1.0	0.27845407

結果

Adidas 排到最前,Nike 緊隨其後,Reebok 保持在底部,分數沒有變化。這正是乘法提升設計要實現的效果:

  • Adidas 和 Nike 都獲得了更多曝光,但按配置的提升比例增加。
  • BM25 的相對差異仍然重要;我們是在調整排名,而不是替換它。
  • 排序變化主要發生在 BM25 分數接近的情況下。
  • 使用加法提升時,相同的 “50% 對 25%” 業務意圖需要在任意 BM25 量表上用數字常量近似,並且效果會在不同查詢間大幅變化。

3)特定意圖仍然優先:“Reebok basketball shoes”

現在運行一個針對 “Reebok basketball shoes” 的高特定品牌查詢,同時保持 Adidas(50%)和 Nike(25%)的促銷仍然生效:

GET products/_search
{
  "size": 3,
  "_source": ["brand", "description"],
  "query": {
    "function_score": {
      "query": {
        "match": { "description": "Reebok basketball shoes" }
      },
      "functions": [
        {
          "filter": { "term": { "brand": "adidas" } },
          "weight": 0.5
        },
        {
          "filter": { "term": { "brand": "nike" } },
          "weight": 0.25
        },
        {
          "weight": 1.0
        }
      ],
      "score_mode": "sum",
      "boost_mode": "multiply"
    }
  }
}

結果顯示如下:

結果

Reebok 壓倒性獲勝,因為 BM25 正確識別了 “Reebok basketball shoes” 的強烈意圖。Adidas 和 Nike 仍分別獲得 50% 和 25% 的提升,但這些乘數遠不足以覆蓋 BM25 分數。

這正是乘法提升設計要實現的效果:

  • 當 BM25 分數接近時,提升可以改變相對排序。
  • 當 BM25 分數差異顯著時(如本例,由於強文本匹配),相同的提升幾乎沒有實際效果。
  • 促銷影響排名,但不會覆蓋核心文本相關性信號。

本例展示了什麼

這些實際查詢展示了乘法提升的關鍵特性:

  • 影響是按比例的,而非任意的。基於百分比的提升在任何 BM25 量表下都有相同比例效果。
  • 文本相關性保持主導。強品牌意圖的查詢仍然顯示正確的產品。
  • 系統行為直觀。商品經理可以看到期望的排名變化。
  • 數學在所有查詢中穩定。無論匹配廣泛還是高度具體,相同的促銷都能正確應用。
  • 應用邏輯保持清晰。業務層決定提升;Elasticsearch 可預測地應用它。

通過 function_score 的乘法提升在可控和可預測的方式下保留了相關性,同時實現了業務影響。

應用邏輯仍然是影響的作者

決定哪些內容應該被提升與在 Elasticsearch 中應用該提升之間有明確的分離。function_score 負責第二部分,而第一部分完全屬於應用邏輯。

你的應用邏輯負責做出如下決策:

  • 哪些利潤閾值對業務重要
  • 是否根據季節性調整受歡迎度
  • 如何解讀客户行為或羣體歸屬
  • 如何編碼活動規則
  • 何時顯示或屏蔽某些產品組

這些是業務決策,而不是評分決策。Elasticsearch 不會判斷用户是注重預算還是奢侈品、是否有促銷活動,或者低庫存是否需要調整曝光度。這些判斷髮生在上游系統中,系統可以訪問用户上下文、會話特徵、分析數據和業務配置。在應用邏輯生成明確的數字信號(如權重、提升因子、閾值、羣體標籤)之後,function_score 查詢提供了一種可靠方式,將這些信號以可控乘數應用於 BM25。

這創建了一個清晰的架構約定:

  • 應用邏輯:決定哪些內容應受影響
  • BM25:提供核心文本相關性
  • function_score:以數學穩定的方式應用影響

因為業務邏輯位於索引之外,團隊可以在不重新索引或重構文檔的情況下調整或實驗提升策略。

結論

電商搜索必須在核心文本相關性與業務考慮(如盈利能力、庫存狀況、客户意圖、季節性和個性化)之間取得平衡。BM25 提供穩定且可解釋的文本相關性基礎,但影響該分數需要謹慎。業務信號應塑造排名,而非覆蓋它。

然而,最常用的手段如 boosted should 子句、rank_feature 字段和臨時腳本評分往往表現不穩定。這些方法在開發早期看似有效,但隨着目錄變化或新查詢模式出現,其侷限性很快顯現。加法提升波動巨大,因為其影響完全依賴於 BM25 的底層量表,而 BM25 在不同查詢中變化極大。在某種情況下產生微小調整的提升,在另一種情況下可能主導排序。腳本評分則帶來不透明邏輯、性能下降以及評分行為難以理解或維護的問題。

通過 function_score 的乘法提升避免了這些問題,它按比例調整 BM25,而不是與其競爭。它不是添加一個獨立的分數組件,而是對 BM25 本身應用可控乘數。這產生了商品經理實際期望的可預測調整,例如:輕微提升高利潤商品、適度降低低庫存商品的可見性,或為相關用户羣體提供温和提升。

同樣重要的是,架構保持清晰。應用邏輯決定哪些業務信號重要,function_score 以一致且可解釋的方式應用它們。業務團隊可以演化策略而不破壞相關性,工程團隊可以優化相關性而不干擾業務規則。

這一原則是之前博客的基礎,這些博客展示瞭如何影響電商排名:

  • 使用 Elasticsearch 的 function_score 查詢按利潤和受歡迎度提升電商搜索
  • 如何通過個性化羣體感知排名提升電商搜索相關性

兩種方法都基於一個理念:業務信號應引導 BM25,而不是覆蓋它。通過 function_score 的乘法提升,提供了一種在實際電商搜索中實現這種平衡的可行、透明且可擴展的方法。

 

原文:BM25 ranking with multiplicative boosts in Elasticsearch - Elasticsearch Labs

 

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.