Elasticsearch性能优化-慢查询

1,107 阅读2分钟

最近在做的需求,其中涉及到对Elasticsearch的操作,但实际上通过ES查询数据时性能上并不是很快,因此对ES语句进行分析。

{
    "query":{
        "bool":{
            "must":[
                {
                    "range":{
                        "created_date":{
                            "from":1609430400000,
                            "to":null,
                            "include_lower":true,
                            "include_upper":true,
                            "boost":1
                        }
                    }
                },
                {
                    "term":{
                        "ZMD_sign":{
                            "value":0,
                            "boost":1
                        }
                    }
                }
            ],
          
            "adjust_pure_negative":true,
            "boost":1
        }
    },
    "version":true,
    "_source":false
}

错用的数据类型

我们通过kibana的profile来进行分析,耗时到底在什么地方?es有一点就是开源社区很活跃,文档齐全,配套的工具也非常的方便和齐全。

image.png

可以看到有两个耗时比较大的,首先说索引的整体数据量在1000W左右,查询中其中一个是时间范围的查询,范围比较大耗时比较长,另外一个ZMD_sign计划使用的是等值查询,但是ES解析优化成个范围查询,并没有用上倒排索引,如果用上倒排索引的话时间复杂度是O(1)的, 这里涉及到一个知识点,那就是对于integer这种数字类型的处理。在es2.x的时代,所有的数字都是按keyword处理的,每个数字都会建一个倒排索引,这样查询虽然快了,但是一旦做范围查询的时候。比如 type>1 and type<5就需要转成 type in (1,2,3,4,5)来进行,大大的增加了范围查询的难度和耗时。

之后es做了一个优化,在integer的时候设计了一种类似于b-tree的数据结构,加速范围的查询,详细可以参考(elasticsearch.cn/article/446)

所以在这之后,所有的integer查询都会被转成范围查询,这就导致了上面看到的ZMD_sign的查询的解释。那么为什么范围查询在我们这个场景下,就这么慢呢?能不能优化。

两种方案:

第一种就是明明我们这个场景是不需要走范围查询的,因为如果走倒排索引查询就是O(1)的时间复杂度,将大大提升查询效率。由于业务在创建索引的时候,ZMD_sign这种字段建成了integer类型,导致最后走了范围查询,那么只需要我们将ZMD_sign类型改成keyword走term查询,就能用上倒排索引了。

第二种方案: 我查询了一下,ZMD_sign 这个值我们取的是 must=0的,es优化成范围查询后数据量范围大概在900W左右,但是如果我们用must_not=1来做范围查询的话,为1的数据量范围大概是50W左右,尝试更改了下查询语句,果然查询时间降了下来。

image.png

总结

ES在创建索引初期,考虑好当前字段的使用场景,使用正确的类型,会对ES查询性能的提升有很大帮助。