ES 创建太多 buckets 错误: trying to create too many buckets. must be less than or equal to: [100000] but was [100001].
错误描述:
trying to create too many buckets. must be less than or equal to: [100000] but was [100001]. this limit can be set by changing the [search.max_buckets] cluster level setting.
一般的解决方法 调大 search.max_buckets
的值,在 kibana 中直接执行下列语句:
PUT /_cluster/settings
{
"persistent": {
"search.max_buckets": 20000
}
}
如果你的服务器能撑住,或者自身评估直接扩大并无问题,那么本文的阅读就可以到此为止了
但是我对扩张 search.max_buckets 感到担忧怎么办?
我们跟踪一个例子向下探索解决方案。
显然 es 默认设置 10000 的上限是有原因的,这块需要对你的服务器性能有一个评估,考虑你的 es 服务是否能撑得住这种大量的聚合计算,冒然扩大限制可能导致服务的崩溃。
如果预计的 buckets 数量级别过大,就需要结合具体场景分析在查询层面进行优化。
Tips 最终解决思路请直接移步文末
我这里实际遇到的需求场景是:
目前需要对用户在工作流中的自定义字段进行聚合
需要计算出当前工作流任务中 自定义字段选项的分布情况(仅支持单选、多选、多级选择)。
例如 有个自定义字段是 ”地区“ 其中有选项 ”北京“ ”上海“ ,那么就需要算出 填选了 北京 的任务有多少个 上海 的任务有多少个
// 一个最简原型 mapping
{
"work_flow" : {
"mappings" : {
"properties" : {
"create_time" : {
"type" : "date"
},
"fields" : {
"type" : "nested",
"properties" : {
"field_id" : {
"type" : "long"
},
"field_type" : {
"type" : "long"
},
"field_value" : {
"type" : "text"
},
"field_value_key" : {
"type" : "keyword"
}
}
},
"group_id" : {
"type" : "long"
},
"task_id" : {
"type" : "long"
}
}
}
}
}
虽然我们需求上限制了 仅支持单选、多选、多级选择,但是自定义字段的 es index 是在一起的,上述需求聚合时免不了要对字段值进行分桶聚合,此时就会将可以开放填写的文本字段也聚合进来,即使这个字段值仅仅只有 1 个任务匹配。当这个工作流中的任务基数足够大的时候就会产生分桶爆炸。
GET /work_flow/_search
{
"size": 0,
"timeout": "5s",
"query": {
"bool": {
"must": [
{
"term": {
"group_id": 666
}
},
{
"range": {
"create_time": {
"from": 1625068800000,
"to": 1627487999000
}
}
}
]
}
},
"track_total_hits": false,
"aggregations": {
"fields": {
"nested": {
"path": "fields"
},
"aggregations": {
"fields.field_id": {
"terms": {
"field": "fields.field_id",
"size": 2147483647
},
"aggregations": {
"fields.field_value_key": {
"terms": {
"field": "fields.field_value_key",
"size": 2147483647
}
}
}
}
}
}
}
}
有一个思路是对字段类型进行过滤后进行聚合,这个思路看似是可行的,但是忽略了一个问题,当前索引是以任务为基本单位存储数据的,自定义字段仅仅是附属值,而一个任务可能多个自定义字段都有值,所以这个过滤可以生效,但是效果并不大。而且如果你存了其他自定义字段的空值,这个过滤就完全没有效果了。但是聊胜于无,在查询时加下空串判断
GET /work_flow/_search
{
"size": 0,
"timeout": "5s",
"query": {
"bool": {
"must": [
{
"range": {
"create_time": {
"from": 1635696000000,
"to": 1638201599000
}
}
}
],
"filter": [
{
"term": {
"group_id": 666
}
},
{
"nested": {
"query": {
"bool": {
"must": [
{
"terms": {
"fields.field_type": [
2,
4,
5
]
}
}
],
"must_not": {
"term":{
"fields.field_value_key":""
}
}
}
},
"path": "fields"
}
}
]
}
},
"track_total_hits": false,
"aggregations": {
"fields": {
"nested": {
"path": "fields"
},
"aggregations": {
"fields.field_id": {
"terms": {
"field": "fields.field_id",
"size": 2147483647
},
"aggregations": {
"fields.field_value_key": {
"terms": {
"field": "fields.field_value_key",
"size": 2147483647
}
}
}
}
}
}
}
}
重新整理一下现在的问题:
es 首先根据我们的要求找到了目标工作流,并且过滤剩下了只包含了 单选,多选,多级选择 的任务 但是这些任务数据中同时可能包含其他自定义字段 之后 es 进行聚合统计,这里导致 trying to create too many buckets 的原因就是我们虽然进行了过滤,但最终数据不可避免的有无效数据参与了分桶。
基于上述的梳理,我大概有以下几个方案
方案:
- 为这类查询单独建立一个索引 (维护代价较大)。
- 分页
- 调小聚合 size
这里采用 2、3 结合的方式进行处理 聚合 size 考虑给到 200 ,具体可以根据场景进行调整
GET /work_flow/_search
{
"size": 0,
"timeout": "5s",
"query": {
"bool": {
"must": [
{
"range": {
"create_time": {
"from": 1635696000000,
"to": 1638201599000
}
}
}
],
"filter": [
{
"term": {
"group_id": 666
}
},
{
"nested": {
"query": {
"bool": {
"must": [
{
"terms": {
"fields.field_type": [
2,
4,
5
]
}
}
],
"must_not": {
"term":{
"fields.field_value_key":""
}
}
}
},
"path": "fields"
}
}
]
}
},
"track_total_hits": false,
"aggregations": {
"fields": {
"nested": {
"path": "fields"
},
"aggregations": {
"fields.field_id": {
"composite": {
"size": 5,
"sources": [
{
"fields": {
"terms": {
"field": "fields.field_id"
}
}
}
]
},
"aggregations": {
"fields.field_value_key": {
"terms": {
"field": "fields.field_value_key",
"size": 200
}
}
}
}
}
}
}
}
这里对 fieldId 进行了分页,加入了 composite
"composite": {
"size": 5,
"sources": [
{
"fields": {
"terms": {
"field": "fields.field_id"
}
}
}
]
},
返回时会返回 after_key
下次请求时带上
"fields.field_id" : {
"after_key" : {
"fields" : 185
}
"fields.field_id": {
"composite": {
"size": 1,
"sources": [
{
"fields": {
"terms": {
"field": "fields.field_id"
}
}
}
],
"after": {"fields":185}
},
这里 DSL 的思路已经搞定了,那么在 Java 代码层面,只需要进行分页分部查询,最后聚合数据即可。文章来源:https://www.toymoban.com/news/detail-471211.html
最终解决思路:文章来源地址https://www.toymoban.com/news/detail-471211.html
- 缩小聚合数据范围 (探寻所有可用的限制条件,能限制尽量限制)
-
使用
composite
对聚合数据分页 (es 查询分页在代码层面最终聚合结果) - 调整合适的 size 大小 (如果你的聚合项有冗余数据,可以考虑调小结果 size)
到了这里,关于ES 创建太多 buckets 错误: trying to create too many buckets. must be less than or equal to: [100000] but w的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!