ES通过抽样agg聚合性能提升3-5倍

一直以来,es的agg聚合分析性能都比较差(对应sql的 group by)。特别是在超多数据中做聚合,在搜索的条件命中特别多结果的情况下,聚合分析会非常非常的慢。
一个聚合条件:聚合分析请求的时间 = search time + agg time
N个聚合条件:聚合分析请求的时间 = search time + agg time * N
搜索的数据范围越大,聚合请求时间越长。
搜索条件命中的数据越多,聚合请求的时间越长。
搜索的字段,不一样的值越多,聚合请求时间越长。例如性别字段,通常仅有3个取值(男、女、未知),这种属于取值少的。像邮箱字段,值非常多,上亿个。这种就属于高基数字段。同样的搜索条件,高基数字段的聚合耗时会多非常多!
聚合请求时候非常吃cpu 和io资源的。通常在大数据检索场景下,很难支持高并发的聚合。并发上去以后,先是CPU飙升,再是IO飙升,随之load很高很高。其根本原因,从agg聚合的源码来看。因为聚合请求分为两个阶段,先根据条件查询数据。然后将命中的全部数据,放在内存中做计算。在第二个过程中,因为将所有命中的数据全部取回来,然后做计算,就涉及到了非常多的小文件的IO。IO会蹭蹭蹭的飙升。
就目前而言,在不改源码的情况下,聚合性能很难有很大的突破。本篇文章,通过抽样的思路,通过抽取分片,相当于数据剪枝的方式,来节省资源消耗。提升聚合分析性能,提升大概在3-5倍。随着数据越多,分片越多,资源越少,性能提升效果越明显。
我个人是做万亿级内容数据检索的。负责搜索集群,负责搜索优化。聚合分析性能优化,我应该说已经看了全网关于优化的文章。在实际数据体量非常大的前提下,实际效果不是太明显。
其中比较好的有这几篇文章。
es官方博文
Improving the performance of high-cardinality terms aggregations in Elasticsearch | Elastic Blog
Elasticsearch 聚合性能优化六大猛招-腾讯云开发者社区-腾讯云
Elasticsearch聚合优化 | 聚合速度提升5倍_es聚合速度-CSDN博客

抽样聚合方案

1.es原生抽样聚合

官方提供的采样聚合

参考文档:Sampler aggregation | Elasticsearch Guide [7.11] | Elastic

ES中的抽样聚合,意思是只对高质量的数据做聚合。比如,指定搜索条件,该搜索条件命中的数据为100W,对这100W数据,根据相关性分数排序。然后对这topK的数据做聚,比如每个shard上取200条评分最高的数据,去聚合。这就是ES sampler aggregation的含义。

2.es pre-filter机制

参考文档:Elasticsearch的search之_shards skipped之谜_布道的博客-CSDN博客__shards skipped

3.es在检索过程中指定分片

GET index_name/_search?preference=_shards:0

抽样抽分片的思路,只每次固定只检测其中一个分片。例如我们的索引一共300G,每个分片30G,一共有10个分片。在检索的过程中,只对其中一个分片做检索和聚合。其最终的聚合结果,根据我们的测试来看,效果还是非常不错的。聚合结果的分布情况和本来的terms聚合相差不大。性能也能提升个几倍。注意这种方式,聚合结果是近似的,并不是完全准确的(ES本身的聚合解结果就不是100%精准的)。

在大数据随机分布的情况下。在搜索命中大量数据情况下,其结果分布也是满足正态分布的。注意在搜索结果命中的结果集越多,其结果越符合正态分布,其聚合结果越接近标准值(原生terms聚合)。这里有一个值,一个经验值,在搜索提交条件命中大于10000的时候,可以用抽样,结果偏差不大。

注意,这里具体抽哪一个分片是有说法的。我们要考虑一个问题,同一个搜索条件,聚合结果应该是一致的。这里可以将搜索条件进行md5,然后取hash值,然后将hash值模上分片总数。这里只是一个思路。

ES官方的抽样聚合说明

抽样方案对比测试

对比测试了三种聚合分析的方式,其中包含了termssampler terms、和shard抽样(假如有10个shard,只对其中一个shard做搜索)

先说测试结论

官方的抽样,召回的结果和标准结果偏差较大。

官方的抽样,时间花费上,并没有太大的提升。

抽取分片,召回的结果和标准结果偏差不大。

抽取分片,时间花费上,性能提升3-5倍。资源花费为分片总数分之一。

响应时间对比如下

|--------------------|-------------|-------------------|-------------------|---------|
| 检索范围 | 检索条件 | 查询语法 | 响应时间 | 备注 |
| major_index_202303 | (北京 AND 暴雨) | terms | 4561 7694 | |
| major_index_202303 | (北京 AND 暴雨) | shard抽样 | 1423 2785 | 效果最好 |
| major_index_202303 | (北京 AND 暴雨) | terms sampler | 5650 3663 | 效果没有太明显 |

召回结果对比如下

|---------|---------------|------------|--------------------------|--------|
| 关键词 | terms(结果) | 抽取一个分片 | sampler terms(抽样200) | 备注 |
| 地区 | 4224 | 446 | 2094 | |
| 中国 | 3772 | 375 | - | |
| 发展 | 3605 | 342 | - | |
| 天气 | 3503 | 378 | 1942 | |
| 部分 | 2781 | 294 | 1525 | |
| 大雨 | 2395 | 236 | - | |
| 暴雨 | 2394 | 264 | 2454 | |
| 气温 | 2079 | 212 | 915 | |
| 局地 | 1851 | 199 | 1055 | |
| 工作 | 1741 | 187 | - | |
| 降雨 | - | - | 1111 | |
| 北京 | - | - | 827 | |
| 巴西 | - | - | 801 | |
| 灾害 | - | - | 801 | |

检索语句

这里使用的是query_string 检索语法。对比标准的terms聚合,官方的simple抽样,和抽分片。

复制代码
`  `"query":` `{`
    `"query_string":` `{`
      `"query":` `"""北京 AND 暴雨""",`
      `"fields":` `[`
        `"content^1.0",`
        `"title^1.0"`
      `],`
      `"type":` `"phrase",`
      `"tie_breaker":` `1,`
      `"default_operator":` `"and",`
      `"max_determinized_states":` `10000,`
      `"enable_position_increments":` `true,`
      `"fuzziness":` `"AUTO",`
      `"fuzzy_prefix_length":` `0,`
      `"fuzzy_max_expansions":` `50,`
      `"phrase_slop":` `0,`
      `"escape":` `false,`
      `"auto_generate_synonyms_phrase_query":` `true,`
      `"fuzzy_transpositions":` `true,`
      `"boost":` `1`
    `}`
  `}`
`

全部测试结果原始数据

|-------------------|-------------|-----------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 搜索范围 | 搜索条件 | 聚合方式 | 耗时情况ms | 返回结果 |
| major_info_202303 | (北京 AND 暴雨) | terms | 4561 7694 | [ { "key" : "地区", "doc_count" : 4224 }, { "key" : "中国", "doc_count" : 3772 }, { "key" : "发展", "doc_count" : 3605 }, { "key" : "天气", "doc_count" : 3503 }, { "key" : "部分", "doc_count" : 2781 }, { "key" : "大雨", "doc_count" : 2395 }, { "key" : "暴雨", "doc_count" : 2394 }, { "key" : "气温", "doc_count" : 2079 }, { "key" : "局地", "doc_count" : 1851 }, { "key" : "工作", "doc_count" : 1741 } ] |
| major_info_202303 | (北京 AND 暴雨) | terms sampler | 5650 3663 | [ { "key" : "暴雨", "doc_count" : 2454 }, { "key" : "地区", "doc_count" : 2094 }, { "key" : "天气", "doc_count" : 1942 }, { "key" : "部分", "doc_count" : 1525 }, { "key" : "降雨", "doc_count" : 1111 }, { "key" : "局地", "doc_count" : 1055 }, { "key" : "气温", "doc_count" : 915 }, { "key" : "北京", "doc_count" : 827 }, { "key" : "巴西", "doc_count" : 801 }, { "key" : "灾害", "doc_count" : 801 } ] |
| major_info_202303 | (北京 AND 暴雨) | terms + 指定shard | 1423 2785 | [ { "key" : "地区", "doc_count" : 446 }, { "key" : "天气", "doc_count" : 378 }, { "key" : "中国", "doc_count" : 375 }, { "key" : "发展", "doc_count" : 342 }, { "key" : "部分", "doc_count" : 294 }, { "key" : "暴雨", "doc_count" : 264 }, { "key" : "大雨", "doc_count" : 236 }, { "key" : "气温", "doc_count" : 212 }, { "key" : "局地", "doc_count" : 199 }, { "key" : "工作", "doc_count" : 187 } ] |

相关推荐
Lill_bin8 小时前
深入理解ElasticSearch集群:架构、高可用性与数据一致性
大数据·分布式·elasticsearch·搜索引擎·zookeeper·架构·全文检索
RwTo10 小时前
Elasticsearch 聚合搜索
大数据·elasticsearch·搜索引擎·全文检索
求学小火龙11 小时前
ElasticSearch介绍+使用
java·大数据·elasticsearch
檀越剑指大厂11 小时前
【Elasticsearch系列六】系统命令API
大数据·elasticsearch·搜索引擎
bug菌¹17 小时前
滚雪球学SpringCloud[5.1讲]: Spring Cloud Config详解
spring·elasticsearch·spring cloud
Li小李同学Li17 小时前
git学习【持续更新中。。。】
git·学习·elasticsearch
nangonghen18 小时前
通过logstash同步elasticsearch数据
大数据·elasticsearch
檀越剑指大厂19 小时前
【Elasticsearch系列四】ELK Stack
大数据·elk·elasticsearch
2401_8401922720 小时前
ELFK日志分析平台,架构和通信
elk·elasticsearch·架构
cyt涛1 天前
搜索功能技术方案
mysql·elasticsearch·全文检索·canal·索引·数据同步·搜索