配置项作用 #
search.allow_expensive_queries 配置项控制是否允许执行被认为是"昂贵"(expensive)的查询操作。昂贵查询通常指那些可能消耗大量资源(CPU、内存)或执行时间过长的查询类型,如脚本查询、正则表达式查询等。
配置项类型 #
该配置项为动态配置,可以在运行时通过集群设置 API 进行修改。
默认值 #
true(允许昂贵查询)
是否必需 #
可选配置项(有默认值)
取值范围 #
true - 允许昂贵查询
false - 禁止昂贵查询
配置格式 #
# 默认配置(允许)
search.allow_expensive_queries: true
# 禁止昂贵查询
search.allow_expensive_queries: false
相关配置项 #
| 配置项 | 默认值 | 说明 |
|---|---|---|
search.allow_expensive_queries | true | 允许昂贵查询 |
search.max_buckets | 65535 | 最大聚合桶数 |
indices.query.bool.max_clause_count | 1024 | 最大布尔子句数 |
工作原理 #
昂贵查询检查机制:
┌─────────────────────────────────────────────────────────────────┐
│ 昂贵查询检查流程 │
└─────────────────────────────────────────────────────────────────┘
查询请求到达
│
▼
检查 allow_expensive_queries
│
├── true(允许)
│ │
│ └── 执行所有类型查询
│ - 脚本查询 ✓
│ - 正则表达式查询 ✓
│ - 复杂聚合 ✓
│
└── false(禁止)
│
└── 检查查询类型
│
├── 非昂贵查询 → 执行 ✓
│ - 简单 term 查询
│ - 基本匹配查询
│
└── 昂贵查询 → 拒绝 ✗
│
└── 返回错误:
"queries of type [XXX] are not allowed"
昂贵查询类型 #
常见昂贵查询类型:
1. 脚本查询 (Script Query)
- 需要运行脚本引擎
- CPU 密集型
- 可能执行复杂计算
2. 正则表达式查询 (Regexp Query)
- 复杂的正则匹配
- 可能回溯导致性能问题
- 字符越长越慢
3. 模糊查询 (Fuzzy Query)
- 模糊匹配算法
- 计算相似度
- 可能生成大量查询
4. 复杂脚本聚合
- 脚本化聚合
- 大量数据处理
- 内存密集型
5. span 查询系列
- 复杂的位置查询
- 计算密集型
使用场景 #
1. 默认配置(推荐) #
search.allow_expensive_queries: true
适用场景:
- 大多数生产环境
- 需要复杂查询功能
- 有性能监控和限制
2. 禁止昂贵查询 #
search.allow_expensive_queries: false
适用场景:
- 资源受限环境
- 防止滥用
- 多租户环境
- 需要保护集群稳定性
3. 临时禁止 #
# 临时禁止昂贵查询,进行集群保护
PUT /_cluster/settings
{
"transient": {
"search.allow_expensive_queries": false
}
}
适用场景:
- 集群负载过高
- 紧急性能问题
- 维护操作
推荐设置建议 #
| 环境 | 推荐值 | 说明 |
|---|---|---|
| 生产环境 | true | 根据需要使用 |
| 资源受限 | false | 保护集群 |
| 多租户 | false | 防止滥用 |
| 开发测试 | true | 方便调试 |
| 受控访问 | true | 配合其他限制 |
性能影响分析 #
允许昂贵查询的影响:
优点:
✓ 支持复杂查询功能
✓ 灵活性高
✓ 满足业务需求
缺点:
✗ 可能消耗大量资源
✗ 可能影响其他查询
✗ 可能导致集群不稳定
禁止昂贵查询的影响:
优点:
✓ 保护集群资源
✓ 防止滥用
✓ 提高稳定性
缺点:
✗ 限制查询能力
✗ 可能影响业务
✗ 需要替代方案
查询替代方案 #
昂贵查询的替代方案:
1. 脚本查询 → 使用 runtime field
- 脚本查询慢
- runtime field 更高效
- 可以缓存
2. 正则表达式查询 → 使用 wildcard/edge_ngram
- 正则查询可能很慢
- wildcard 查询更快
- edge_ngram 适合前缀匹配
3. 复杂聚合 → 预聚合/分区
- 复杂聚合消耗资源
- 使用 transform 预聚合
- 使用分区聚合
4. 大范围查询 → 使用索引策略
- 时间范围查询
- 使用索引生命周期管理
- 按时间分索引
动态配置示例 #
# 禁止昂贵查询
PUT /_cluster/settings
{
"transient": {
"search.allow_expensive_queries": false
}
}
# 允许昂贵查询
PUT /_cluster/settings
{
"transient": {
"search.allow_expensive_queries": true
}
}
# 查询当前配置
GET /_cluster/settings?filter_path=*.search.allow_expensive_queries
监控建议 #
# 查看当前配置
GET /_cluster/settings?filter_path=*.search.allow_expensive_queries
# 查看慢查询
GET /_tasks?actions=*search&detailed=true&pretty
# 查看正在执行的查询
GET /_tasks?group_by=parents&pretty
# 查看查询性能统计
GET /_nodes/stats/indices/search?filter_path=**.query_total,**.query_time_in_millis
错误示例 #
禁止昂贵查询后的错误信息:
# 尝试执行脚本查询
GET /_search
{
"query": {
"script": {
"script": {
"source": "doc['field'].value > 100"
}
}
}
}
# 错误响应
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "queries of type [script] are not allowed"
}
]
}
}
安全考虑 #
多租户环境的安全考虑:
问题:
- 恶意用户可能执行昂贵查询
- 可能消耗所有资源
- 影响其他租户
保护措施:
1. 禁止昂贵查询
search.allow_expensive_queries: false
2. 限制查询复杂度
indices.query.bool.max_clause_count: 500
3. 限制聚合桶数
search.max_buckets: 10000
4. 使用查询超时
timeout: 30s
5. 使用字段数据缓存限制
indices.fielddata.cache.size: 20%
注意事项 #
- 动态更新:此配置为动态配置,可在线修改
- 查询类型:影响多种查询类型
- 业务影响:禁用可能影响业务功能
- 替代方案:考虑使用更高效的查询方式
- 监控配合:配合慢查询日志使用
- 渐进调整:可以先监控,再决定是否禁止





