Elasticsearch查询优化

南墨2年前技术文章823

1 使用更快的硬件

查询性能大部分场景下更多的在于IO能力,很多时候查询速度受限于磁盘IO能力,使用SSD会比旋转类存储介质好得多。

如果查询类型属于计算比较多的,则可以考虑使用更快的CPU

2 为文件系统cache预留足够的内存

在一般情况下,读写都会被操作系统cachecache保存在系统物理内存中。命中cache可以降低对磁盘的直接访问频率。查询依赖对cache的命中,如果某个请求需要从磁盘读取数据,则一定会产生相对较高的延迟。

应该至少为系统cache预留一半的可用物理内存,更大的内存有更高的cache命中率。

3 Mappings优化

请确认mappings设置是否合理。

1.       对于只需要精确查询的字段,例如时间戳,应该设置为keyword

2.       对需要进行全文检索的字段设置合理的分词器,不同的分词器查询效率相差较大。

4 强制段合并历史索引

为不再更新的历史索引执行force merge,讲Lucene索引合并为单个分段,可以提高查询速度。当一个Lucene索引存在多个分段时,每个分段会单独执行查询再讲结果合并,将只读索引强制合并成一个Lucene分段不仅可以优化查询过程,对索引恢复速度也是有好处的。

curl -XPOST --tlsv1.2 --negotiate -k -u : 'https://ip:httpport/_all/_forcemerge?only_expunge_deletes=false&max_num_segments=1&flush=true&pretty'

5 过滤查询(filter

Elasticsearch的查询操作分为2种:查询(query)和过滤(filter),查询(query)默认会计算每个返回文档的得分,然后根据得分排序;而过滤(filter)只会筛选出符合的文档,并不计算得分,且可以缓存文档。

对于非全文检索的使用场景,如果不关心查询结果和查询条件的相关度,只是想查找目标数据,可以使用filter来提高查询效率。

6 路由(routing

Elasticsearch写入文档时,文档会通过一个公式路由到一个索引中的一个分片上。默认公式如下:

shard_num = hash(_routing) % num_primary_shards

_routing字段的取值,默认是_id字段,可以根据业务场景设置经常查询的字段作为路由字段。例如可以考虑将用户id、地区作为路由字段,查询时可以过滤不必要的分片,加快查询速度。

7 游标查询(scroll

Elasticsearch为了避免深分页,不允许使用分页(from&size)查询10000条以后的数据,需要使用游标(scroll)查询。

优化scroll:在一般场景下,scroll用来取得排序好的大量数据,但很多时候只需要返回数据,这时候可以对scroll进行优化。使用_docsort返回的结果不会有排序,此时执行效率最快。

8 避免使用wildcard模糊匹配查询

Elasticsearch默认支持通过*?正则表达式来做模糊匹配,数据量级别达到TB+甚至更高之后,模糊匹配查询通常会耗时比较长,甚至可能导致内存溢出,卡死乃至崩溃宕机的情况。所以数据量大的情况下,不要使用模糊匹配查询。

9 调节查询请求中的batched_reduce_size

该字段是查询请求中的一个参数。默认情况下,聚合操作在协调节点需要等待所有的分片都取回结果后才执行,使用batched_reduce_size参数可以不等待全部分片返回结果,而是在指定数量的分片返回结果之后就可以先处理一部分(reduce)。这样可以避免协调节点在等待全部结果的过程中占用大量内存,避免极端情况下可能导致OOM。该字段的默认值为512

10 使用自适应副本选择(ARS

为了充分利用计算资源和负载均衡,协调节点将查询请求轮询转发到分片的每个副本,轮询策略是负载均衡过程中最简单的策略。

Elasticsearch实现了可以评估出副本所在节点的压力和健康程度,这就可以让我们选出一个能够更快返回搜索请求的节点。可以通过命令动态开启:

cluster.routing.use_adaptive_replica_selection:true

11 聚合查询优化

大多时候对单个字段的聚合查询还是比较快的,但是当需要聚合多个字段时,就会产生大量的分组,最终结果就是占用Elasticsearch大量的内存,从而导致内存溢出的情况发生。尽量根据业务优化,减少聚合次数。

11.1 默认深度优先聚合改为广度优先聚合

添加设置:"collect_mode": "breadth_first"

depth_first  :直接进行子聚合的计算。

breadth_first  :先计算出当前聚合的结果,针对这个结果在对子聚合进行计算。

11.2 优化聚合执行方式

在每一层terms aggregation内部加一个 execution_hint: map”。

添加设置:"execution_hint": "map"

1.       查询结果直接放入到内存中构建map,在查询结果集小的场景下,速度极快;

2.       但如果查询结果集合很大(百万-亿级别)的时候,传统聚合方式会比map方式快。

11.3 预热全局序号

全局序号是一种数据结构,用于在keyword字段上运行terms聚合。它用一个数值来代表字段中的字符串值,然后为每一个数值分配一个bucket。这需要一个对全局序号和bucket的构建过程。默认情况下,它们被延迟构建,因为Elasticsearch不知道哪些字段将用于terms聚合,哪些字段不会。可以通过配置mappingrefresh时告诉Elasticsearch预先加载全局序号:

"mappings": {
"type": {
"properties": {
"foo":{
"type": "keyword",
"esager_global_ordinals"true
}
}
}
}



相关文章

Elasticsearch查询慢日志配置

shard级别的查询慢日志会将慢查询(查询和获取阶段)记录到elasticsearch_cluster_index_search_slowlog.log日志中。设置查询慢日志各种级别下的阀值,同时也支...

切换不同的网络访问同一个业务报错"network error"

切换不同的网络访问同一个业务报错"network error"

问题现象:业务:xxx,使用谷歌浏览器登陆之后,访问“商品档案”模块,会提示“network error”报错内容,但是切换到其他浏览器测试是可以正常访问的,同时,在使用谷歌浏览器访问的情况下,如果切...

MySQL索引与事务的透析——(超详解)

MySQL索引与事务的透析——(超详解)

索引2.1索引存在意义在数据库使用select查询数据的时候有以下几个步骤:1.先遍历表;2.在把当前的行带入条件看条件是否成立;3.若成立则保留,反之就不保留,跳过;那么在一个表的数据非常大的时候,...

远程DEBUG HADOOP源码方法

远程DEBUG HADOOP源码方法

1. 安装IDEA2. 下载hadoop源码,必须与集群服务代码版本一致,否则会导致有的类无法找到3. 将源码导入IDEA工程并完成build4. 点击 菜单栏--运行--编辑配置 进行相关debug...

Python 并发编程 Futures

Python 并发编程 Futures

说明编程中如果能合理利用编程语言的并发编程技巧,都可以极大提升程序的性能。在 Python 3.2 版本为用户提供了一个标准库 concurrent.futures 可以实现进程池 和 线程池,本篇文...

kafka常见配置参数解析

broker.idbroker 的全局唯一编号,不能重复,只能是数字num.network.threads=3处理网络请求的线程数量num.io.threads=8用来处理磁盘 IO 的线程数量soc...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。