ElasticSearch权威指南学习(结构化查询)

时间:2022-01-21 14:46:57

请求体查询

  1. 简单查询语句(lite)是一种有效的命令行adhoc查询。但是,如果你想要善用搜索,你必须使用请求体查询(request body search)API。

  2. 空查询

    • 我们以最简单的 search API开始,空查询将会返回索引中所有的文档。

    GET /_search

    {}

    • 同字符串查询一样,你可以查询一个,多个或_all索引(indices)或类型(types):
    GET /index_2014*/type1,type2/_search
    {}
    • 你可以使用from及size参数进行分页:
    GET /_search
    {
    "from": 30,
    "size": 10
    }

结构化查询 Query DSL

  1. 使用结构化查询,你需要传递query参数:

    GET /_search
    {
    "query": YOUR_QUERY_HERE
    }
  2. 空查询 - {} - 在功能上等同于使用match_all查询子句,正如其名字一样,匹配所有的文档:

    GET /_search
    {
    "query": {
    "match_all": {}
    }
    }

查询子句

  1. 你可以使用match查询子句用来找寻在tweet字段中找寻包含elasticsearch的成员:

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

合并多子句

  1. 查询子句就像是搭积木一样,可以合并简单的子句为一个复杂的查询语句
    • 叶子子句(leaf clauses)(比如match子句)用以在将查询字符串与一个字段(或多字段)进行比较
    • 复合子句(compound)用以合并其他的子句。例如,bool子句允许你合并其他的合法子句,must,must_not或者should,如果可能的话:
    {
    "bool": {
    "must": { "match": { "tweet": "elasticsearch" }},
    "must_not": { "match": { "name": "mary" }},
    "should": { "match": { "tweet": "full text" }}
    }
    }
    • 复合子句能合并 任意其他查询子句,包括其他的复合子句。 这就意味着复合子句可以相互嵌套,从而实现非常复杂的逻辑。
    • 以下实例查询的是邮件正文中含有“business opportunity”字样的星标邮件或收件箱中正文中含有“business opportunity”字样的非垃圾邮件:
    {
    "bool": {
    "must": { "match": { "email": "business opportunity" }},
    "should": [
    { "match": { "starred": true }},
    { "bool": {
    "must": { "folder": "inbox" }},
    "must_not": { "spam": true }}
    }}
    ],
    "minimum_should_match": 1
    }
    }

查询与过滤

  1. 查询与过滤语句非常相似,但是它们由于使用目的不同而稍有差异

  2. 一条过滤语句会询问每个文档的字段值是否包含着特定值

    • created 的日期范围是否在 2013 到 2014 ?
    • status 字段中是否包含单词 "published" ?
    • lat_lon 字段中的地理位置与目标点相距是否不超过10km ?
  3. 一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score,并且 按照相关性对匹配到的文档进行排序。 这种评分方式非常适用于一个没有完全配置结果的全文本搜索

性能差异

  1. 使用过滤语句得到的结果集--一个简单的文档列表,快速匹配运算并存入内存是十分方便的,每个文档仅需要1个字节。这些缓存的过滤结果集与后续请求的结合使用是非常高效的
  2. 查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比过滤语句更耗时,并且查询结果也不可缓存。
  3. 幸亏有了倒排索引,一个只匹配少量文档的简单查询语句在百万级文档中的查询效率会与一条经过缓存的过滤语句旗鼓相当,甚至略占上风。但是一般情况下,一条经过缓存的过滤查询要远胜一条查询语句的执行效率。

使用情况

  1. 原则上来说,使用查询语句做全文本搜索或其他需要进行相关性评分的时候,剩下的全部用过滤语句

最重要的查询过滤语句

  1. term 过滤

    • term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型):
    { "term": { "age":    26           }}
    { "term": { "date": "2014-09-01" }}
    { "term": { "public": true }}
    { "term": { "tag": "full_text" }}
  2. terms 过滤

    • terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:
    {
    "terms": {
    "tag": [ "search", "full_text", "nosql" ]
    }
    }
  3. range 过滤

    • range过滤允许我们按照指定范围查找一批数据:
    {
    "range": {
    "age": {
    "gte": 20,
    "lt": 30
    }
    }
    }

    范围操作符包含:

    gt :: 大于

    gte:: 大于等于

    lt :: 小于

    lte:: 小于等于

  4. exists 和 missing 过滤

    • exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件
    {
    "exists": {
    "field": "title"
    }
    }
  5. bool 过滤

    • bool 过滤可以用来合并多个过滤条件查询结果的布尔逻辑,它包含一下操作符:
      • must :: 多个查询条件的完全匹配,相当于 and。
      • must_not :: 多个查询条件的相反匹配,相当于 not。
      • should :: 至少有一个查询条件匹配, 相当于 or。
    • 这些参数可以分别继承一个过滤条件或者一个过滤条件的数组
    {
    "bool": {
    "must": { "term": { "folder": "inbox" }},
    "must_not": { "term": { "tag": "spam" }},
    "should": [
    { "term": { "starred": true }},
    { "term": { "unread": true }}
    ]
    }
    }
  6. match_all 查询

    • 使用match_all 可以查询到所有文档,是没有查询条件下的默认语句。
    {
    "match_all": {}
    }
  7. match 查询

    • match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它
    • 如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析match一下查询字符
    {
    "match": {
    "tweet": "About Search"
    }
    }
  8. multi_match 查询

    • multi_match查询允许你做match查询的基础上同时搜索多个字段:
    {
    "multi_match": {
    "query": "full text search",
    "fields": [ "title", "body" ]
    }
    }
  9. bool 查询

    • bool 查询与 bool 过滤相似,用于合并多个查询子句。不同的是,bool 过滤可以直接给出是否匹配成功, 而bool 查询要计算每一个查询子句的 _score (相关性分值)。
    must:: 查询指定文档一定要被包含。
    must_not:: 查询指定文档一定不要被包含。
    should:: 查询指定文档,有则可以为文档相关性加分。
    • 以下查询将会找到 title 字段中包含 "how to make millions",并且 "tag" 字段没有被标为 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" }}}
    ]
    }
    }

查询与过滤条件的合并

  1. 带过滤的查询语句
    • search API中只能包含 query 语句,所以我们需要用 filtered 来同时包含 "query" 和 "filter" 子句:
    • 在收信箱中匹配邮件
    {
    "filtered": {
    "query": { "match": { "email": "business opportunity" }},
    "filter": { "term": { "folder": "inbox" }}
    }
    }
    • 我们在外层再加入 query 的上下文关系:
    GET /_search
    {
    "query": {
    "filtered": {
    "query": { "match": { "email": "business opportunity" }},
    "filter": { "term": { "folder": "inbox" }}
    }
    }
    }
    • ps: 过滤查询已被弃用,并在ES 5.0中删除。现在应该使用bool / must / filter查询

验证查询

  1. 查询语句可以变得非常复杂,特别是与不同的分析器和字段映射相结合后,就会有些难度
  2. validate API 可以验证一条查询语句是否合法
    GET /ecommerce/product/_validate/query?explain
    {
    "query": {
    "filtered":{
    "query":{
    "match":{
    "name":"jiajieshi yagao"
    }
    },
    "filter":{
    "term":{
    "price":40
    }
    }
    }
    }
    }

    结果

    {
    "valid": false,
    "error": "org.elasticsearch.common.ParsingException: no [query] registered for [filtered]"
    }
    • ps:可以总结下碰到no [xxx] registered for [xxxx] 这种情况,很大可能是版本升级后,该方法被废除了