zoukankan      html  css  js  c++  java
  • ElasticSearch总结1-查询表达式

    参考资料:Elasticsearch: 权威指南 

    在线地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

    1. 查询表达式

      查询表达式(Query DSL)是一种非常灵活又富有表现力的 查询语言。 Elasticsearch 使用它可以以简单的 JSON 接口来展现 Lucene 功能的绝大部分。在你的应用中,你应该用它来编写你的查询语句。它可以使你的查询语句更灵活、更精确、易读和易调试。 要使用这种查询表达式,只需将查询语句传递给 query 参数:

    GET /_search
    {
        "query": YOUR_QUERY_HERE
    }

      查询语句的典型结构:

    {
        QUERY_NAME: {
            ARGUMENT: VALUE,
            ARGUMENT: VALUE,...
        }
    }

      如果是针对某个字段,那么它的结构如下:

    {
        QUERY_NAME: {
            FIELD_NAME: {
                ARGUMENT: VALUE,
                ARGUMENT: VALUE,...
            }
        }
    }

      举例,使用 match 关键字查询语句 来查询 tweet 字段中包含 elasticsearch 的 tweet

    GET /_search
    {
        "query": {
            "match": {
                "tweet": "elasticsearch"
            }
        }
    }

    2. 查询与过滤

      Elasticsearch 使用的查询语言(DSL)拥有一套查询组件,这些组件可以以无限组合的方式进行搭配。这套组件可以在以下两种情况下使用:过滤情况(filtering context)和查询情况(query context)。

      当使用于 过滤情况 时,查询被设置成一个“不评分”或者“过滤”查询。即,这个查询只是简单的问一个问题:“这篇文档是否匹配?”。回答也是非常的简单,yes 或者 no ,二者必居其一。

      当使用于 查询情况 时,查询就变成了一个“评分”的查询。和不评分的查询类似,也要去判断这个文档是否匹配,同时它还需要判断这个文档匹配的有 多好(匹配程度如何)。 

      性能差异:

      过滤查询(Filtering queries)只是简单的检查包含或者排除,这就使得计算起来非常快。考虑到至少有一个过滤查询(filtering query)的结果是 “稀少的”(很少匹配的文档),并且经常使用不评分查询(non-scoring queries),结果会被缓存到内存中以便快速读取,所以有各种各样的手段来优化查询结果。

      相反,评分查询(scoring queries)不仅仅要找出匹配的文档,还要计算每个匹配文档的相关性,计算相关性使得它们比不评分查询费力的多。同时,查询结果并不缓存。

      多亏倒排索引(inverted index),一个简单的评分查询在匹配少量文档时可能与一个涵盖百万文档的filter表现的一样好,甚至会更好。但是在一般情况下,一个filter 会比一个评分的query性能更优异,并且每次都表现的很稳定。

    过滤(filtering)的目标是减少那些需要通过评分查询(scoring queries)进行检查的文档。

    3. 查询关键字

    3.1 match_all 查询

      match_all 查询简单的匹配所有文档。在没有指定查询方式时,它是默认的查询:

    { "match_all": {}}

      等同于空查询,如下:

    GET /_search
    {} 

      它经常与 filter 结合使用—​例如,检索收件箱里的所有邮件。所有邮件被认为具有相同的相关性,所以都将获得分值为 1 的中性 _score。

    3.2 match 查询

      无论你在任何字段上进行的是全文搜索还是精确查询,match 查询是你可用的标准查询。 如果你在一个全文字段上使用 match 查询,在执行查询前,它将用正确的分析器去分析查询字符串:

    { "match": { "tweet": "About Search" }}

      如果在一个精确值的字段上使用它,例如数字、日期、布尔或者一个 not_analyzed 字符串字段,那么它将会精确匹配给定的值:

    { "match": { "age":    26           }}
    { "match": { "date":   "2014-09-01" }}
    { "match": { "public": true         }}
    { "match": { "tag":    "full_text"  }}

      对于精确值的查询,你可能需要使用 filter 语句来取代 query,因为 filter 将会被缓存。接下来,我们将看到一些关于 filter 的例子。

    3.3 multi_match 查询

      multi_match 查询可以在多个字段上执行相同的 match 查询:

    {
        "multi_match": {
            "query":    "full text search",
            "fields":   [ "title", "body" ]
        }
    }

    3.4 range 查询

      range 查询找出那些落在指定区间内的数字或者时间:

    {
        "range": {
            "age": {
                "gte":  20,
                "lt":   30
            }
        }
    }

      被允许的操作符如下:

      gt 大于

      gte 大于等于

      lt 小于

      lte 小于等于

    3.5 term 查询

      term 查询被用于精确值匹配,这些精确值可能是数字、时间、布尔或者那些 not_analyzed 的字符串:

    { "term": { "age":    26           }}
    { "term": { "date":   "2014-09-01" }}
    { "term": { "public": true         }}
    { "term": { "tag":    "full_text"  }}

       term 查询对于输入的文本不 分析 ,所以它将给定的值进行精确查询。

    3.6 terms 查询

      terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件:

    { "terms": { "tag": [ "search", "full_text", "nosql" ] }}

      和 term 查询一样,terms 查询对于输入的文本不分析。它查询那些精确匹配的值(包括在大小写、重音、空格等方面的差异)。

    3.7 exists查询和 missing查询 

      exists 查询和 missing 查询被用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档。这与SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 在本质上具有共性:

    {
        "exists":   {
            "field":    "title"
        }
    }

      这些查询经常用于某个字段有值的情况和某个字段缺值的情况。

    4. 合并查询语句

      你可以用 bool 查询来实现你的需求。这种查询将多查询组合在一起,成为用户自己想要的布尔查询。

      它接收以下参数:

      must 文档 必须 匹配这些条件才能被包含进来。

      must_not 文档 必须不 匹配这些条件才能被包含进来。

      should 如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。

      filter 必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。

    4.1 基础组合

      由于这是我们看到的第一个包含多个查询的查询,所以有必要讨论一下相关性得分是如何组合的。每一个子查询都独自地计算文档的相关性得分。一旦他们的得分被计算出来, bool 查询就将这些得分进行合并并且返回一个代表整个布尔操作的得分。

    下面的查询用于查找 title 字段匹配 how to make millions 并且不被标识为 spam 的文档。那些被标识为 starred 或在2014之后的文档,将比另外那些文档拥有更高的排名。如果 两者 都满足,那么它排名将更高:

    {
        "bool": {
            "must":     { "match": { "title": "how to make millions" }},
            "must_not": { "match": { "tag":   "spam" }},
            "should": [
                { "match": { "tag": "starred" }},
                { "range": { "date": { "gte": "2014-01-01" }}}
            ]
        }
    }

      如果没有 must 语句,那么至少需要能够匹配其中的一条 should 语句。但,如果存在至少一条 must 语句,则对 should 语句的匹配没有要求。

    4.2 增加带过滤器(filtering)的查询

      如果我们不想因为文档的时间而影响得分,可以用 filter 语句来重写前面的例子:

    {
        "bool": {
            "must":     { "match": { "title": "how to make millions" }},
            "must_not": { "match": { "tag":   "spam" }},
            "should": [
                { "match": { "tag": "starred" }}
            ],
            "filter": {
              "range": { "date": { "gte": "2014-01-01" }} 
            }
        }
    }

      range 查询已经从 should 语句中移到 filter 语句

      通过将 range 查询移到 filter 语句中,我们将它转成不评分的查询,将不再影响文档的相关性排名。

      由于它现在是一个不评分的查询,可以使用各种对 filter 查询有效的优化手段来提升性能。所有查询都可以借鉴这种方式。将查询移到 bool 查询的 filter 语句中,这样它就自动的转成一个不评分的 filter 了。 

      如果你需要通过多个不同的标准来过滤你的文档,bool 查询本身也可以被用做不评分的查询。简单地将它放置到 filter 语句中并在内部构建布尔逻辑:

    {
        "bool": {
            "must":     { "match": { "title": "how to make millions" }},
            "must_not": { "match": { "tag":   "spam" }},
            "should": [
                { "match": { "tag": "starred" }}
            ],
            "filter": {
              "bool": { 
                  "must": [
                      { "range": { "date": { "gte": "2014-01-01" }}},
                      { "range": { "price": { "lte": 29.99 }}}
                  ],
                  "must_not": [
                      { "term": { "category": "ebooks" }}
                  ]
              }
            }
        }
    }

      将 bool 查询包裹在 filter 语句中,我们可以在过滤标准中增加布尔逻辑

      通过混合布尔查询,我们可以在我们的查询请求中灵活地编写 scoring 和 filtering 查询逻辑。

    4.3 constant_score 查询

      尽管没有 bool 查询使用这么频繁,constant_score 查询也是你工具箱里有用的查询工具。它将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。

      可以使用它来取代只有 filter 语句的 bool 查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助。

    {
        "constant_score":   {
            "filter": {
                "term": { "category": "ebooks" } 
            }
        }
    }

      term 查询被放置在 constant_score 中,转成不评分的 filter。这种方式可以用来取代只有 filter 语句的 bool 查询。

    5. 查询语句分析

    5.1 验证是否合法

      查询可以变得非常的复杂,尤其和不同的分析器与不同的字段映射结合时,理解起来就有点困难了。不过 validate-query API 可以用来验证查询是否合法。

    GET /gb/tweet/_validate/query
    {
       "query": {
          "tweet" : {
             "match" : "really powerful"
          }
       }
    }

      以上 validate 请求的应答告诉我们这个查询是不合法的:

    {
      "valid" :         false,
      "_shards" : {
        "total" :       1,
        "successful" :  1,
        "failed" :      0
      }
    }

    5.2 理解错误信息

      为了找出 查询不合法的原因,可以将 explain 参数 加到查询字符串中:

    GET /gb/tweet/_validate/query?explain 
    {
       "query": {
          "tweet" : {
             "match" : "really powerful"
          }
       }
    }

      explain 参数可以提供更多关于查询不合法的信息。 很明显,我们将查询类型(match)与字段名称 (tweet)搞混了:

    {
      "valid" :     false,
      "_shards" :   { ... },
      "explanations" : [ {
        "index" :   "gb",
        "valid" :   false,
        "error" :   "org.elasticsearch.index.query.QueryParsingException:
                     [gb] No query registered for [tweet]"
      } ]
    }

    5.3 理解查询语法

      对于合法查询,使用 explain 参数将返回可读的描述,这对准确理解 Elasticsearch 是如何解析你的 query 是非常有用的:

    GET /_validate/query?explain
    {
       "query": {
          "match" : {
             "tweet" : "really powerful"
          }
       }
    }

      我们查询的每一个 index 都会返回对应的 explanation ,因为每一个 index 都有自己的映射和分析器:

    {
      "valid" :         true,
      "_shards" :       { ... },
      "explanations" : [ {
        "index" :       "us",
        "valid" :       true,
        "explanation" : "tweet:really tweet:powerful"
      }, {
        "index" :       "gb",
        "valid" :       true,
        "explanation" : "tweet:realli tweet:power"
      } ]
    }

      从 explanation 中可以看出,匹配 really powerful 的 match 查询被重写为两个针对 tweet 字段的 single-term 查询,一个single-term查询对应查询字符串分出来的一个term。

      当然,对于索引 us ,这两个 term 分别是 really 和 powerful ,而对于索引 gb ,term 则分别是 realli 和 power 。之所以出现这个情况,是由于我们将索引 gb 中 tweet 字段的分析器修改为 english 分析器。

    6. 排序

      Elasticsearch默认是相关性排序的,为了按照相关性来排序,需要将相关性表示为一个数值。在 Elasticsearch 中, 相关性得分 由一个浮点数进行表示,并在搜索结果中通过 _score 参数返回, 默认排序是 _score 降序。

      相关性解释:https://www.elastic.co/guide/cn/elasticsearch/guide/current/relevance-intro.html

    6.1 按字段排序

      我们可以使用 sort 参数进行实现。下面的例子中,通过时间来对 tweets 进行排序是有意义的,最新的 tweets 排在最前。 

    GET /_search
    {
        "query" : {
            "bool" : {
                "filter" : { "term" : { "user_id" : 1 }}
            }
        },
        "sort": { "date": { "order": "desc" }}
    }

    7. 分页查询

      分页查询要在查询请求体里使用size和from关键字,size是返回数量,from是跳过多少数据。

    GET /_search
    {
      "from": 30,
      "size": 10
    }
  • 相关阅读:
    搭建kafka高级消费 (high-consumer)php7
    kafka搭建到配置borker集群(项目开发-区块链)
    快速提高谷歌浏览器(Chrome)自带下载器的网速
    利用IO和File类实现拷贝文件目录问题
    随机红包小算法
    二叉树前序中序后序层序遍历问题
    荷兰国旗问题
    二分法查找
    找出数组中最大值and索引
    数组元素反转
  • 原文地址:https://www.cnblogs.com/huanshilang/p/14103066.html
Copyright © 2011-2022 走看看