承接上篇文章Elasticsearch笔记-深入查询,本篇文章主要介绍过滤查询。
其实准确来说,ES中的查询操作分为2种:查询(query)和过滤(filter)。查询即是之前提到的query查询,它(查询)默认会计算每个返回文档的得分,然后根据得分排序。而过滤(filter)只会筛选出符合的文档,并不计算得分,且它可以缓存文档。所以,单从性能考虑,过滤比查询更快。
换句话说,过滤适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据。
过滤器使用
查询10月之前contents字段包含“ES”的文档
{
"query": {
"filtered":{
"query":{
"range":{
"date":{ "lte":"2016-10-01" } }
},
"filter":{
"match":{
"contents":"ES" }
}
}
}
}
过滤查询包含filtered
关键字,里面又包含普通的查询query
逻辑和filter
过滤逻辑。运行时先执行过滤语句,后执行普通查询。对比下面只使用了查询的DSL:
{
"query": {
"bool":{
"must":[{
"range":{
"date":{ "lte":"2016-10-01" } }
},{
"match":{
"contents":"ES" }
}]
}
}
}
两者返回结果是一样的。
过滤器类型
过滤器类型与查询类型基本相对应,都有范围(过滤)查询、term、terms等类型。
term、terms过滤
term、terms的含义与查询时一致。term用于精确匹配、terms用于多词条匹配。不过既然过滤器既然适用于大氛围过滤,term、terms在过滤中使用意义不大。
举例见前面过滤器使用一节
范围过滤(range)
查询16年10月以来所有内容含有“java”的文档,先过滤剩下符合10月的文章,再精确匹配。
{
"query": {
"filtered":{
"query":{
"match":{
"contents":"java" }
},
"filter":{
"range":{
"date":{ "gte":"2016-10-01" } }
}
}
}
}
exists、mising过滤器
exists过滤指定字段没有值的文档
{
"query": {
"filtered":{
"filter":{
"exists":{
"field":"id" }
}
}
}
}
将不返回id
字段无值的文档。
missing
过滤器与exists
相反,它过滤指定字段有值的文档。
{
"query": {
"filtered":{
"filter":{
"missing":{
"field":"id" }
}
}
}
}
只返回缺少id值的文档,与上次exists过滤结果形成互补。
标识符(ids)过滤器
需要过滤出若干指定_id的文档,可使用标识符过滤器(ids)
{
"query": {
"filtered":{
"filter":{
"ids":{
"values":[1,2,6,7] }
}
}
}
}
需注意的是:指定的标识符是文档的_id
,为文档唯一标识。不同于自己指定的id
字段。
限定过滤器(limit)
限定过滤器限定单个分片返回的文档数。
还记得 ElasticSearch笔记-基础知识文章最后提到的分页吗?如果你查询10条数据,则每个分片都会返回10条数据,集合后再选出前10条数据。如果使用limit
限定过滤器,则可限定每个分片返回文档数。
限定每个分片返回一条数据
{
"query": {
"filtered":{
"filter":{
"limit":{
"value":1 }
}
}
}
}
组合过滤器
可以对这些过滤器组合使用,ES中有2类组合过滤器。一类是bool
过滤器,一类是and
、or
、not
过滤器。bool
过滤器对应布尔查询(bool
),关于两者的区别,详细解释在这里:
关于elasticsearch filter bitset的全部
这里简要说一下:
- bool过滤器使用了bitset结构标识该文档是否匹配,当重复执行同一过滤时可简单查询bitset结构从而提高效率。应尽量使用bool过滤。
- 位置过滤(Geo filter)、数值范围过滤(Numeric_range filter)、脚本过滤(Script filter)没有bitset结构,使用and、or、not过滤器更高效。
总结来说,一般情况下用bool过滤器,当遇到位置查询、数值范围、脚本查询时使用and、or、not过滤。
查询日期在16年10月份且文章标题或内容包含“ES“的文档
用SQL表示为
select * from article where date between '2016-10-01' and '2016-10-31' and (name like '%ES%' or contents like '%ES%')
使用bool过滤器
{
"query": {
"filtered":{
"filter":{
"bool":{
"should":[{ "match":{ "name":"ES" } },{ "match":{ "contents":"ES" } }],
"must":{ "range":{ "date":{ "gte":"2016-10-01", "lte":"2016-10-31" } } } }
}
}
}
}
布尔查询也可嵌套布尔查询,如要查询16年10月份内容有关ES的文章或任何时段文章名称与java相关的所有文章。(这里只是举例,不考虑实际情况)
用SQL表示为
select * from article where contents like '%ES%' and date between '2016-10-01' and '2016-10-31' or name like '%java%'
{
"query": {
"filtered": {
"filter": {
"bool": {
"should": [{ "bool": { "must": [{ "range": { "date": { "gte": "2016-09-01", "lte": "2016-09-30" } } }, { "match": { "contents": "js" } }] } }, { "match": { "name": "java" } }] }
}
}
}
}
这里解释一下,我们查询的主要用or关系连接,所以使用bool
查询的should
语句。一边是contents like '%ES%' and date between '2016-10-01' and '2016-10-31'
,另一个为name like '%java%'
前者需嵌套一个bool
查询,使用must
连接,后者简单使用match
即可。
注意这种结构的写法。类似可参考Elasticsearch权威指南-组合过滤