zoukankan      html  css  js  c++  java
  • ElasticSearch的Query和Filter区别

    ElasticSearch的Query和Filter区别

    这个其实在官网也有一定的介绍:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/full-text-queries.html

    相关性分数

    默认情况下,Elasticsearch 按相关性分数对匹配的搜索结果进行排序,相关性分数衡量每个文档与查询的匹配程度。 相关性分数是一个正浮点数,在搜索 API 的 _score 元字段中返回。 _score 越高,文档越相关。虽然每种查询类型可以不同地计算相关性分数,但分数计算还取决于查询子句是在query 还是 filter中运行。

    查询

    在查询上下文中,查询子句回答“此文档与此查询子句匹配程度如何?”的问题。除了决定文档是否匹配外,查询子句还会在 _score 元字段中计算相关性分数。 只要将查询子句传递给查询参数,例如搜索 API 中的查询参数,查询上下文就会生效。

    过滤

    在过滤器上下文中,查询子句回答“此文档是否与此查询子句匹配?”的问题。答案是简单的 Yes 或 No —— 不计算分数。过滤上下文主要用于过滤结构化数据,例如 这个时间戳是否在 2015 年到 2016 年的范围内? 状态字段是否设置为“已发布”? Elasticsearch 会自动缓存常用的过滤器,以提高性能。 只要将查询子句传递给过滤器参数,例如 bool 查询中的 filter 或 must_not 参数、constant_score 查询中的过滤器参数或过滤器聚合,过滤器上下文就会生效。

    GET /_search
    {
      "query": { 
        "bool": { 
          "must": [
            { "match": { "title":   "Search"        }},
            { "match": { "content": "Elasticsearch" }}
          ],
          "filter": [ 
            { "term":  { "status": "published" }},
            { "range": { "publish_date": { "gte": "2015-01-01" }}}
          ]
        }
      }
    }
    

    filter与query对比大解密

    filter,仅仅只是按照搜索条件过滤出需要的数据而已,不计算任何相关度分数,对相关度没有任何影响
    query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序

    一般来说,如果你是在进行搜索,需要将最匹配搜索条件的数据先返回,那么用query;如果你只是要根据一些条件筛选出一部分数据,不关注其排序,那么用filter除非是你的这些搜索条件,你希望越符合这些搜索条件的document越排在前面返回,那么这些搜索条件要放在query中;如果你不希望一些搜索条件来影响你的document排序,那么就放在filter中即可

    filter与query性能

    • filter,不需要计算相关度分数,不需要按照相关度分数进行排序,同时还有内置的自动cache最常使用filter的数据
    • query,相反,要计算相关度分数,按照分数进行排序,而且无法cache结果

    filter缓存的秘密

    (1)在倒排索引中查找搜索串,获取document list

    举例

    word doc1 doc2 doc3
    2017-01-01 *
    2017-02-02 * *
    2017-03-03 * * *

    如果对2017-02-02进行过滤的话,可以在倒排索引中搜到doc2,doc3

    (2)为每个在倒排索引中搜索到的结果,构建一个bitset

    使用找到的doc list,构建一个bitset,就是一个二进制的数组,数组每个元素都是0或1,用来标识一个doc对一个filter条件是否匹配,如果匹配就是1,不匹配就是0,以上面的例子来说,这个bitset即为[0, 1, 1]。doc1:不匹配这个filter的,doc2和do3:是匹配这个filter的,通过这个简单的数据结构去实现复杂的功能,可以节省内存空间,提升性能

    (3)遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找满足所有条件的document

    一次性其实可以在一个search请求中,发出多个filter条件,每个filter条件都会对应一个bitset遍历每个filter条件对应的bitset,先从最稀疏的开始遍历,如下

    [0, 0, 0, 1, 0, 0]:比较稀疏 ,[0, 1, 0, 1, 0, 1]比较密集。先遍历比较稀疏的bitset,就可以先过滤掉尽可能多的数据,遍历所有的bitset,找到匹配所有filter条件的doc。

    请求:filter,postDate=2017-01-01,userID=1

    postDate: [0, 0, 1, 1, 0, 0]
    userID: [0, 1, 0, 1, 0, 1]

    遍历完两个bitset之后,找到的匹配所有条件的doc,只剩下doc4了,就可以将document作为结果返回给client了

    (4)caching bitset,跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset。

    • 跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset。使用缓存,可以不用重新扫描倒排索引,不用反复生成bitset,可以大幅度提升性能。为什么小的segment不进行缓存:segment数据量很小,此时哪怕是扫描也很快;segment会在后台自动合并,小segment很快就会跟其他小segment合并成大segment,此时就缓存也没有什么意义,segment很快就消失了。

    • filter大部分情况下来说,在query之前执行,先尽量过滤掉尽可能多的数据

      • query:是会计算doc对搜索条件的relevance score,还会根据这个score去排序
      • filter:只是简单过滤出想要的数据,不计算relevance score,也不排序
    • 以后只要是有相同的filter条件的,会直接来使用这个过滤条件对应的cached bitset

    • filter比query的好处就在于会caching,实际上并不是一个filter返回的完整的doc list数据结果。而是filter bitset缓存起来。下次不用扫描倒排索引了。

    (5)filter大部分情况下来说,在query之前执行,先尽量过滤掉尽可能多的数据

    • query:是会计算doc对搜索条件的relevance score,还会根据这个score去排序
    • filter:只是简单过滤出想要的数据,不计算relevance score,也不排序

    (6)如果document有新增或修改,那么cached bitset会被自动更新

    (7)以后只要是有相同的filter条件的,会直接来使用这个过滤条件对应的cached bitset

  • 相关阅读:
    iOS----------弹窗动画
    书单
    如何屏蔽垃圾短信
    2018年IOS/Android UI设计规范
    关于Keychain
    OpenUDID 和 IDFA 比较
    iOS-----------关于UDID
    iOS-----------设置自定义字体
    【2020Python修炼记】前端开发之 JavaScript 基础
    【2020Python修炼记】前端开发之 CSS基础布局
  • 原文地址:https://www.cnblogs.com/dalianpai/p/14987120.html
Copyright © 2011-2022 走看看