文章目录
ElasticSearch Query DSL(一)
ElasticSearch提供了一个基于JSON的完整的Query DSL(Domain Special Language领域特定语言)。将查询 DSL 视为查询的 AST(抽象语法树),由两种类型的子句组成:
- 简单的查询子句:简单查询子句在特定的字段上寻找特定的值。例如
match、term、range
。这些查询可以单独使用 - 复合查询的子句:复合查询包含简单查询和复合查询并且以逻辑的方式组合多个查询(例如
bool
或者dis_max
查询),或者改变他们的行为(例如constant_score
查询)
查询子句的行为取决于它们是在查询上下文中还是在过滤器上下文中使用。
查询和过滤器上下文
相关性分数
默认情况下,ElasticSearch通过相关性分数对匹配的结果进行排序,相关性分数衡量了每个文档与查询的匹配程度。
相关性分数是一个正浮点数,在search API
中以_score
字段返回。_score
分数越高,说明文档的相关性越高。虽然每种查询类型可以计算出不同的相关性分数,但是分数计算也取决于查询子句是在查询上下文中还是在过滤器上下文中。
查询上下文
在查询上下文中,一个查询回答了此文档与此查询子句的匹配程度如何?
的问题。除了决定文档是否匹配之外,查询上下文还会计算_score
相关性分数。
查询上下文将查询子句传递给query
参数时开始生效,例如search API
中的query
参数。
过滤器上下文
在过滤器上下文中,回答的是这个文档匹配这个查询子句么?
的问题,这个回答只是简单的yes or no
。_score
相关性分数不会被计算。过滤器上下文大多数情况下用来过滤结构化数据,例如:
- 这个
timestamp
是否在2015
和2016
之间 status
字段是否是pushlished
ElasticSearch会自动缓冲常用的过滤器,来提高查询性能。
查询和过滤器上下文使用示例
以下是在search API
中使用查询和过滤器上下文中使用查询子句的例子。这个查询将根据以下条件来匹配文档
title
字段包含search
单词content
字段包含elasticsearch
单词status
字段包含精确的pushlished
publish_date
字段包含从 2015 年 1 月 1 日起的日期。
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
'
复合查询
Boolean查询
与其他boolean查询相结合的匹配查询。bool
查询对应Lucence
的BooleanQuery
。它使用一个或者多个boolean子句构建,每个子句都有一个类型化事件,事件类型是:
must | 该子句必须出现在匹配的文档中。这将有助于计算得分。利用逻辑语句替换其实就是and 关系 |
---|---|
filter | 该子句必须出现在匹配的文档中。然后不像是must 那样,分数计算将被忽略。过滤器查询在过滤器上下文中执行,这意味着忽略评分并考虑将子句用于缓存。 |
should | 这个子句应该出现在匹配的文档中。利用逻辑语句替换其实就是or 的关系。 |
must_not | 该子句一定不能出现在匹配的文档中。子句在过滤器上下文中执行,这意味着忽略评分并考虑将子句用于缓存。由于评分被忽略,所有文档的评分为 0。 |
bool查询采用越多越好
的方法,因此每个匹配到的must
或should
子句得分将被加在一起,作为每个文档的最终_score
。
curl -X POST "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool" : {
"must" : {
"term" : { "user.id" : "kimchy" }
},
"filter": {
"term" : { "tags" : "production" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tags" : "env1" } },
{ "term" : { "tags" : "deployed" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}
'
使用minimum_should_match
你可以使用minimum_should_match
参数来指定mush
子句匹配到的文档中should
子句的数量或者百分比。
如果bool
查询包含最少一个should
子句并且没有must
或者filter
子句,那么默认值为1
,否则为0
。
使用bool.filter
计算分数
在filter
元素下的查询对评分没有影响,_score
会返回0
。例如,以下所有三个查询都返回状态字段包含术语 active 的所有文档。
第一个查询为所有文档分配 0 分,因为没有指定评分查询:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"filter": {
"term": {
"status": "active"
}
}
}
}
}
'
这个 bool
查询有一个 match_all
查询,它为所有文档分配 1.0
的分数。
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"term": {
"status": "active"
}
}
}
}
}
'
这个 constant_score
查询的行为方式与上面的第二个示例完全相同。 constant_score
查询将 1.0
的分数分配给过滤器匹配的所有文档。
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"constant_score": {
"filter": {
"term": {
"status": "active"
}
}
}
}
}
'
提升查询
返回positive
查询匹配到的文档,同时降低negative
查询匹配的文档的相关性分数。
你可以使用boosting
查询来降级某些文档而不将他们从搜索结果中排除。
请求例子
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"boosting": {
"positive": {
"term": {
"text": "apple"
}
},
"negative": {
"term": {
"text": "pie tart fruit crumble tree"
}
},
"negative_boost": 0.5
}
}
}
'
boosting
的顶级参数
positive
:(必须,查询对象),希望运行的查询。任何返回的文档都必须以此查询相匹配。negative
:(必须,查询对象),降低匹配到文档的相关性分数的查询。如果返回的文档与boosting
查询和此查询匹配,则提升查询将计算文档的最终相关性分数,如下所示:- 从
positive
查询中获取原始相关性分数。 - 将分数乘以
negative_boost
值。
- 从
negative_boost
:(必须,float),0 到 1.0 之间的浮点数用于降低与negative
查询匹配的文档的相关性分数。
常量得分查询
包装一个过滤器查询并且返回与boost
参数值相等的匹配文档。
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"constant_score": {
"filter": {
"term": { "user.id": "kimchy" }
},
"boost": 1.2
}
}
}
'
全文查询
全文查询允许你搜索已经被分析的文本字段,例如邮件的正文。
间隔查询
intervals
查询使用匹配规则。然后将这些规则应用于来自指定字段的术语。
这些定义产生跨越文本主体中的术语的最小间隔序列。这些间隔可以通过父源进一步组合和过滤。
例如,我们用my favourite food
这样一个字符串在my_text field里进行intervals查询,查询规则是该字符串出现在"hot water"或者cold porridge
字符串的前面,那么query语句可以这样来写:
curl -X POST "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "my favorite food",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "hot water" } },
{ "match" : { "query" : "cold porridge" } }
]
}
}
]
}
}
}
}
}
'
简要概述上面语句,像包含my favourite food is cold porridge
这样字符串的文档就会被检索到,因为my favourite food
出现在cold porridge
前面,满足intervals query语法规则;另一个只包含了when it's cold my favourite food is porridge
字符串的文档就不会被匹配到,因为cold
和porridge
出现在了my favourite food
两边,不符合我们配置的intervals query语法规则。
match参数
参数 | 描述 |
---|---|
query | 用户查询的字符串 |
max_gaps | 字符串中每个词在text field中出现的最大词间距,超过最大间距的将不会被检索到;默认值是-1,即不限制,设置为0的话,query中的字符串必须彼此相连不能拆分 |
ordered | query中的字符串是否需要有序显示,默认值是false,即不考虑先后顺序 |
analyzer | 对query参数中的字符串使用什么分词器,默认使用mapping时该field配置的 search analyzer |
filter | 可以为query搭配一个intervals filter,该filter不同于Boolean filter 有自己的语法结构 |
all_of参数
参数 | 描述 |
---|---|
intervals | 一个interval集合,集合里面的所有match需要同时在一个文档数据上同时满足才行 |
max_gaps | 多个interval查询在一个文档中允许的最大间距,超过最大间距的将不会被检索到;默认值是-1,即不限制,设置为0的话,所有的interval query必须彼此相连不能拆分 |
ordered | 配置 intervals 出现的先后顺序,默认值false |
filter | 可以为query搭配一个intervals filter,该filter不同于Boolean filter 有自己的语法结构 |
any_of参数
参数 | 描述 |
---|---|
intervals | 一个interval集合,集合里面的所有match不需要同时在一个文档数据上同时满足 |
filter | 可以为query搭配一个intervals filter |
filter参数
match query filter,不是严格的查询过滤器,不同于Boolean filter ,有自己的语法结构.我们先看一个例子,假设我们要在my_text field上查询包含hot
和porridge
的文档,要求这两个词的词距不超过10个字符,且文档中不包含salty
,以下是查询语句:
curl -X POST "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"intervals" : {
"my_text" : {
"match" : {
"query" : "hot porridge",
"max_gaps" : 10,
"filter" : {
"not_containing" : {
"match" : {
"query" : "salty"
}
}
}
}
}
}
}
}
'
参数 | 描述 |
---|---|
containing | interval query中terms之间需要包含filter中的terms |
contained_by | interval query中的字符串需要被包含在filter query的terms里 |
not_containing | containing 对立面 |
not_contained_by | contained_by 对立面包 |
not_overlapping | query 与filter 词距不重叠 |
匹配查询
返回与提供的文本、数值、日期或者布尔值相匹配的文档。这个提供的文本在匹配前会被分析。
例子如下:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"message": {
"query": "this is a test"
}
}
}
}
'
match的顶级参数
<field>
:(必须,对象),你希望搜索的字段名
field参数
-
query
:(必须),你希望在提供的<field>
字段中查找文本,数值,日期或者布尔数据。match
在执行查询之前会分析提供的任何文本数据。这意味着匹配查询可以在文本字段中搜索分析的分词而不是精确的术语。 -
analyzer
:(可选的,字符串),analyzer
从来将查询值中的文本数据转换为分词。默认为<field>
映射的索引时间分析器。如果没有映射分析器,则使用索引的默认分析器。 -
auto_generate_synonyms_phrase_query
:(可选的,boolean),如果为true
,match phrase
自动为多个术语创建同义词。默认为true
。 -
fuzziness
:(可选的,string),允许匹配的最大编辑距离 -
max_expansions
:(可选的,integer),查询将扩展到的最大术语数。默认值为50。 -
prefix_length
:(可选的,integer),模糊匹配的起始字符数。默认值为0。 -
fuzzy_transpositions
:(可选的,boolean),如果为真,则模糊匹配的编辑包括两个相邻字符的换位(ab→ba)。默认值为true -
operator
:(可选的。字符串)布尔逻辑,用于解释查询值中的文本。有效值:OR
(Default):capital of Hungary
>>>>>>capital OR of OR Hungary
.AND
:capital of Hungary
>>>>>capital AND of AND Hungary
.
短请求例子
您可以通过组合 <field>
和查询参数来简化匹配查询语法。例如:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"message": "this is a test"
}
}
}
'
匹配布尔前缀查询
match_bool_prefix
查询分析其输入,并从术语构造一个bool
查询。除了最后一个术语外,其他每个术语都将在术语查询中使用。最后一个词用于前缀查询。match_bool_prefix
查询,例如
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_bool_prefix" : {
"message" : "quick brown f"
}
}
}
'
其中分析产生的术语 quick
、brown
和 f
类似于以下 bool
查询
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool" : {
"should": [
{ "term": { "message": "quick" }},
{ "term": { "message": "brown" }},
{ "prefix": { "message": "f"}}
]
}
}
}
'
match_bool_prefix
查询和match_phrase_prefix
查询的一个重要区别是,match_phrase_prefix
查询以短语的形式匹配它的词汇,但是match_bool_prefix
查询可以在任何位置匹配它的词汇。上面的示例match_bool_prefix
查询可以匹配包含quick brown fox
的字段,但是也可以匹配brown fox quick
。它还可以匹配包含术语quick
、术语brown
和以f
开头的术语的字段,这些术语出现在任何位置。
参数
默认情况下,match_bool_prefix
查询的输入文本将使用来自查询字段映射的分析器进行分析。可以使用分析器参数配置不同的搜索分析器
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_bool_prefix": {
"message": {
"query": "quick brown f",
"analyzer": "keyword"
}
}
}
}
'
匹配短语查询
match_phrase
查询分析文本,并从分析文本中创建一个短语查询。例如:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_phrase": {
"message": "this is a test"
}
}
}
'
可以将分析器设置为控制哪个分析器将对文本执行分析过程。它默认为字段显式映射定义,或默认搜索分析器,例如:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_phrase": {
"message": {
"query": "this is a test",
"analyzer": "my_analyzer"
}
}
}
}
'
组合字段
该combined_fields
查询支持搜索多个文本字段,就好像它们的内容已被索引到一个组合字段中一样。它采用以术语为中心的查询视图:首先将查询字符串分析为单独的术语,然后在任何字段中查找每个术语。当匹配可以跨越多个文本字段时,此查询特别有用,例如文章的title
、 abstract
和body
:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"combined_fields" : {
"query": "database systems",
"fields": [ "title", "abstract", "body"],
"operator": "and"
}
}
}
'
提示:一次可以查询的字段数是有限制的。 默认为 1024。它由indices.query.bool.max_clause_count
设置。
字段提升
可以使用脱字符 (^) 符号提升单个字段:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"combined_fields" : {
"query" : "distributed consensus",
"fields" : [ "title^2", "body" ]
}
}
}
'
combined_fields
查询提供了一种跨多个文本字段进行匹配和评分的原则方法。为了支持这一点,它要求所有字段具有相同的搜索分析器。
如果您希望使用单个查询来处理不同类型的字段,如关键字或数字,那么multi_match
查询可能更适合。它同时支持文本和非文本字段,并接受不共享同一分析器的文本字段。
主要的multi_match
匹配模式best_fields
和most_fields
采用以字段为中心的查询视图。相反,combined_fields
是以术语为中心的:operator
和minimum_should_match
是按术语而不是按字段应用的。具体地说,类似于:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"combined_fields" : {
"query": "database systems",
"fields": [ "title", "abstract"],
"operator": "and"
}
}
}
'