multi-search 的錯誤處理策略是 fail-fast:請求裡任意一條 query 參數非法,整個請求立即終止,返回一個錯誤物件——不返回任何部分成功的結果。這意味著你不能指望「好的 query 先返回,壞的 query 報錯後重試」。必須確保所有 query 都合法後,multi-search 才會返回 results 陣列或 federated hits 列表。
Issue & Env(案發現場與環境)
- 業務場景:電商全站搜索。
products和blog_posts兩個索引都建好了,但寫 multi-search 時手滑把blog_posts寫成了blog_post(少了 s)。發出請求後返回 400,products的結果也沒拿到——雖然它的 query 完全合法。 - 環境:Meilisearch v1.54+,任意 multi-search 請求。
- 關鍵區分:這不是網絡超時或部分索引宕機——那會有不同的錯誤路徑。fail-fast 是請求參數校驗層面的行為:在 Meilisearch 引擎開始執行任何 query 之前,它先做一輪全請求的參數校驗,校驗通不過就直接返回第一個發現的錯誤。
StackTrace(錯誤響應)
{
"message": "Index `blog_post` not found.",
"code": "index_not_found",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#index_not_found"
}
注:fail-fast 的錯誤響應就是第一個非法 query 對應的錯誤碼——indexUid 不存在就報
index_not_found、filter 語法錯就報invalid_search_filter、offset 為負數就報invalid_search_offset。錯誤消息只涉及第一個被發現的問題,不會列出全部。
Reproduce(復現程式碼)
# products 和 blog_posts 都已建好,blog_post 不存在
curl -X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
--data-binary '{
"queries": [
{ "indexUid": "products", "q": "headphones", "limit": 5 },
{ "indexUid": "blog_post", "q": "headphones" }
]
}'
{"message":"Index `blog_post` not found.","code":"index_not_found","type":"invalid_request","link":"https://docs.meilisearch.com/errors#index_not_found"}
products 那條 query 完全合法,但因為第二條 query 有不存在的 indexUid,整個請求返回 400,沒有 results 陣列,也沒有任何 hits。
Root Cause(根因分析)
multi-search 是一個原子請求,不是並行子請求
Meilisearch 對 multi-search 的處理是:
- 解析整個請求體
- 對所有 queries 做一輪前置校驗(indexUid 存在性、filter 語法、分頁參數等)
- 校驗通過後,並行執行所有 query,合併返回
校驗階段任何一條 query 不通過,第 3 步就不發生——這就是 fail-fast。引擎不會先跑第 1 條,發現第 2 條錯了再返回第 1 條的結果。
對比:客戶端自己併發
如果你不用 multi-search,而是在應用層同時發兩個 POST /indexes/{uid}/search 請求,其中一個 indexUid 寫錯,另一個還是會正常返回——因為它們是獨立的 HTTP 請求,獨立的校驗和執行。multi-search 把多個請求打包成一個,代價就是失去了部分成功的能力。
為什麼這麼設計
Meilisearch 的 multi-search 支持 federated mode(合併重排),這個合併步驟要求所有 query 的結果都拿到之後才能做。如果允許部分成功,合併邏輯就要處理「某些 query 超時/失敗怎麼辦」——設計複雜度大幅上升。官方選擇了 fail-fast,換來了簡單的語義:要麼全成功,要麼全失敗。
The Fix(解決方案)
第一步:每條 query 單獨驗證
multi-search 裡的每條 query 先單獨跑通再合併進來。
# 先单独验证 blog_posts(注意是复数)
curl -X POST 'http://localhost:7700/indexes/blog_posts/search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
-d '{"q":"headphones"}'
{"hits":[...],"query":"headphones","processingTimeMs":1,"estimatedTotalHits":42}
單獨跑通了再進 multi-search。
第二步:修正 multi-search 裡的 indexUid
curl -X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
--data-binary '{
"queries": [
{ "indexUid": "products", "q": "headphones", "limit": 5 },
{ "indexUid": "blog_posts", "q": "headphones", "limit": 3 }
]
}'
{
"results": [
{ "indexUid": "products", "hits": [...], "processingTimeMs": 1 },
{ "indexUid": "blog_posts", "hits": [...], "processingTimeMs": 2 }
]
}
排查建議
- multi-search 的 indexUid 建議用設定常量或枚舉,別硬編碼字符串——打錯了編譯器/IDE 能發現。
- 錯誤消息只列第一個發現的問題——修完第一個重發,可能又冒出第二個。所以建議每條 query 先單獨驗證通過再合併。
- 如果你真的需要部分成功的語義(比如 3 個索引搜,其中一個暫時掛了但另外兩個繼續返回),別用 multi-search,在應用層併發發獨立的 search 請求,哪個成功就用哪個的結果。
References(參考來源)
- Multi-search overview — Meilisearch 官方文檔meilisearch-docs
- Multi-search API reference — Meilisearch 官方文檔meilisearch-docs
