好久没看书了,最近闲来无事,针对ES的range查询的一些毛刺问题,想办法如何去降低(避免是避免不了了)。无意中在ES的官网看到一篇博客,光看标题肯定就觉的吊炸天了吧。
话说Elasticsearch 5.2 开始就引入了integer_range,float_range, long_range,double_range和date_range,好吧,老实说,之前从来没有关心过它。直到有一天突然想到一个问题.....
需求
话说,在电商系统里,其实很多的库都会有档期的概念,专场会有始末时间,商品打折也有,总结就是很多的表都会有类似一个xxx_start_time 和xxx_end_time这两个冬冬。
好,那么我们通常要筛选出一批商品列表,专场列表,上架列表等等,我们就需要分别对start 和end做range操作,那自然而然就用到下面这样的搜索:
"bool": {
"filter": [
{
"range": {
"merchand.show_from": {
"lt": "1533026579999"
}
}
},
{
"range": {
"merchan.show_to": {
"gt": "1533026579999"
}
}
}
]
}
大家都知道Lucene6.0 开始对于数字类型用的是一种新的BKD-Tree 数据结构,整棵树首先是不会完全常驻内存,并且通过range计算时对于数据集大时,build 出 bit set 和build scorer都需要不少时间。
上面的例子,输入的仅仅只是一个时间点,但是其实查询的是分别对两个字段做了range,假如第一个range从10亿集合中得出结果集是10w,耗时50ms,第二个range也同样从10亿集合得出10w,耗时50ms,(这里我们暂且忽略doc values 的情形,先讨论两个都走索引,最坏情况!)而最后做完交集可能只有几十个doc id 命中了。那其实是不是很冤枉,因为时间都耗在无谓地对那些结果集做bit set 和build scorer。
后来我在想,有没有一种类似GeoLatLonPoint这样的数据结构,可以把 start_time,end_time 都可以塞入一个字段中,那么其实我查询的话通过对区间来做结果集筛查,往往就能大大压缩return 的