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
