侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 352 篇文章
  • 累计创建 135 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

ES教程8-Filter查询语法及示例

孔子说JAVA
2022-10-13 / 0 评论 / 0 点赞 / 90 阅读 / 5,272 字 / 正在检测是否收录...
广告 广告

ES中的查询操作分为2种: 查询(query)和过滤(filter)。查询(query)默认会计算每个返回文档的得分,然后根据得分排序。而过滤(filter)只会筛选出符合的文档(即在查询过程中,只判断该文档是否满足条件,不会进行相似查询,只有 yes 或者 no),并不计算 得分,且它可以缓存文档。所以,单从性能考虑,过滤比查询更快。

1、过滤查询_Filter Query

Elasticsearch中的所有的查询都会触发相关度得分的计算。对于那些不需要相关度得分的场景下,Elasticsearch以过滤器的形式提供了另一种查询功能,过滤器在概念上类似于查询,但是它们有非常快的执行速度,执行速度快主要有以下两个原因:

  • 过滤器不会计算相关度的得分,所以它们在计算上更快一些。
  • 过滤器可以被缓存到内存中,这使得在重复的搜索查询上,其要比相应的查询快出许多。

过滤器适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据。

常见过滤类型如下:

  • term
  • terms
  • range
  • exists
  • ids

2、过滤filter示例

为了理解过滤器,可以将一个查询(像是match_all,match,bool等)和一个过滤器结合起来。

  • 在执行filter和query时,先执行filter在执行query。
  • Elasticsearch会自动缓存经常使用的过滤器,以加快性能。

2.1 过滤查询

只查询price字段为13.2的数据

{
  "query": {
    "bool": {
      "filter": {
        "term": {
            "price": 13.2
        }
      }
    }
  }
}

查询全部职员时过滤年龄大于10的人员信息。

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_all": {}}
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 10
          }
        }
      }
    }
  }
}

image-1665452046569

2.2 term过滤

关键词过滤后再查找关键词。

GET /ems/emp/_search  
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "小黑"
          }
        }}
      ],
      "filter": {
        "term": {
          "content":"框架"
        }
      }
    }
  }
}

先在content中查找“框架”的数据,再执行query中name为“小黑”的数据

image-1665452089613

2.3 terms过滤

GET /ems/emp/_search    
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "小黑"
          }
        }}
      ],
      "filter": {
        "terms": {
          "content":[
              "框架",
              "spring"
            ]
        }
      }
    }
  }
}

image-1665452133538

2.4 ranage 过滤

范围过滤器,ranage语法:

  • gt : 大于
  • lt : 小于
  • gte : 大于等于
  • lte :小于等于
GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "小黑"
          }
        }}
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 7,
            "lte": 25
          }
        }
      }
    }
  }
}

先在age中查找age大于等于7,小于等于25的数据,再执行query中查找“小黑”的数据

image-1665452167457

2.5 exists过滤

exists是用来匹配文档的mapping中是否包含某一个字段,如果是就返回。它过滤存在指定字段,获取字段不为空的数据。

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "小黑"
          }
        }}
      ],
      "filter": {
        "exists": {
          "field":"age"
        }
      }
    }
  }
}

先查询 age 属性不为null的数据。

image-1665452206446

2.6 ids过滤

过滤含有指定字段的索引记录,类似于mysql的where id in ()的语义,他支持value属性,可以传入一个数组

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "小黑"
          }
        }}
      ],
      "filter": {
        "ids": {
          "values": ["dQZIFHcB7sSdNbu_KMhO","dAZIFHcB7sSdNbu_KMhO"]
        }
      }
    }
  }
}

返回属性_id为dQZIFHcB7sSdNbu_KMhO、dAZIFHcB7sSdNbu_KMhO的文档,如果存在的话

image-1665452239319

2.7 bool filter

布尔过滤

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": {
            "match": {
              "title": "java学习教程"
            }
          }
        }
      }
    }
  }
}

2.8 and , or , not查询

如果不使用bool,可以用and , or , not查询

GET /blank/_search
{
  "query": {
      "filter": {
        "and":[
          {
            "term":{
              "price" : 10
            }
          },
          {
            "term":{
              "articleid":"100000"
            }
          }
        ]
      }
    }
  }
}

3、过滤聚合查询

3.1 filter聚合

filter对满足过滤查询的文档进行聚合计算,在查询命中的文档中选取过滤条件的文档进行聚合,先过滤在聚合。

{
    "size": 0, 
    "aggs": {
      "agg_filter":{
        "filter": {
          "match":{"gender":"F"}
        },
        "aggs": {
          "avgs": {
            "avg": {
              "field": "age"
            }
          }
        }
      }
    }
}

3.2 filtters聚合

多个过滤组聚合计算。

{
    "size": 0, 
    "aggs": {
      "message": {
        "filters": {
          
          "filters": {
            "errors": {
              "exists": {
                "field": "__type"
              }
            },
            "warring":{
              "term": {
                "__type": "info"
              }
            }
          }
        }
      }
    }
}

4、filter高效的原理

image-1665463267429

简单来说,若是你的业务场景不须要算分,使用filter真的能够让你的查询效率飞起来。为了说明filter查询高效的缘由,引入ES的一个概念 query contextfilter context

  • query context 关注的是,文档到底有多匹配查询的条件,这个匹配的程度是由相关性分数决定的,分数越高天然就越匹配。因此这种查询除了关注文档是否知足查询条件,还须要额外的计算相关性分数.

  • filter context 关注的是,文档是否匹配查询条件,结果只有两个,是和否。没有其它额外的计算。它经常使用的一个场景就是过滤时间范围。而且filter context会自动被ES缓存结果,效率进一步提升。

对于bool查询,must使用的就是query context,而filter使用的就是filter context。

比较filter过滤和must过滤

1)使用filter过滤时间范围

GET kibana_sample_data_ecommerce/_search
{
  "size": 1000, 
  "query": {
    "bool": {
      "must": [
        {"term": {
          "currency": "EUR"
        }}
      ],
      "filter": {
        "range": {
          "order_date": {
            "gte": "2020-01-25T23:45:36.000+00:00",
            "lte": "2020-02-01T23:45:36.000+00:00"
          }
        }
      }
    }
  }
}

2)使用must过滤时间范围

GET kibana_sample_data_ecommerce/_search
{
  "size": 1000, 
  "query": {
    "bool": {
      "must": [
        {"term": {
          "currency": "EUR"
        }},
        {"range": {
          "order_date": {
            "gte": "2020-01-25T23:45:36.000+00:00",
            "lte": "2020-02-01T23:45:36.000+00:00"
          }
        }}
      ]
    }
  }
}

查询的结果都是(但是性能上有差异):

{
  "took" : 25,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1087,
      "relation" : "eq"
    },
    
    ...

经过kibana自带的search profiler来看看ES的查询的详细过程。使用must查询的执行过程是这样的:

image-1665453959439

image-1665453966649

能够明显看到,这次查询计算了相关性分数,并且score的部分占据了查询时间的10分之一左右。filter的查询我就不截图了,区别就是score这部分是0,也就是不计算相关性分数。

除了是否计算相关性算分的差异,常常使用的过滤器将被Elasticsearch自动缓存,以提升性能。

我本身曾经在一个项目中,对一个业务查询场景作了这种优化,当时线上的索引文档数量大概是3000万左右,改为filter以后,查询的速度几乎快了一倍。

我截了几张图,你来感觉下。

image-1665454015072

image-1665454022623

我们应该根据本身的实际业务场景选择合适的查询语句,在某些不须要相关性算分的查询场景,尽可能使用filter context可让你的查询更加高效。

0

评论区