关键字:
Elasticsearch,字符串类型的时间,时间比较,RangeQuey
场景:
没有手动指定es的mapping,借助spring data elastic search的相关注解标识,然后,启动的时候自动创建索引。其中有的时间被存储为text了。那么,我们在使用rangeQuery比较的时候,只有gt生效。
解决方案。在查询的时候, 添加.keyword,示例如下:
boolQueryBuilder.must(new RangeQueryBuilder(CatalogConst.QUERY_PREFIX + "licenseStart.keyword").gte(licenseStartValue).lte(licenseEndValue).format("yyyy-MM-dd HH:mm:ss"));
只要你是5.x以后的版本,上述操作是可以的。先拿去解决问题,然后看下边的分析:
1.ES5.0及以后的版本取消了string类型,将原先的string类型拆分为text和keyword两种类型。
两者的区别在于,text会对字段进行分词处理,而keyword不会。
当你没有实践indexTemplate等形式对你的索引字段手动指定mapping,ES就会使用Dynamic Mapping,通过你传入的文档中的字段的值,进行字段的动态映射。例如字段classroom传入数字26会被映射为long类型。ip的值"192.168.0.1",会被映射为ip类型。然而对于不满足ip和date格式的普通字符串,会被映射为text类型,但为了保留对这些字段进行精确查询与聚合的能力,又同时对他们做了keyword类型的映射。作为该字段的fields属性写入到_mapping中。所以。"yyyy-MM-dd HH:mm:ss" 类型的时间,会被当做text存储,又保留了keyword字段属性。如图:
2.range 支持text类型排序 用的是TermRangeQuery 使用BytesRef.compareTo(BytesRef)进行比较
number/date 类型 用的是 NumericRangeQuery,也就是按照数值排序。
所以,直接使用text类型的时间字符串无法正确的比较时间早晚,需要使用其keyword字段