ElasticSearch-4-高级查询Query DSL

 

ElasticSearch-4-高级查询Query DSL

 

1、简介

ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL(Domain Specified Language 领域专用语言) , Query DSL是利用Rest API传递JSON格式的请求体(RequestBody)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。
 

2、语法介绍

1、基本语法:
GET /<index_name>/_search {json请求体数据}

查看指定字段、分页、排序、范围查询

GET /<your-index-name>/_search
{
 "query": {
     // 匹配所有文档
    "match_all": {},
    // 返回前10条数据
    "size": 10,
    // 返回指定字段
    "_source": ["field1","field2"],
    // 只看以obj.开头的字段
    "_source": "obj.*",
    // - from&size分页查询
    "from": 0,
    "size": 5, 
    // 根据指定字段排序
    "sort": [
        {
          "age": "desc"
        }
    ],
    // 范围查询
     "range": {
      "<field_name>": {
        "gte": <lower_bound>, // 表示大于或等于
        "lte": <upper_bound>, // 表示小于或等于
        "gt": <greater_than_bound>, // 表示严格大于
        "lt": <less_than_bound>  // 表示严格小于
      },
      // 根据一组id查询
      "ids": {
      "values": ["id1", "id2", "id3", ...],
      
    }
 }
}

 

2、精确匹配

精确匹配是指的是搜索内容不经过文本分析直接用于文本匹配,这个过程类似于数据库的SQL查询,搜索的对象大多是索引的非text类型字段。此类检索主要应用于结构化数据,如ID、状态和标签等。
term检索主要应用于单字段精准匹配的场景。在实战过程中,需要避免将term检索应用于text类型的检索。进一步说,term检索针对的是非text类型,用于text类型时并不会报错,但检索结果一般会达不到预期。
term查询的基本语法如下:
GET /{index_name}/_search
{
 "query": {
    "term": {
      "{field.keyword}": {
        "value": "your_exact_value"
      }
    }
 }
}
这里的{index_name}是你要查询的索引名称,{field.keyword}是你要匹配的字段名称,.keyword后缀表示该字段是一个keyword类型,用于存储精确匹配的数据。"value"是你要精确匹配的值。term处理多值字段(数组)时,term查询是包含,不是等于。
可以通过 Constant Score 将查询转换成一个 Filtering,避免算分(查询相关度计算),并利用缓存,提高性能。
GET /employee/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "address.keyword": "广州白云山公园"
        }
      }
    }
  }
}

terms多值精准匹配:

GET /<index_name>/_search
{
 "query": {
    "terms": {
      "<field_name>": [
        "value1",
        "value2",
        "value3",
        ...
      ]
    }
 }
}
Elasticsearch支持日期数学表达式,允许在查询和聚合中使用相对时间点。以下是一些常见的日期数学表达式的示例和解释:
  • now:当前时间点。
  • now-1d:从当前时间点向前推1天的时间点。
  • now-1w:从当前时间点向前推1周的时间点。
  • now-1M:从当前时间点向前推1个月的时间点。
  • now-1y:从当前时间点向前推1年的时间点。
  • now+1h:从当前时间点向后推1小时的时间点。
# 返回所有在当前时间点前两年内的产品文档。
GET /product/_search
{
  "query": {
    "range": {
      "date": {
        "gte": "now-2y"
      }
    }
  }
}

 

3、exists——是否存在查询

exists查询用于查找包含特定字段的文档,无论该字段的值是什么(包括null值,但注意null值在Elelasticsearch中不会被索引,所以实际上exists查询是查找那些字段存在且索引了的文档)。

查询某个字段存在的文档

GET /your_index/_search
{
  "query": {
    "exists": {
      "field": "field_name"
    }
  }
}

反向查询:查找某个字段不存在的文档

可以使用must_notexists结合来查找字段不存在的文档。
GET /products/_search
{
  "query": {
    "bool": {
      "must_not": {
        "exists": {
          "field": "description"
        }
      }
    }
  }
}

 

4、prefix——前缀匹配

默认状态下,前缀查询不做相关性分数计算,它只是将所有匹配的文档返回,然后赋予所有相关分数值为1。
原理:需要遍历所有倒排索引,并比较每个词项是否以所搜索的前缀开头。这种查询通常用于自动补全或搜索功能。
  • 如果字段是text类型,那么它会被分词,而prefix查询是针对分词后的术语进行前缀匹配。例如,如果文档的title字段被分词为["apple", "iphone"],那么前缀"app"可以匹配到"apple",但前缀"apple i"可能无法匹配,因为"apple i"不是任何一个术语的前缀(它是两个术语的组合)。

  • 如果字段是keyword类型,那么整个字段作为一个术语,前缀匹配是针对整个字段值的。

基本语法:
GET /<index_name>/_search
{
 "query": {
    "prefix": {
      "your_field_name": {
        "value": "your_prefix_string"
      }
    }
 }
}

 

 5、wildcard——通配符匹配

wildcard检索适用于对部分已知内容的文本字段进行模糊检索。
通配符包括两种。
  • 星号(*):表示零或多个字符,可用于匹配任意长度的字符串。
  • 问号(?):表示一个字符,用于匹配任意单个字符。

 基本语法:

GET /<index_name>/_search
{
 "query": {
    "wildcard": {
      "your_field_name": {
        "value": "your_search_pattern"
      }
    }
 }
}

示例:

GET /employee/_search
{
  "query": {
    "wildcard": {
      "address.keyword": {
        "value": "*州*公园"
      }
    }
  }
}

 

6、regexp——正则匹配查询

虽然该检索方式的功能强大,但建议在非必要情况下避免使用,以保持查询性能的高效和稳定。

 基本语法:

GET /<index_name>/_search
{
 "query": {
    "regexp": {
      "your_field_name": {
        "value": "your_search_pattern"
      }
    }
 }
}

 

7、fuzzy——支持编辑距离的模糊查询

fuzzy检索是一种强大的搜索功能,它能够在用户输入内容存在拼写错误或上下文不一致时,仍然返回与搜索词相似的文档。通过使用编辑距离算法来度量输入词与文档中词条的相似程度,模糊查询在保证搜索结果相关性的同时,有效地提高了搜索容错能力。
编辑距离是指从一个单词转换到另一个单词需要编辑单字符的次数。如中文集团到中威集团编辑距离就是1,只需要修改一个字符;如果fuzziness值在这里设置成2,会把编辑距离为2的东东集团也查出来。

 基本语法如下:

GET /<index_name>/_search
{
  "query": {
    "fuzzy": {
      "your_field": {
        "value": "search_term",
        "fuzziness": "AUTO",
        "prefix_length": 1
      }
    }
  }
}
  • fuzziness参数用于编辑距离的设置,其默认值为AUTO,支持的数值为[0,1,2]。如果值设置越界会报错。
  • prefix_length: 搜索词的前缀长度,在此长度内不会应用模糊匹配。默认是0,即整个词都会被模糊匹配。

 

8、terms_ set——用于解决多值字段中的文档匹配问题

 terms set 查询是 Elasticsearch 中一个特殊的查询,它允许根据匹配的项数来筛选文档。特别的是,这个匹配的项数可以是一个变量,该变量存储在文档的另一个字段中。

基本语法:

GET /your_index/_search
{
  "query": {
    "terms_set": {
      "field_name": {
        "terms": ["term1", "term2", "term3"],
        "minimum_should_match": 2  // 最小匹配数,
        "minimum_should_match_field": "required_matches"  // 从指定的字段获取最小匹配数
      }
    }
  }
}

minimum_should_match_script: 提供一个自定义脚本,用于动态计算匹配数量。如果需要动态设置匹配所需的术语数,这个参数将非常有用。

 示例:

GET /candidates/_search
{
  "query": {
    "terms_set": {
      "skills": {
        "terms": ["Java", "Python", "Elasticsearch"],
        "minimum_should_match_script": {
          "source": """
            // 使用缓存参数,避免重复计算
            if (params.cached_threshold == null) {
              // 复杂的计算逻辑
              params.cached_threshold = Math.min(3, doc['skills'].size());
            }
            return params.cached_threshold;
          """,
          "params": {
            "cached_threshold": null
          }
        }
      }
    }
  }
}

 

3、全文检索

全文检索查询旨在基于相关性搜索和匹配文本数据。这些查询会对输入的文本进行分析,将其拆分为词项(单个单词),并执行诸如分词、词干处理和标准化等操作。此类检索主要应用于非结构化文本数据,如文章和评论等。
精确匹配与全文检索的本质区别主要表现在两个方面:
  • 精确不对待检索文本进行分词处理,而是将整个文本视为一个完整的词条进行匹配。
  • 全文检索则需要对文本进行分词处理。在分词后,每个词条将单独进行检索,并通过布尔逻辑(如与、或、非等)进行组合检索,以找到最相关的结果。

 1、match——分词查询

match查询是一种全文搜索查询,它使用分析器将查询字符串分解成单独的词条,并在倒排索引中搜索这些词条。match查询适用于文本字段,并且可以通过多种参数来调整搜索行为。
对于match查询,其底层逻辑的概述:
1.分词:首先,输入的查询文本会被分词器进行分词。分词器会将文本拆分成一个个词项(terms),如单词、短语或特定字符。分词器通常根据特定的语言规则和配置进行操作。
2.匹配计算:一旦查询被分词,ES将根据查询的类型和参数计算文档与查询的匹配度。对于match查询,ES将比较查询的词项与倒排索引中的词项,并计算文档的相关性得分。相关性得分衡量了文档与查询的匹配程度。
3.结果返回:根据相关性得分,ES将返回最匹配的文档作为搜索结果。搜索结果通常按照相关性得分进行排序,以便最相关的文档排在前面。

基本语法:

GET /<index_name>/_search
{
 "query": {
    "match": {
      "<field_name>": "<query_string>"
    }
 }
}
minnum_should_match参数用来控制匹配的分词的最少数量。
# 最少匹配广州,公园两个词
GET /employee/_search
{
  "query": {
    "match": {
      "address": {
        "query": "广州公园",
        "minimum_should_match": 2
      }
    }
  }
}

 

2、multi_match——多字段查询

multi_match查询在Elasticsearch中用于在多个字段上执行相同的搜索操作。它可以接受一个查询字符串,并在指定的字段集合中搜索这个字符串。multi_match查询提供了灵活的匹配类型和操作符选项,以便根据不同的搜索需求调整搜索行为。
基础语法:
GET /<index_name>/_search
{
 "query": {
    "multi_match": {
      "query": "<query_string>",
      "fields": ["<field1>", "<field2>", ...]
    }
 }
}

 

3、match_phrase短语查询

match_phrase查询在Elasticsearch中用于执行短语搜索,它不仅匹配整个短语,而且还考虑了短语中各个词的顺序和位置。这种查询类型对于搜索精确短语非常有用,尤其是在用户输入的查询与文档中的文本表达方式需要严格匹配时。
基础语法:
GET /<index_name>/_search
{
 "query": {
    "match_phrase": {
      "<field_name>": {
        "query": "<phrase>"
      }
    }
 }
}
match_phrase查询还支持一个可选的slop参数,用于指定短语中词之间可以出现的最大位移数量。默认值为0,意味着短语中的词必须严格按照顺序出现。如果设置了非零的slop值,则允许短语中的某些词在一定范围内错位。

 

4、query_string——支持与或非表达式的查询

query_string查询是一种灵活的查询类型,它允许使用Lucene查询语法来构建复杂的搜索查询。query_string查询可以在单个或多个字段上进行搜索,并且可以处理复杂的查询逻辑。
这种查询类型支持多种逻辑运算符:
  • 与(AND)、或(OR)和非(NOT)(必须大写)。
  • 以及通配符(? 匹配任意单个字符;* 匹配零个或多个字符。)
  • 模糊搜索(使用~进行模糊匹配,后面可以跟一个编辑距离(默认为2))。
  • 正则表达式。使用/包裹正则表达式。示例:title:/elastik.*/

通过使用括号将条件分组,以控制逻辑运算的优先级。如果查询字符串中包含特殊字符(如+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /),需要使用反斜杠\进行转义。

范围查询

数值和日期字段可以使用范围查询:

  • age:[18 TO 30] 包含边界
  • age:{18 TO 30} 不包含边界
  • age:[18 TO *] 大于等于18
  • age:{* TO 30} 小于30

也可以使用比较操作符:

  • age:>=18

  • age:<30

  • age:(>=18 AND <30)

基础语法:

GET /<index_name>/_search
{
 "query": {
    "query_string": {
      "query": "<your_query_string>",
      "default_field": "<field_name>"
    }
 }
}

示例:

GET /employee/_search
{
  "query": {
    "query_string": {
      "fields": ["name","address"],
      "query": "张三 OR (广州 AND 王五)"
    }
  }
}

 

5、simple_query_string

类似Query String,但是会忽略错误的语法,同时只支持部分查询语法,不支持AND OR NOT,会当作字符串处理。支持部分逻辑:
  • + 替代AND
  • | 替代OR
  • - 替代NOT

在生产环境中推荐使用 simple_query_string 而不是 query_string 。主要是因为simple_query_string 提供了更宽松的语法,能够容忍一定程度的输入错误,而不会导致整个
查询失败。如果直接将用户输入用于query_string查询,可能会受到注入攻击,建议使用simple_query_string或者对用户输入进行转义。

基础语法:

GET /<index_name>/_search
{
 "query": {
    "simple_query_string": {
      "query": "<query_string>",
      "fields": ["<field1>", "<field2>", ...],
      "default_operator": "OR" // 或 "AND"
    }
 }
}

 

4、bool query布尔查询

布尔查询可以按照布尔逻辑条件组织多条查询语句,只有符合整个布尔条件的文档才会被搜索出来。
在布尔条件中,可以包含两种不同的上下文。
  1. 搜索上下文(query context):使用搜索上下文时,Elasticsearch需要计算每个文档与搜索条件的相关度得分,这个得分的计算需使用一套复杂的计算公式,有一定的性能开销,带文本分析的全文检索的查询语句很适合放在搜索上下文中。
  2. 过滤上下文(filter context):使用过滤上下文时,Elasticsearch只需要判断搜索条件跟文档数据是否匹配,例如使用Term query判断一个值是否跟搜索内容一致,使用Range query判断某数据是否位于某个区间等。过滤上下文的查询不需要进行相关度得分计算还可以使用缓存加快响应速度,很多术语级查询语句都适合放在过滤上下文中。

image

 示例:使用搜索上下文

GET /books/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "java编程"
          }
        },{
          "match": {
            "description": "性能优化"
          }
        }
      ]
    }
  }
}

示例:使用过滤上下文:

GET /books/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "language": "java"
          }
        },
        {
          "range": {
            "publish_time": {
              "gte": "2010-08-01"
            }
          }
        }
      ]
    }
  }
}

 

 5、highlight高亮

highlight 关键字: 可以让符合条件的文档中的关键词高亮。
highlight相关属性:
  • pre_tags 前缀标签
  • post_tags 后缀标签
  • tags_schema 设置为styled可以使用内置高亮样式
  • require_field_match 多字段高亮需要设置为false

 示例:

GET /products/_search
{
  "query": {
    "term": {
      "name": {
        "value": "牛仔"
      }
    }
  },
  "highlight": {
    "fields": {
      "*":{}
    }
  }
}
自定义高亮html标签,可以在highlight中使用pre_tags和post_tags
GET /products/_search
{
  "query": {
    "multi_match": {
      "fields": ["name","desc"],
      "query": "牛仔"
    }
  },
  "highlight": {
    "post_tags": ["</span>"], 
    "pre_tags": ["<span style='color:red'>"],
    "fields": {
      "*":{}
       // 多字段高亮
       // "name": {}, "desc": {}
    }
  }
}

 

6、地理空间位置查询

在Elasticsearch中,地理空间数据通常存储在geo_point字段类型中。这种字段类型可以存储纬度和经度坐标,用于表示地球上的一个点。
以下是一个使用geo_distance查询的例子,它会找到距离特定点一定距离内的所有文档。
PUT /my_index
{
 "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
 }
}

// 使用以下查询来找到距离给定坐标点(例如lat和lon)小于或等于10公里的所有文档
GET /my_index/_search
{
 "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_distance": {
          "distance": "10km",
          "distance_type": "arc",
          "location": {
            "lat": 39.9,
            "lon": 116.4
          }
        }
      }
    }
 }
}
  • "geo_distance" 是一个地理距离查询,它允许您指定一个距离和一个点的坐标。
  • "distance" 是查询的最大距离,单位可以是米(m)、公里(km)等。
  • "distance_type" 可以是 arc(以地球表面的弧长为单位)或 plane(以直线距离为单位)。通常对于地球上的距离查询,建议使用 arc。
  • "location" 是查询的参考点,包含纬度和经度坐标。

 

 

 

posted @ 2026-01-06 18:57  邓维-java  阅读(5)  评论(0)    收藏  举报