最近在做的需求,其中涉及到对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有一点就是开源社区很活跃,文档齐全,配套的工具也非常的方便和齐全。
可以看到有两个耗时比较大的,首先说索引的整体数据量在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左右,尝试更改了下查询语句,果然查询时间降了下来。
总结
ES在创建索引初期,考虑好当前字段的使用场景,使用正确的类型,会对ES查询性能的提升有很大帮助。