must_not 必须不匹配
搜索发布日期为2019-12-20,或歌曲ID为2a8f4288-c0a9-5c9b-8f99-67339b66f4c0,但发布日期不能是2019-12-21的歌曲 GET /music/children/_search { "query": { "constant_score": { "filter": { "bool": { "should": [ {"term":{ "releaseDate":"2019-12-20" }}, {"term":{ "id":"2a8f4288-c0a9-5c9b-8f99-67339b66f4c0" }} ], "must_not": { "term": { "releaseDate":"2019-12-21" } } } } } } } 搜索歌曲ID为2a8f4288-c0a9-5c9b-8f99-67339b66f4c0,或者是歌曲ID为34116101-7fa2-5630-a1a4-1735e19d2834而且发布日期为2019-12-20的帖子 GET /music/children/_search { "query": { "constant_score": { "filter": { "bool": { "should": [ {"term":{ "id":"2a8f4288-c0a9-5c9b-8f99-67339b66f4c0" }}, { "bool": { "must" : [ { "term" : { "id":"34116101-7fa2-5630-a1a4-1735e19d2834" }}, { "term" : { "releaseDate":"2019-12-20" }} ] } } ] } } } } } 多值搜索使用语法terms,可以同时搜索多个值,类似mysql的in语句。
GET /music/children/_search { "query": { "constant_score": { "filter": { "terms": { "id": [ "34116101-7fa2-5630-a1a4-1735e19d2834", "99268c7e-8308-569a-a975-bbce7d3f9a8e" ] } } } } } 范围查询针对Long类型和date类型的数据,是支持范围查询的,使用gt、lt、gte、lte来完成范围的判断。与mysql的>、<、>=、<=以及between...and异曲同工。
搜索时长在45-60秒之间的歌曲对Long类型的范围查询,直接使用范围表达式:
GET /music/children/_search { "query": { "constant_score": { "filter": { "range": { "length": { "gte": 45, "lte": 60 } } } } } } 日期的范围搜索针对日期的范围搜索,除了直接写日期,加上常规的范围表达式之外,还可以使用+1d、-1d表示对指定日期的加减,如"2019-12-21||-1d"表示"2019-12-20",也可以使用now-1d表示昨天,挺有趣。
给个示例:搜索2019-12-21前一天新发布的歌曲
GET /music/children/_search { "query": { "constant_score": { "filter": { "range": { "releaseDate" :{ "gt":"2019-12-21||-1d" } } } } } } Null值处理倒排索引在建立时,是不接受空值的,这就意味着null,[],[null]这些各种形式的null值,不无法存入倒排索引的,那这样怎么办?
Elasticsearch提供了两种查询,类似于mysql的is not null和not exists。
存在查询exists查询,会返回那些指定字段有值的文档,与mysql的is not null类似。
案例中的tags字段,就是一个选填项,有些记录可能是null值,如果我需要查询所有的tags值的记录,请求如下:
GET /music/children/_search { "query": { "constant_score": { "filter": { "exists": { "field": "tags" } } } } } 缺失查询缺失查询原来是有关键字missing表示,效果与exists相反,语法上与mysql的is null类似,但6.x版本就已经废弃了,我们可以改用must not + exists实现相同的效果。
还是使用tags字段为例,查询tags为空的文档:
GET /music/children/_search { "query": { "bool": { "must_not": { "exists": { "field": "tags" } } } } } filter缓存过滤器为什么效率那么高?除了本身的设计集合来达到高效过滤之外,还将查询结果适当地缓存化。
filter执行原理我们了解一下Elasticsearch对过滤器的简单操作:
根据fitler条件查找匹配的文档,获取document list。如果有多个过滤条件且涉及多个字段,那么就会有多个document list,document list是按倒排索引来的。
根据document list构建bitset(包含0或1的数组),匹配了是1,没匹配上为0,如[1,0,0,0]。
迭代所有的bitset,从最稀疏的开始(可以排除到大量的文档),取数组相同位置所有值为1的记录。
将bitset缓存在内存中,用于提高性能。
filter比query好处是会caching,下次不用查倒排索引,filter大部分情况下在query之前执行query会计算doc对搜索条件的relevance score,还会根据这个score去排序
filter简单过滤出想要的数据,不计算relevance score,也不排序
最近的256个filter中,某个filter超过一定次数(次数不固定),就会自动缓存这个filter对应的bitset。
filter针对小segment获取的结果,可以不缓存,segment<1000条或segment大小<index总大小的 3%。原因是数据量小,重新扫描很快,太小的segment在后台会自动合并到大的segment中,缓存意义不大
缓存更新缓存的更新非常智能,增量更新的方式,如果有document新增或修改时,会将新文档加入bitset,而不是删除缓存或整个重新计算。
小结本篇前半部分使用了大量的示例,可以快速阅读,后面介绍了filter的过滤原理及缓存处理机制,可以了解一下,谢谢。