【ElasticSearch】查询优化

【ElasticSearch】查询优化

  • 前言
  • 优化方案
    • File Cache
    • 数据预热
    • 冷热分离
    • 业务设计
    • 查询语句
      • 查询Fetch Source优化
      • 调整filter过滤顺序
      • 索引时间精度优化
      • 索引优化,合理使用keyword类型
      • reIndex索引
      • 禁止深分页查询

前言

最近做了一个需求当天申请数量限制的一个需求,需要查询用户当天的数据,因为数据规模还是蛮大的,而且每天的访问量就是主业务主流程的量,所以考虑从es中查询,但是压测之后发现耗时400~600ms,这坑定不能接受,所以就有了下面的优化之路。

优化方案

File Cache

【ElasticSearch】查询优化_第1张图片

我们向ES里写的数据,实际上都写到磁盘文件里去了,磁盘文件里的数据操作系统会自动将里面的数据缓存到os cache里面去。
ES的查询就严重依赖OS的File Cache,所以说内存分配的内存肯定是越多越好。最理想的情况就是FileCache的内存大小和存储的数据的大小差不多。即使达不到这个标准,最少也需要达到存储的数据的一半。

数据预热

其实和缓存的数据预热是一样的套路。
对于那些你觉得比较热点的,经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据,每隔一段时间,你就提前访问一下,让数据进入filesystem cache里面去。这样期待下次别人访问的时候,一定性能会好一些。
举个例子,就比如说,微博,你可以把一些大v,平时看的人很多的数据给提前你自己后台搞个系统,每隔一会儿,你自己的后台系统去搜索一下热数据,刷到filesystem cache里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,很快。

冷热分离

上面说了File Cache对ES的性能印象很大,所以FileCache资源极其宝贵,应该用在刀刃上,所以需要做冷热数据的分离操作。
比如我们现在主业务表上有一百多个字段,但是常用来查询的字段也就十几个,数据规模的下降性能不言而喻。这么做的好处就是占用内存空间小,可以把更多的数据放在内存中。否则的一百多个字段都会放到内存中,会占用太多的空间。一般来说可以采用ES+HBase(MongoDB)的模式来存储数据。也就是说把索引数据存储在ES中,先从ES中查到数据,构建记录的主键,然后根据主键去HBase(MongoDB)中根据主键去查其余的字段。

业务设计

对于一些比较复杂的关联查询,类似复杂SQL。ES的性能都不太好,所以可以在设计存入ES的数据模型的时候先做一部分工作,可以把关联关系直接放在数据模型中,这个通过ES就可以直接查询到。 也就是说把关联关系放在在业务代码中。

查询语句

查询Fetch Source优化

  • 问题
    业务查询语句获取的数据集比较大,并且从source中获取了非必须的字段,导致查询较慢。

举例:只需要从es中查询id这一个字段,却把所有字段查询了出来

  • 分析
    因为数据集较大,若每个字段都去source中获取所需字段,会导致耗时严重增加,需要避免这种操作,可以大大降低es集群,网络和客户端的压力,提高程序的性能。

  • 优化方法
    查语句查询时,将fetchSource设置为false

调整filter过滤顺序

  • 问题
    过滤效果不明显的条件放在了前面,导致查询出大量不需要的数据,导致查询变慢,还有就是如果不需要根据条件进行排序一定要使用filter,而避免使用must。

  • 优化方法
    把过滤效果明显的条件提前,按照过滤效果把过滤条件排序

索引时间精度优化

  • 分析
    降低时间精度。研究Filter的工作原理可以看出,它每次工作都是遍历整个索引的,所以时间粒度越大,对比越快,搜索时间越短,在不影响功能的情况下,时间精度越低越好,有时甚至牺牲一点精度也值得,当然最好的情况是根本不作时间限制。

  • 优化方法
    es重新刷索引,增加冗余的时间字段,精确到天。
    带有时间范围的查询使用该字段进行查询

索引优化,合理使用keyword类型

  • 分析
    ES5.x里对数值型字段做TermQuery可能会很慢。
    在ES5.x+里,一定要注意数值类型是否需要做范围查询,看似数值,但其实只用于Term或者Terms这类精确匹配的,应该定义为keyword类型。
    ES 2.x -> 5.x升级对于数值类型和Term Query有何重大变化?
    Lucene6.0引入了重新设计的数值类型的索引结构,不再采用倒排索,而是使用了更适合范围查找的Block K-d Tree。 ES从5.0开始引入这种新结构
    Term Query由于通常非常快,从5.1.1开始不再被缓存到Query Cache
    有兴趣的可以看一下详细分析:https://elasticsearch.cn/article/446

  • 优化方法
    把不做范围查询的数值类型修改为keyword类型

reIndex索引

先在管理平台创建新索引模板。模板名:xxx_new,设置索引生成规则

在导数据之前将新索引副本数设为0,这样导数据速度较快,导完数据再改为1 即可

通过脚本执行reIndex操作,需要记录开始时间time​

再次执行reIndex上次reIndex期间新写入的增量数据(time减去时差8小时) ,这一步的写入可能需要几分钟

操作动态配置,停止写入ES数据,然后再次reindex这几分钟内写入的增量数据,命令同上(这一次的写入可能就几秒钟了)

删除旧索引,并将新索引的别名设置为旧索引的名称

开启写入ES开关,并且重新导入停止写入ES期间的数据,并恢复各索引副本数为1。

禁止深分页查询

ES的深分页查询性能很差。最好不要用,用别的workaround。

你可能感兴趣的:(面试,es,查询优化)