最近线上的es报了一个异常,核心信息如下:
我们的es索引是嵌套索引,上面的这个异常大致意思是说在某个shard里面嵌套结构里面 k1.k2.time这个字段不存在数据,所以排序失败。
我们知道在ES里面可以分shard和索引,大多数时候我们es索引都是自动按某个规则创建的,比如说按天,按月,按年,这个用过logstash的同学应该都比较熟悉,收集的log基本上都是按天生成索引的,然后我们用kibana查询或者自己写代码查询。
下面看总结一些问题场景:
(场景1)查询一个不存在的索引
默认情况下,查询一个不存在的索引是会报异常的(no such index....) ,那么如何避免这个问题呢?
有两种办法:
A:每次查询前去使用es的索引api判断这个索引存在不存在,如果不存在就不进行任何操作,存在的话在执行查询,这样就能避免,但这样的问题就是每次都得判断存在不存在多一次查询交互。
B:在构建查询时,使用通配符标识索引,如果这个索引不存在,查询结果就是空,但是不会报异常,这样比较方便,不需要关注存在不存在问题。
一个java api的例子如下:
如上代码,查询这个不存在的索引,这段代码结果不会报错,推荐使用这种方法。
(场景2)查询一个不存在的字段
查询一个不存在的字段es是不会报错的
(场景3)排序一个不存在的字段
默认情况下,排序一个不存在的字段,在es里面也会报错。这里主要分三种情况:
A:排序的单个索引不存在这个字段
B:排序的单个索引存在这个字段,但是它分shard了,如果有3个shard,只有2个shard上有这个字段,另外一个shard上没有这个字段,那么它同样会报异常
C:跨索引查询,如果跨2个索引,一个索引上所有的shard都包含这个字段,另外一个索引有部分shard没有,那么也会出现这个问题
如何解决:
这个也比较好解决,在排序的时候,需要设置在maping里面不存在的里面,应该如何处理,容错代码如下:
注意unmappedType方法了,定义这个值不存在的时候,默认按什么类型处理。
(场景4)在一个不存在的字段上算count,max,min,sum,avg这些指标
求聚合统计这些指标时,也不会报错,但结果值列有不同,详情如下:
(场景5)分组一个不存在的字段
分组一个不存在的字段,也不会报错,返回结果是空
上面这些场景基本涵盖了查询统计大多数的可能出现的问题,需要我们在使用的时候需要注意一下,避免一些不必要的问题。
最后我们来介绍一下es里面一个有用的查询Exists Query:
功能:查询的字段至少有一个非null值才回返回
我们来看官网给的一个例子:
上面这个查询是查字段user的数据,是不是为空,注意下面的这些数据,是可以被匹配上
在来看下,那些情况,不能被匹配:
此外,Exists Query可以非常方便的替代Miss Query看下面的例子:
上面这个查询将返回没有user字段的数据,java api写法如下:
注意,经过测试发现一个嵌套索引里面,如果只有一个为空的数组,然后使用嵌套查询Exists Query是会报错的,而使用平铺的Exists Query是不会报错的,也就是说,嵌套的索引里面必须有一个不为空的对象存在,才能使用Exists Query查询语法,来查询相关字段不存在的数据 否则会报错,这一点目前还没看到有任何好的办法来校验多级嵌套结构下的某个索引里面到底存不存在某个嵌套结构,嵌套索引的判断是否存在大致一样 唯一需要注意到是,嵌套结构,一定有一条不为空的数据存在才行
关于嵌套索引结构的校验,请参考下面这个链接:
https://gist.github.com/Erni/7484095