StackTraces
Meilisearch已驗證

Meilisearch PUT ranking-rules 只傳自定義規則,相關度排序整體失效

@debug_master今天更新閱讀 6 min00

PUT /settings/ranking-rules 是全量覆蓋語義,不是增量追加。只傳一條自定義規則(比如 ["rating:desc"])會把預設 7 條全部沖掉——typo、proximity、attributeRank、wordPosition、exactness 的裁決全部退場,只有 words 靠隱式優先兜底。不報錯,但相關度排序整體失效,結果順序變成「命中詞數相同就按你的字段排」。

Issue & Env(案發現場與環境)

  • 業務場景:想讓「評分高的書」常駐搜索前排,把 rating:desc 寫進排名規則。為了「省事」只傳了這一個規則。結果發現:拼錯詞的文檔和拼寫正確的文檔平起平坐、命中標題的文檔不再比命中摘要的靠前,整個相關度排序像被拔掉了。
  • 環境:Meilisearch v1.54+(預設排名規則為 7 條:words、typo、proximity、attributeRank、sort、wordPosition、exactness,v1.36 起 attribute 拆分為 attributeRank + wordPosition)。
  • 示例索引用 books_rank(6 條書籍文檔,含 title_en、rating 字段)。其中兩條關鍵數據:
{"id": 2, "title": "黑暗森林", "title_en": "The Dark Forest", "rating": 9.2}
{"id": 6, "title": "影之森", "title_en": "The Forest of Shadows", "rating": 8.5}

StackTrace(無報錯,靜默失效)

第一步先看設置被覆蓋成什麼樣:

curl http://localhost:7700/indexes/books_rank/settings/ranking-rules \
  -H "Authorization: Bearer aSampleMasterKey"
["rating:desc"]

返回體裡只剩一條規則——不是追加,是整個陣列被替換了。沒有任何報錯,PUT 成功、任務 succeeded。

第二步看搜索行為變化。用 q=forest 搜(兩個書名裡都有 forest,拼錯的場景同理):

curl -X POST http://localhost:7700/indexes/books_rank/search \
  -H "Authorization: Bearer aSampleMasterKey" \
  -H "Content-Type: application/json" \
  -d '{"q":"forest"}'

預設 7 條規則下,attributeRank 和 wordPosition 會裁決:兩本書都命中 title_en,但《影之森》的 forest 在標題第 2 個詞位、《黑暗森林》在第 3 個詞位,wordPosition 讓《影之森》排前。覆蓋後這個裁決消失了:

默认规则:影之森 8.5 → 黑暗森林 9.2(wordPosition:词位靠前者胜)
覆盖后:  黑暗森林 9.2 → 影之森 8.5(只剩隐式 words 平局 → rating:desc 接管)

順序整個翻轉。相關度維度(詞位、字段權重、錯字數)全部不再參與排序。

Root Cause(根因分析)

PUT settings 全家都是全量覆蓋

Meilisearch 的所有 PUT /settings/* 子路由(包括 PUT /settings 整體)都是替換整個陣列/物件的語義。官方 settings API 文檔對 ranking-rules 更新端點的描述就是覆寫現有列表。想「追加」必須把舊規則原樣帶上。

沖掉預設規則後,裁決鏈只剩隱式 words

官方 relevancy 文檔寫明:即使你刪掉 words,Meilisearch 仍會隱式地按 words 優先排序——這是保底,不是完整相關度。被沖掉的其餘 5 條各管一攤:

被沖掉的規則 失效後果
typo 拼錯詞的文檔與拼寫正確的文檔平起平坐(typo tolerance 仍放行匹配,只是不再按錯字數排序)
proximity 詞距不再影響順序,「dark forest」相鄰命中和相隔十詞命中一樣
attributeRank 標題命中與摘要命中不再有先後
wordPosition 詞位靠前不再加分
exactness 精確整值匹配不再優先於部分匹配

words 的隱式優先意味著「命中詞數」還在起作用——所以現象是同命中數內部順序失控,而不是徹底亂序,這也是它容易瞞過測試的原因。

順帶澄清:自定義規則不需要 sortableAttributes

rating:desc 這類自定義排名規則只要字段在全部文檔裡是數字或字符串即可,不要求先聲明 sortableAttributes(那是 sort 搜索參數的要求)。所以坑不在聲明缺失,純在覆蓋語義。

The Fix(解決方案)

第一步:全量帶上預設 7 條,自定義規則放鏈尾

curl -X PUT http://localhost:7700/indexes/books_rank/settings/ranking-rules \
  -H "Authorization: Bearer aSampleMasterKey" \
  -H "Content-Type: application/json" \
  --data-binary '["words","typo","proximity","attributeRank","sort","wordPosition","exactness","rating:desc"]'

放鏈尾是軟排序:相關度先裁決,打平時評分高的靠前。要「評分硬壓相關度」就放鏈首,代價是犧牲相關度——位置即權重。

第二步:拿不準就重置為預設

DELETE 該端點會把 rankingRules 恢復成預設 7 條(設置類端點的重置語義):

curl -X DELETE http://localhost:7700/indexes/books_rank/settings/ranking-rules \
  -H "Authorization: Bearer aSampleMasterKey"

排查建議

  • 改完規則先 GET /settings/ranking-rules 看一眼,確認預設 7 條都在——全量覆蓋不留神就會少帶。
  • 設置更新是異步任務且觸發全量重建,等任務 succeeded 再驗證順序,否則看到的還是舊索引的結果。
  • 用 _rankingScoreDetails 驗證:預設規則下明細裡有 typo、attributeRank 等鍵;被覆蓋後這些鍵會消失,一眼就能看出裁決鏈缺了誰。
  • v1.36+ 環境注意:attribute 不能與 attributeRank/wordPosition 混用,帶規則時別把新舊兩套寫在一起。

References(參考來源)

最後更新於 2026-10-31

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法