配置项作用 #
index.max_result_window 配置项控制索引查询中 from + size 的最大值。此配置限制分页查询的结果窗口大小,防止过大的分页请求导致内存溢出。
配置项类型 #
该配置项为动态配置,可以在运行时通过索引设置 API 进行修改。
默认值 #
10000
是否必需 #
可选配置项(有默认值)
取值范围 #
1 ~ 正整数
配置格式 #
# 默认配置
index.max_result_window: 10000
# 增加窗口大小
index.max_result_window: 50000
# 减少窗口大小(保护集群)
index.max_result_window: 1000
工作原理 #
分页查询使用 from 和 size 参数:
┌─────────────────────────────────────────────────────────────────┐
│ 分页查询原理 │
└─────────────────────────────────────────────────────────────────┘
查询请求:
GET /my_index/_search
{
"from": 9000,
"size": 100
}
结果窗口计算:
window = from + size = 9000 + 100 = 9100
验证:
if (window <= max_result_window) {
允许查询
} else {
拒绝查询 (Result window is too large)
}
from + size 机制 #
传统分页:
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 第1页: from=0, size=10 返回文档 1-10 │
│ 第2页: from=10, size=10 返回文档 11-20 │
│ 第3页: from=20, size=10 返回文档 21-30 │
│ ... │
│ 第1000页: from=9990, size=10 │
│ window = 9990 + 10 = 10000 = max_result_window ✓ │
│ │
│ 第1001页: from=10000, size=10 │
│ window = 10000 + 10 = 10010 > max_result_window ✗ │
│ 报错: Result window is too large │
│ │
└─────────────────────────────────────────────────────────────────┘
使用场景 #
1. 默认配置(大多数场景) #
index.max_result_window: 10000
适用于常规分页查询,每页 10-50 条记录。
2. 大数据量导出 #
index.max_result_window: 100000
警告: 增加此值会显著增加内存使用和垃圾回收压力。
3. 严格限制(保护集群) #
index.max_result_window: 1000
防止用户请求过大的分页。
4. 小数据索引 #
index.max_result_window: 50000
适用于数据总量确定的小索引。
使用示例 #
创建索引时设置:
PUT /my_index
{
"settings": {
"index.max_result_window": 50000
}
}
动态修改:
# 增加窗口大小
PUT /my_index/_settings
{
"index.max_result_window": 50000
}
# 减少窗口大小
PUT /my_index/_settings
{
"index.max_result_window": 5000
}
常见错误 #
超过窗口限制:
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10050]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
]
}
}
替代方案 #
对于深度分页,建议使用以下替代方案:
1. Scroll API #
# 初始化滚动查询
GET /my_index/_search?scroll=5m
{
"size": 1000,
"query": {
"match_all": {}
}
}
# 使用滚动 ID 获取下一批
GET /_search/scroll
{
"scroll": "5m",
"scroll_id": "..."
}
2. Search After #
GET /my_index/_search
{
"size": 100,
"query": { "match_all": {} },
"sort": [{"_id": "asc"}],
"search_after": ["last_doc_id"]
}
3. PIT (Point In Time) #
# 创建 PIT
POST /my_index/_pit?keep_alive=10m
# 使用 PIT 查询
GET /_search
{
"size": 100,
"pit": {
"id": "...",
"keep_alive": "10m"
},
"query": { "match_all": {} },
"sort": [{"_shard_doc": "asc"}]
}
推荐设置建议 #
| 场景 | 推荐值 | 说明 |
|---|---|---|
| 默认 | 10000 | 通用场景 |
| 常规分页 | 10000 | 足够大多数应用 |
| 数据导出 | 100000+ | 配合 scroll API 使用 |
| 严格限制 | 1000-5000 | 保护集群资源 |
| 小索引 | 50000 | 数据总量明确的情况 |
性能影响分析 #
| max_result_window | 内存使用 | 查询性能 | 垃圾回收 | 适用场景 |
|---|---|---|---|---|
| 1000 | 低 | 高 | 低 | 严格限制 |
| 10000 | 中 | 中 | 中 | 默认配置 |
| 50000 | 高 | 低 | 高压力 | 大数据导出 |
| 100000+ | 很高 | 很低 | 很高压力 | 特殊场景 |
内存使用估算 #
每个命中文档的内存开销 ≈ 文档字段大小 + 元数据
估算公式:
内存使用 = (from + size) × 平均文档大小
示例:
from + size = 10000
平均文档大小 = 2KB
内存使用 ≈ 10000 × 2KB = 20MB
对于复杂查询(聚合、排序),内存使用会成倍增加
监控建议 #
# 查看当前配置
GET /my_index/_settings?filter_path=*.index.max_result_window
# 监控搜索拒绝
GET /_cat/nodes?v&h=name,search.thread_pool_rejected
# 查看搜索线程池
GET /_cat/thread_pool/search?v
常见问题 #
问题 1:深度分页报错
Result window is too large
解决方案:
- 增加 max_result_window
PUT /my_index/_settings
{
"index.max_result_window": 50000
}
- 使用 search_after(推荐)
GET /my_index/_search
{
"size": 100,
"query": { "match_all": {} },
"sort": [{"_id": "asc"}],
"search_after": ["last_id"]
}
问题 2:内存溢出
原因: max_result_window 设置过大
解决方案:
# 减少窗口大小
PUT /my_index/_settings
{
"index.max_result_window": 5000
}
问题 3:查询性能下降
原因: 深度分页必须从开始处理并丢弃结果
解决方案: 使用 search_after 或 scroll API
最佳实践 #
- 避免深度分页:尽量使用 search_after
- 保持合理窗口:默认值 10000 适合大多数场景
- 监控内存使用:跟踪 JVM 堆内存使用情况
- 使用专用 API:大数据导出使用 scroll API
- 考虑用户友好:限制分页深度(如最多 100 页)
注意事项 #
- 动态更新:此配置为动态配置,可在线修改
- 内存压力:增大此值会增加内存和 GC 压力
- 集群影响:多个大窗口查询同时运行可能导致集群问题
- 替代方案:深度分页应使用 search_after 或 scroll API
- 按需设置:根据实际需求调整,而非盲目增大





