Elasticsearch系列(12)Query之复合查询

2020-09-14  本文已影响0人  正义的杰克船长

1. 前言

Elasticsearch提供了一个完整的基于JSON的查询DSL(领域特定语言)来定义查询。可以将查询DSL看作查询的AST(抽象语法树),它由两种类型的子句(clauses)组成:
(1)叶查询子句(Leaf query clauses):特定字段中查找特定值,例如匹配(match)、词条(term)或范围(range)查询。这些查询可以单独查询使用。
(2)复合查询子句(Compound query clauses):包装其他叶查询或复合查询,并使用逻辑方式来组合多个查询(如bool或dis_max查询),或用于改变它们的行为(如constant_score查询)。

查询子句的行为取决于它们是在查询上下文中使用还是在筛选上下文中使用。

允许昂贵查询

某些类型的查询通常执行缓慢,这是因为它们的实现方式会影响集群的稳定性,这些查询分类如下:

可以通过设置参数allow_expensive_queries为false(默认为true)来阻止此类查询的执行。

2. 查询和过滤器上下文

相关性得分

默认情况下,Elasticsearch根据相关性评分对匹配的搜索结果进行排序,相关性评分衡量每个文档与查询的匹配程度。相关性得分是一个正浮点数,在搜索API的_score元数据字段中返回。_score字段值越高,文档越相关。

查询上下文

在查询(query)上下文中,一个查询子句回答了问题“这个文档与这个查询子句匹配得有多好?”,除了决定文档是否匹配之外,查询子句还会计算相关性分数保存在_score元数据字段中。

过滤器上下文

在过滤器(filter)上下文中,查询子句回答问题“这个文档与这个查询子句匹配吗?”,答案是简单的“是”或“不是”—没有计算分数。过滤器上下文主要用于过滤结构化数据。

查询和过滤器例子
PUT /my_index_01
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "store": true
      },
      "create_date": { "type": "date" },
      "id": {  "type": "keyword" },
      "user": {
        "properties": {
          "name": { "type": "keyword" },
          "age": { "type": "integer" }
        }
      },
      "status": {  "type": "keyword" }
    }
  }
}
POST /my_index_01/_doc/1
{"id":"00000001", "content":"Quick Brown Fox", "create_date": "2015-01-01", "user.name":"james", "user.age": 35, "status": "enable" }
POST /my_index_01/_doc/2
{"id":"00000002", "content":"Quick White Fox", "create_date": "2015-01-02", "user.name":"fake", "user.age": 26, "status": "disable" }
GET my_index_01/_search
{
    "query": {  //1
      "bool": {   //2
        "must":[
          {"match":{"content":"Fox"}},
          {"match":{"user.name":"james"}}
        ],
        "filter":[  //3
          {"term":{"status":"enable"}},
          {"range":{"create_date": {"gte":"2014-01-01"}}}
        ]
      }
  }
}

注释1:query参数表示查询上下文
注释2:在查询上下文中使用bool和两个match子句,这意味着它们会对每个文档的匹配程度进行评分。
注释3:filter参数表示过滤器上下文,在过滤器上下文中使用term和range子句,它们将过滤掉不匹配的文档,但不会影响匹配文档的得分。

注意:在查询上下文中为查询计算的分数表示为单精度浮点数;它们只有24位的精度。超过精度将被转换为浮点数进行分数计算,从而丢失精度。

3. 复合查询

首先创建索引my_index_01,并索引数据:

PUT /my_index_01
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "store": true
      },
      "create_date": { "type": "date" },
      "id": {  "type": "keyword" },
      "user": {
        "properties": {
          "name": { "type": "keyword" },
          "age": { "type": "integer" }
        }
      },
      "status": {  "type": "keyword" }
    }
  }
}
POST /my_index_01/_doc/1
{"id":"00000001", "content":"Quick Brown Fox", "create_date": "2015-01-01", "user.name":"james jordan", "user.age": 35, "status": "enable" }
POST /my_index_01/_doc/2
{"id":"00000002", "content":"Quick White Fox", "create_date": "2015-01-02", "user.name":"fake li", "user.age": 26, "status": "disable" }

3.1 bool查询

用于组合多个叶子或复合查询子句的布尔值查询,使用一个或多个布尔子句构建的,每个子句都有一个有类型的,如must、should、must_not或filter子句。

查询参数

查询示例如下:

POST my_index_01/_search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user.name" : "james jordan" }
      },
      "filter": {
        "term" : { "status" : "enable" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 30 }
        }
      },
      "should" : [
        { "term" : { "id" : "00000001" } },
        { "term" : { "id" : "00000002" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

使用minimum_should_match参数来指定返回的文档必须匹配的should子句的数量或百分比。如果布尔查询包含should子句,并且没有must或filter子句,则默认值为1,否则默认值为0。

命名查询

每个查询可在其顶级定义一个_name。可以使用命名查询来跟踪匹配返回的文档。如果使用了命名查询,则响应对于每次命中都包含一个matched_queries属性。示例如下:

POST my_index_01/_search
{
  "query": {
    "bool": {
      "should": {
        "match": {
          "user.name": { "query": "james jordan", "_name": "custom_value" }
        }
      }
    }
  }
}

返回结果如下

3.2 boosting查询

boosting查询包含两部分:positive查询和negative查询。

查询参数

示例如下:

POST my_index_01/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "content": "Fox"
        }
      },
      "negative": {
        "match": {
          "content": "White"
        }
      },
      "negative_boost": 10
    }
  }
}

返回结果片段如下:

3.3 constant_score查询

包装一个过滤器(filter)查询,并返回每个文档的相关性分数为常量boost参数值。

查询参数

示例如下:

POST my_index_01/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "match": {  "content": "Fox" }
      },
      "boost": 1.2
    }
  }
}

3.4 dis_max查询

dis_max查询包含一个或多个查询子句,如果返回的文档匹配了多个查询子句,dis_max查询将找到匹配子句中最高相关性分数, 将其分配给文档,而且为任何其他匹配子查询加上一个离线增量。

查询参数

示例如下:

POST my_index_01/_search
{
  "query": {
     "dis_max": {
        "queries": [
          { "term" : { "user.name" : "fake li" } },
          { "term" : { "id" : "00000002" } }
        ],
        "tie_breaker": 0.5
      }
  }
}

返回结果片段如下:

"max_score" : 0.76246184,
"hits" : [
  {
    "_index" : "my_index_01",
    "_type" : "_doc",
    "_id" : "2",
    "_score" : 0.76246184,
    "_source" : {
      "id" : "00000002",
      "content" : "Quick White Fox",
      "create_date" : "2015-01-02",
      "user.name" : "fake li",
      "user.age" : 26,
      "status" : "disable"
    }
  }
]

3.5 function_score查询

function_score查询可以修改查询返回的文档相关性分数,需要定义一个查询和若干个函数,用这些函数为查询返回的每个文档计算一个新分数。

示例如下:

POST my_index_01/_search
{
  "query": {
     "function_score": {
        "query": { "match_all": {} },
        "boost": "5", 
        "functions": [
          {
            "filter": { "match": { "content": "Brown" } },
            "random_score": {}, 
            "weight": 23
          },
          {
            "filter": { "match": { "content": "White" } },
            "weight": 42
          }
        ],
        "max_boost": 42,
        "score_mode": "max",
        "boost_mode": "multiply",
        "min_score": 30
    }
  }
}
score_mode
参数值
参数说明
multiply 分数相乘(默认)
sum 分数之和
avg 分数平均
first 第一个函数的分数
max 最大分数值
min 最小分数值
boost_mode
参数值
参数说明
multiply 函数分数与查询分数相乘(默认)
replace 只使用函数分数,忽略查询分数
sum 函数分数与查询分数之和
avg 函数分数与查询分数平均
max 函数分数与查询分数之间最大值
min 函数分数与查询分数之间最小值
script_score

除了自定义函数,还可以使用脚本函数,使用script_score函数可以包装另一个查询,并使用脚本表达式从文档中的其他数值字段值来定制它的评分。示例如下:

POST my_index_01/_search
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "script_score": {
        "script": {
          "source": "Math.log(2 + doc['user.age'].value)"
        }
      }
    }
  }
}

脚本支持参数形式,示例如下:

POST my_index_01/_search
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "script_score": {
        "script": {
          "params": {
            "a": 5,
            "b": 1.2
          },
          "source": "params.a / Math.pow(params.b, doc['user.age'].value)"
        }
      }
    }
  }
}
其他得分函数
上一篇 下一篇

猜你喜欢

热点阅读