federated search 的分頁是合併結果層面的——所有索引的結果混在一起後再分頁。所以分頁參數必須放在
federation物件裡,寫在單條 query 裡的offset/limit/page/hitsPerPage全部被靜默忽略,不報錯但也不生效。這是 Meilisearch 官方 API reference 明確寫的限制:「These options are not compatible with federated searches.」
Issue & Env(案發現場與環境)
- 業務場景:federated search 搜
movies和movie_ratings兩個索引,想讓 movies 只返回前 5 條、movie_ratings 返回前 10 條。結果發現兩個索引都返回了 20 條(預設 limit)——queries 裡寫的 limit 參數完全沒生效。 - 環境:Meilisearch v1.54+,帶
federation: {}或 federation 子參數的 multi-search 請求。 - 關鍵區分:這和 multi-index search(不傳 federation)相反——multi-index 模式下,每條 query 的 offset/limit 獨立生效。一用 federation,queries 裡的分頁參數就被引擎忽略了。
StackTrace(無報錯,靜默忽略)
# federation 模式下,queries 里的 limit 被忽略
curl -X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
--data-binary '{
"federation": {},
"queries": [
{ "indexUid": "movies", "q": "batman", "limit": 5 },
{ "indexUid": "movie_ratings", "q": "batman", "limit": 10 }
]
}'
{
"hits": [
{"id": 268, "title": "Batman", "_federation": {"indexUid": "movies", "queriesPosition": 0}}
],
"processingTimeMs": 1,
"limit": 20,
"offset": 0,
"estimatedTotalHits": 14
}
返回體裡 "limit": 20——federation 預設值,不是 queries 裡寫的 5 或 10。沒有任何報錯,queries 裡的 limit 被靜默忽略。
Root Cause(根因分析)
federated 分頁是合併層面的,不是單索引層面的
federated search 的處理流程是:
- 並行執行所有 query(不做單 query 分頁)
- 拿到所有命中文檔,按 merge 算法合併重排
- 對合併後的單列表做分頁
因為第 1 步不做分頁,queries 裡寫的 offset/limit/page/hitsPerPage 就沒有任何作用——引擎在執行時先忽略它們,合併完再用 federation 層的分頁參數來切。
兩套分頁體系,二選一
federation 物件裡支持兩種分頁模式:
| 模式 | 參數 | 返回體字段 | 適用場景 |
|---|---|---|---|
| estimation(預設) | federation.offset + federation.limit |
estimatedTotalHits |
大部分場景,性能好 |
| exhaustive | federation.page + federation.hitsPerPage |
totalPages, totalHits |
精確知道總數時(頁碼導航) |
不能混用——同時寫 federation.offset 和 federation.page,行為未定義,實踐中避免。
對比 multi-index 模式
不傳 federation 時,每條 query 的 offset/limit/page/hitsPerPage 獨立生效——因為每條 query 返回獨立的 results 陣列,分頁在單 query 層面做。一用 federation,分頁的「層級」就從單 query 升到了合併列表。
The Fix(解決方案)
第一步:把分頁參數移到 federation 物件裡
curl -X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
--data-binary '{
"federation": { "offset": 0, "limit": 20 },
"queries": [
{ "indexUid": "movies", "q": "batman" },
{ "indexUid": "movie_ratings", "q": "batman" }
]
}'
或者用 exhaustive 分頁:
curl -X POST 'http://localhost:7700/multi-search' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
--data-binary '{
"federation": { "page": 2, "hitsPerPage": 10 },
"queries": [
{ "indexUid": "movies", "q": "batman" },
{ "indexUid": "movie_ratings", "q": "batman" }
]
}'
第二步:如果需要單 query 限制,用 filter 或 weight 替代
如果你確實想讓 movies 的結果少一些、movie_ratings 的結果多一些,正確的做法不是在 query 裡寫 limit,而是用 weight 控制排名優先級——weight > 1.0 的 query 結果會更多地出現在合併列表的前面。或者在 query 里加 filter(比如只搜 genres = “Action” 的 movies)來減少命中數。
排查建議
- 觸發 federation 模式的唯一條件:請求體裡
federation字段存在(哪怕是{}空物件)。一旦 federation 存在,queries 裡的分頁參數就作廢。 - 這不是 bug 是設計——官方 API reference 明確寫了
offset/limit/hitsPerPage/page「not compatible with federated searches」。 - 沒有報錯 = 靜默忽略。所以調試時別假設「我寫了 limit: 5 為什麼返回了 20 條」——先確認自己是不是不小心加了
federation: {}。
References(參考來源)
- Federated search — Meilisearch 官方文檔meilisearch-docs
- Multi-search API reference — Meilisearch 官方文檔meilisearch-docs
