场景

es查询报错,报错如下:

trying to create too many buckets. must be less than or equal to: [10000] but was [10001].

问题分析

显示网上搜索了一番,大都给出了问题原因,那就是ES聚合查询的聚合桶查询默认为10000,查询超过的时候,就会报错,导致查询失败。由于Bucket aggregations查询操作比较消耗内存,如果聚集桶过多,频率较大时,很容易导致集群JVM内存不足,进而产生查询熔断。

我们看下官网描述,确实是这么回事:

问题复现

注意官网的这一句话:

Requests that attempt to return more than this limit will return an error.
翻译:试图返回超过此限制的请求将返回错误。

那么我们来验证一下,复现一下问题:

环境说明:本人采用的是es7.8.1的版本进行演示测试,使用postman进行测试

创建测试聚合桶查询的索引库(PUT请求)

localhost:9200/testbuckets
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"price": {
"type": "long"
},
"color": {
"type": "keyword"
},
"size": {
"type": "long"
},
"category": {
"type": "keyword"
},
"label": {
"type": "keyword"
},
"release_date": {
"type": "date"
}
}
}
} ====返回====
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "testbuckets"
}

构建测试数据,为了模拟分桶数据,我将创建一些手机测试数据用于演示。

创建数据(PUT请求)

localhost:9200/testbuckets/_bulk
{"index":{}}
{"name":"小米13","price":3400,"color":"白色","size":6.21,"category":"小米","label":"高端","release_date":"2022-02-06"}
{"index":{}}
{"name":"小米13","price":3400,"color":"黑色","size":6.21,"category":"小米","label":"高端","release_date":"2022-02-06"}
{"index":{}}
{"name":"小米12","price":2400,"color":"黑色","size":6.21,"category":"小米","label":"快充","release_date":"2021-02-06"}
{"index":{}}
{"name":"苹果13","price":3400,"color":"黑色","size":6.21,"category":"苹果","label":"性能","release_date":"2022-02-06"}
{"index":{}}
{"name":"苹果14","price":2400,"color":"远峰蓝色","size":6.21,"category":"苹果","label":"性能","release_date":"2021-02-06"}
{"index":{}}
{"name":"华为Mate 50","price":5200,"color":"白色","size":6.21,"category":"华为","label":"鸿蒙OS","release_date":"2021-05-06"}
{"index":{}}
{"name":"华为Mate 50","price":5200,"color":"黑色","size":6.21,"category":"华为","label":"鸿蒙OS","release_date":"2021-05-06"}
{"index":{}}
{"name":"华为Mate 40 Pro","price":5900,"color":"黑色","size":6.21,"category":"华为","label":"商务","release_date":"2022-02-06"}
{"index":{}}
{"name":"华为Mate 40 Pro","price":5900,"color":"白色","size":6.21,"category":"华为","label":"商务","release_date":"2022-02-06"} ps:使用postman批量插入测试数据,最后一条记录后面需要换行,否则会插入失败

修改es最大分桶配置参数(PUT请求)

http://127.0.0.1:9200/_cluster/settings
{
"persistent": {
"search.max_buckets": 2 //为了演示,设值为2,官方默认此值为10000
}
}

构造聚合查询,在上面,我们创建了测试使用的手机索引库,此时,我们按照手机颜色进行数据聚合分组查询:

查询数据(GET请求)

http://127.0.0.1:9200/testbuckets/_search
{
"aggs": {
"by_color": { // 按照颜色合聚合
"terms": {
"field": "color" // 聚合字段
}
}
},
"size": 0 //不显示原始数据,只看分组数据
} ===返回结果===
{
"error": {
"root_cause": [
{
"type": "too_many_buckets_exception",
"reason": "Trying to create too many buckets. Must be less than or equal to: [2] but was [3]. This limit can be set by changing the [search.max_buckets] cluster level setting.",
"max_buckets": 2
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "testbuckets",
"node": "UuMcBk37TNWHjY4hVtzyVA",
"reason": {
"type": "too_many_buckets_exception",
"reason": "Trying to create too many buckets. Must be less than or equal to: [2] but was [3]. This limit can be set by changing the [search.max_buckets] cluster level setting.",
"max_buckets": 2
}
}
]
},
"status": 503
}

可以看到错误已经复现了,为什么呢,因为我们刚才将search.max_buckets配置参数改成了2,而实际上我们的测试数据里,如果根据color来分桶查询,会有黑色,白色,远峰蓝色这3种颜色,查询结果超过了限制值,就报错了,就证明了官方的Requests that attempt to return more than this limit will return an error的说法

我们将search.max_buckets改大一点再看(PUT请求)

http://127.0.0.1:9200/_cluster/settings
{
"persistent": {
"search.max_buckets": 3
}
}
===返回结果===
{
"acknowledged": true,
"persistent": {
"search": {
"max_buckets": "3"
}
},
"transient": {}
}

再次执行查询(GET请求),就会发现不报错了。

http://127.0.0.1:9200/testbuckets/_search
{
"aggs": {
"by_color": { // 按照颜色合聚合
"terms": {
"field": "color" // 聚合字段
}
}
},
"size": 0 //不显示原始数据,只看分组数据
}
===返回结果===
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"by_color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "黑色",
"doc_count": 5
},
{
"key": "白色",
"doc_count": 3
},
{
"key": "远峰蓝色",
"doc_count": 1
}
]
}
}
}

解决方案

方案一

修改配置(PUT请求):

// 临时修改,es重启失效
http://127.0.0.1:9200/_cluster/settings
{"transient": {"search.max_buckets": 50000}} // 永久修改,esc重启依旧生效
http://127.0.0.1:9200/_cluster/settings
{"persistent": {"search.max_buckets": 50000}}

服务器上可使用curl命令:

// 临时修改,es重启失效
curl -X PUT "http://127.0.0.1:9200/_cluster/settings" -H 'Content-Type: application/json' -d '{"transient":{"search.max_buckets": 50000}}' // 永久修改,esc重启依旧生效
curl -X PUT -k "http://127.0.0.1:9200/_cluster/settings" -H 'Content-Type: application/json' -d '{"persistent":{"search.max_buckets": 1000000}}'
说明:es一些配置修改,有两种方式,上面我修改最大分桶参数使用到了persistent,二者区别如下。
transient 临时:这些设置在集群重启之前一直会生效。一旦整个集群重启,这些设置就会被清除。
persistent 永久:这些设置永久保存,除非再次被手动修改。是将修改持久化到文件中,重启之后也不影响。

弊端:由于Bucket aggregations查询操作比较消耗内存,如果聚集桶过多,频率较大时,很容易导致集群JVM内存不足,进而产生查询熔断,所以不能无限制的扩大分桶数参数,需要结合实际服务器能力与业务需求来考量一个合适的值。

方案二

整改业务,大多场景下,对于查询结果是想获取到自己想要的精确少量结果,es 默认设置 10000 的上限是有原因的,这块需要对你的服务器性能有一个评估,考虑你的 es 服务是否能撑得住这种大量的聚合计算,冒然扩大限制可能导致服务的崩溃。如果预计的 buckets 数量级别过大,就需要结合具体场景分析在查询层面进行优化。

比如还拿我上面的手机测试库来看,如果非要不改配置而实现查询不报错,那么我们可以这样来优化一下查询业务。

此处仅做个参考思路演示,具体实际生产场景需要结合具体业务考虑。

http://127.0.0.1:9200/testbuckets/_search
{"query":{
"match":{
"category":"小米" // 限制查询手机类别,缩小数据范围,此处以小米品牌为例
}
},
"aggs": {
"by_color": {
"terms": {
"field": "color"
}
}
},
"size": 0 //不显示原始数据,只看分组数据
} ===返回结果====
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"by_color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "黑色",
"doc_count": 2
},
{
"key": "白色",
"doc_count": 1
}
]
}
}
}

ES实战-trying to create too many buckets的更多相关文章

  1. es实战之数据导出成csv文件

    从es将数据导出分两步: 查询大量数据 将数据生成文件并下载 本篇主要是将第二步,第一步在<es实战之查询大量数据>中已讲述. csv vs excel excel2003不能超过6553 ...

  2. 1W字|40 图|硬核 ES 实战

    前言 上篇我们讲到了 Elasticsearch 全文检索的原理<别只会搜日志了,求你懂点检索原理吧>,通过在本地搭建一套 ES 服务,以多个案例来分析了 ES 的原理以及基础使用.这次我 ...

  3. es实战之查询大量数据

    背景 项目中已提供海量日志数据的多维实时查询,客户提出新需求:将数据导出. 将数据导出分两步: 查询大量数据 将数据生成文件并下载 本文主要探讨第一步,在es中查询大量数据或者说查询大数据集. es支 ...

  4. Spring Boot & ES 实战,值得参考!

    作者:废物大师兄 cnblogs.com/cjsblog/p/9756978.html 1. 前言 1.1. 集成方式 Spring Boot中集成Elasticsearch有4种方式: REST C ...

  5. Spark2.2+ES6.4.2(三十二):ES API之index的create/update/delete/open/close(创建index时设置setting,并创建index后根据avro模板动态设置index的mapping)

    要想通过ES API对es的操作,必须获取到TransportClient对象,让后根据TransportClient获取到IndicesAdminClient对象后,方可以根据IndicesAdmi ...

  6. 2017 ES GZ Meetup分享:Data Warehouse with ElasticSearch in Datastory

    以下是我在2017 ES 广州 meetup的分享 ppt:https://elasticsearch.cn/slides/11#page=22 摘要 ES最多使用的场景是搜索和日志分析,然而ES强大 ...

  7. ElasticStack系列之十六 & ElasticSearch5.x index/create 和 update 源码分析

    开篇 在ElasticSearch 系列十四中提到的问题即 ElasticStack系列之十四 & ElasticSearch5.x bulk update 中重复 id 性能骤降,继续这个问 ...

  8. es与hive整合

    在hive classpath中添加elasticsearch-hadoop.jar,以下方法任一种均可: 1.启动hiveserver2 前,在hive-site.xml文件中更改hive.aux. ...

  9. Ceph RGW 创建默认的pool

    使用Ceph-deploy完成RGW服务部署后(最好是在部署RGW服务前建立如下这些pool),使用sudo ceph osd lspools 命令,会发现RGW自动以默认参数创建了N个rgw相关的p ...

  10. manage account

    #!/bin/bash # #Delete_user - Automates the steps to remove an account # ############################ ...

随机推荐

  1. 上午小博(java小知识)

    使用super来引用父类的成分,使用this来引用当前对象 一个类从另一个类继承,new这个子类的实例的时候,使用super来引用父类对象,this是指当前对象的引用. 当new一个对象出来的时候,这 ...

  2. cnpm : 无法将“cnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。所在位置 行:1 字符: 1

    出现问题原因: 使用vscode终端powershell控制台查看cnpm版本或者运行cnpm的相关命令时提示如标题错误(cmd控制台提示:'cnpm' 不是内部或外部命令,也不是可运行的程序或批处理 ...

  3. Java期末测试

    会议预约管理信息系统(50分)     1.项目背景: 会议是企业进行决策.协商的重要组织形式,是企业日常办公处理事务的重要手段,是办公流程中不可缺少的重要环节,作为企业,如何有效的进行会议组织,管理 ...

  4. 安卓逆向 HOOK 第一课 XP的安装以及编写

    <meta-data android:name="xposedmodule" android:value="true" /> <meta-da ...

  5. 大曝光!从RabbitMQ平滑迁移至Kafka架构设计方案!

    历史原因,公司存在多个 MQ 同时使用的问题,我们中间件团队在去年下半年开始支持对 Kafka 和 Rabbit 能力的进行封装,初步能够完全支撑业务团队使用. 鉴于在之前已经基本完全实施 Kafka ...

  6. 一位数左边补0,slice也可以

    以下三种方法都可以返回:"09" 1.n<10 ?'0'+n:''+n 2.('0'+n).slice(-2) 3.(''+n).padStart(2,'0')

  7. Java第五讲异常处理总结

    1. 在运行上述代码时javac产生idiv字节码指令,在运行下面的程序时javac产生ddiv字节指令,导致了两段代码运行结果不同. 2. 3.finally语句块一定会执行吗? /** * 自定义 ...

  8. 【Linux SPI】RFID RC522 设备驱动

    一.概述 MFRC522 支持 SPI.I2C.UART 接口,我在某宝上购买了一个 SPI 接口的 RC522 模块.此笔记主要要是通过 RC522 模块学习 linux 中的 SPI 驱动,方便今 ...

  9. Unity3D 不挂载脚本自动初始化

    https://blog.csdn.net/piai9568/article/details/98886028

  10. 死磕rmi之 RegistryImpl

    Registry初始化 可以把注册中心理解为特殊的远程对象,这个对象就像一个容器一样,存储其他远程对象. 可以本地直接调用四大方法,也可通过调用远程对象的方式调用. 查看一下类继承关系 可参照http ...