02.组合查询

1.bool查询

这个是用来组合查询使用,可以使用下面4个条件

must
子句(查询)必须出现在匹配的文档中,并将有助于得分。

filter
子句(查询)必须出现在匹配的文档中。但是,与查询分数不同的是,忽略该分数。 Filter子句在过滤器上下文中执行,这意味着计分被忽略,并且子句被考虑用于缓存。

should
子句(查询)应出现在匹配的文档中。

must_not
子句(查询)不得出现在匹配的文档中。子句在过filter context 中执行,这意味着计分被忽略,并且子句被视为用于缓存。由于计分被忽略,因此所有文档的分数均返回0。

这个地方的minimum_should_match需要注意,他会对should起作用,但是默认值受整个bool查询中的must,filter影响,如果你没有明确指定minimum_should_match那么:

  1. 当bool查询中只有should查询的话,则minimum_should_match的值是1
  2. 如果还有must,filter查询的话,则minimum_should_match的值为0,

这个地方像是一个坑,所以一定要注意,在shouldmustorfilter一起使用的话,尽量明确设置minimum_should_match,否则返回的结果可能并没有命中should中的任何一个条件。

bool查询的score计算方式是 mustshould查询的score的和

1.1. 使用样例

POST _search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user" : "kimchy" }
      },
      "filter": {
        "term" : { "tag" : "tech" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 20 }
        }
      },
      "should" : [
        { "term" : { "tag" : "wow" } },
        { "term" : { "tag" : "elasticsearch" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

1.2. filter的使用

GET _search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}



GET _search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}


GET _search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}

2. boost query

  1. 返回匹配肯定查询的文档,同时降低也匹配否定查询的文档的相关性得分。
  2. 您可以使用增强查询来降级某些文档,而不必将它们从搜索结果中排除。
GET /_search
{
    "query": {
        "boosting" : {
            "positive" : {
                "term" : {
                    "text" : "apple"
                }
            },
            "negative" : {
                 "term" : {
                     "text" : "pie tart fruit crumble tree"
                }
            },
            "negative_boost" : 0.5
        }
    }
}

positive:(必填)要运行的查询。返回的所有文档都必须与此查询匹配。

negative:(必填)查询用于降低匹配文档的相关性得分。
如果返回的文档与肯定查询和该negative查询匹配,文档的最终相关性得分按照如下所示规则进行计算:

  1. 从positive查询中获取原始的相关性分数。
  2. 将分数乘以negative_boost值。

negative_boost:(必需,浮点数)0到1.0之间的浮点数,用于降低与否定查询匹配的文档的相关性得分。

3. constant score query

这个查询一般包裹了一个filter context query,然后赋予每个文档一个固定的相关性得分

GET /_search
{
    "query": {
        "constant_score" : {
            "filter" : {
                "term" : { "user" : "kimchy"}
            },
            "boost" : 1.2
        }
    }
}

4. disjunction max query

可以翻译为最相似最重要查询

返回与一个或多个包装查询(称为查询子句或子句)匹配的文档。

如果返回的文档与多个查询子句匹配,则dis_max查询为该文档计算的相关性得分=max(来自任何匹配子句的最高相关性得分)+tie*其他匹配的子查询得分。

您可以使用dis_max在用不同提升因子映射的字段中搜索术语。

样例

GET /_search
{
    "query": {
        "dis_max" : {
            "queries" : [
                { "term" : { "title" : "Quick pets" }},
                { "term" : { "body" : "Quick pets" }}
            ],
            "tie_breaker" : 0.7
        }
    }
}

query

(必需的查询对象数组)包含一个或多个查询子句。返回的文档必须与这些查询中的一个或多个匹配。如果一个文档匹配多个查询,Elasticsearch将使用最高的相关性得分。

tie_breaker

(可选,float)0到1.0之间的浮点数,用于增加与多个查询子句匹配的文档的相关性得分。默认为0.0。
您可以使用tie_breaker值为多个字段中包含相同术语的文档分配比仅在多个字段中最好的包含该术语的文档更高的相关性分数,而不必将其与多个中两个不同术语的更好的情况混淆领域。

如果文档与多个子句匹配,则dis_max查询将计算该文档的相关性得分,如下所示:

  1. 从具有最高分数的匹配子句中获取相关性分数。
  2. 将来自其他任何匹配子句的得分乘以tie_breaker值。
  3. 将最高分数加到相乘的分数上。

如果tie_breaker值大于0.0,则所有匹配子句都计数,但是得分最高的子句计数最多。

5. function score

function_score允许您修改查询检索的文档分数。例如,如果分数函数在计算上很昂贵,并且在过滤后的文档集上计算分数也足够使用了,则此功能很有用。

要使用function_score,用户必须定义一个查询和一个或多个函数,这些函数为查询返回的每个文档计算一个新分数。

function_score只能与以下一个函数一起使用:

GET /_search
{
    "query": {
        "function_score": {
            "query": { "match_all": {} },
            "boost": "5", # 针对整个query的boost乘数
            "random_score": {},   # 这个random_score就是预定义的一个function,es有几个预定义的function,后面会讲到
            "boost_mode":"multiply"
        }
    }
}

同时,还可以组合多个function 或者是对一些特殊的doc进行function score的计算

GET /_search
{
    "query": {
        "function_score": {
          "query": { "match_all": {} },
          "boost": "5", 
          "functions": [
              {
                  "filter": { "match": { "test": "bar" } },
                  "random_score": {}, 
                  "weight": 23
              },
              {
                  "filter": { "match": { "test": "cat" } },
                  "weight": 42
              }
          ],
          "max_boost": 42,
          "score_mode": "max",
          "boost_mode": "multiply",
          "min_score" : 42
        }
    }
}

上面的这些看不懂不要紧,后面会逐一解释。

首先,通过定义的function对每个文档评分。参数score_mode指定如何组合计算出的分数:

5.1. score_mode boost_mode的含义

score_mode 和 boost_mode 含义一致,但是起作用的地方不一致,score_mode针对的是多个function计算出来的score如何最终计算出来这些function对应的score,
boost_mode 针对的是如何将上一步计算的function计算的score和query查询得到的score合并得到最终的query score

  1. multiply: 多个score相乘
  2. sum: 相加
  3. avg: 求平均
  4. first: 第一个function计算出来的score
  5. max: 最大值
  6. min: 最小值

  因为score 可以在不同的范围上(例如,衰减函数的分数在0到1之间,而field_value_factor则是任意的),并且由于有时希望函数对分数有不同的影响,因此每个函数的分数都可以由用户定义weight。weight可以在函数数组(上面的示例)中为每个函数定义,并乘以各个函数计算出的分数。如果给定weight而没有任何其他函数声明,则weight充当仅返回weight的函数。

如果将score_mode设置为avg,则各个分数将由加权平均值合并。例如,如果两个function返回分数1和2,并且它们各自的weight分别为3和4,则它们的分数将合并为(1 * 3 + 2 * 4)/(3 + 4)而不是(1 * 3 + 2 * 4)/ 2。

通过设置max_boost参数,可以将新score限制为不超过特定限制。 max_boost的默认值为FLT_MAX。

新计算的分数与query score 合并。参数boost_mode定义如何合并:

  1. multiply: query score and function score 相乘 multiplied (default),这个是默认设置
  2. replace: 只使用function计算出来的score
  3. sum: query score and function score are 相加 added
  4. avg: average
  5. max: max of query score and function score
  6. min: min of query score and function score

5.2. function的类型

script_score
weight
random_score
field_value_factor
decay functions: gauss, linear, exp

1.script_score

script_score函数允许您包装另一个查询,并可以选择使用脚本表达式从文档中其他数字字段值派生的计算来自定义另一个查询的评分。这是一个简单的示例:

GET /_search
{
    "query": {
        "function_score": {
            "query": {
                "match": { "message": "elasticsearch" }
            },
            "script_score" : {
                "script" : {
                  "source": "Math.log(2 + doc['likes'].value)"
                }
            }
        }
    }
}

在不同的脚本字段值和表达式之上,_score脚本参数可用于基于包装的查询来检索分数。

脚本编译被缓存以加快执行速度。如果脚本具有需要考虑的参数,则最好重用相同的脚本并为其提供参数:

GET /_search
{
    "query": {
        "function_score": {
            "query": {
                "match": { "message": "elasticsearch" }
            },
            "script_score" : {
                "script" : {
                    "params": {
                        "a": 5,
                        "b": 1.2
                    },
                    "source": "params.a / Math.pow(params.b, doc['likes'].value)"
                }
            }
        }
    }
}

请注意,与custom_score查询不同,query的分数将与script评分的结果相乘。如果希望禁止这种情况,请设置“ boost_mode”:“ replace”

2.weight

weight分数使您可以将分数乘以提供的weight。有时可能需要这样做,因为在特定查询上设置的boost值会被标准化,而对于此得分函数则不会。数字值是float类型。

3.random_score

random_score生成的分数从0到1一直均匀分布,但不包括1。默认情况下,它使用内部Lucene doc id作为随机性的来源,这非常有效,但不幸的是不可复现,因为文档可能会通过合并重新编号。

如果您希望分数是可复现的,则可以提供seed和field。然后将基于该seed,所考虑文档的字段的最小值以及根据索引名称和分片ID计算的salt来计算最终分数,以便获得具有相同值但存储在不同索引中的文档不同的分数。请注意,位于相同分片中且具有相同字段值的文档将获得相同的分数,因此通常希望使用对所有文档都具有唯一值的字段。最好的默认选择是使用_seq_no字段,其唯一的缺点是,如果更新文档,则分数会改变,因为更新操作也会更新_seq_no字段的值。

可以在不设置字段的情况下设置种子,但这已被弃用,因为这需要在_id字段上加载字段数据,这会占用大量内存。

GET /_search
{
    "query": {
        "function_score": {
            "random_score": {
                "seed": 10,
                "field": "_seq_no"
            }
        }
    }
}

4.field_value_factor

使用field_value_factor函数可以使用文档中的字段来影响得分。与使用script_score函数类似,但是它避免了脚本编写的开销。如果用于多值字段,则在计算中仅使用该字段的第一个值。

例如,假设您有一个用数字likes字段索引的文档,并希望通过该字段影响文档的分数,那么这样做的示例如下所示:

GET /_search
{
    "query": {
        "function_score": {
            "field_value_factor": {
                "field": "likes",
                "factor": 1.2,
                "modifier": "sqrt",
                "missing": 1
            }
        }
    }
}

上面的查询,对应的score会这样计算score= sqrt(1.2 * doc[‘likes’].value)

field: 计算score使用的field
factor: 乘以field.value使用的系数,默认是1
modifier: 计算方式score的方式
missing: 没有这个field的doc如何打分,这个是默认将field.value替换为missing

modifier可以有以下几种

  1. none: 不会对字段值应用任何运算
  2. log: 取字段值的常用对数以10为底的对数。因为此函数可能返回负值(0到1之间的值),则会导致错误,因此建议改用log1p。
  3. log1p: 将1加至field.value值并取对数
  4. log2p: 在字段值上加2并取公共对数
  5. ln: 取字段值的自然对数。因为此函数将返回负值(0到1之间的值),会引起错误,所以建议改用ln1p。
  6. ln1p: 将1加到栏位值并取自然对数
  7. ln2p: 将2加到栏位值并取自然对数
  8. square: 对字段值求平方(乘以它本身)
  9. sqrt: 取字段值的平方根
  10. reciprocal: 倒数,交换字段值,与1 / x相同,其中x是字段的值
5.decay functions: gauss, linear, exp

衰减函数
衰减函数对文档进行评分,该函数的衰减取决于文档的数字字段值与用户给定原点的距离。这类似于范围查询,但具有平滑的边缘而不是框。
要对具有数字字段的查询使用距离评分,用户必须为每个字段定义一个原点和一个小数位数。需要原点来定义从中计算距离的“中心点”,并需要标度来定义衰减率。衰减函数指定为

"linear": { 
    "FIELD_NAME": { 
          "origin": "11, 12",
          "scale": "2km",
          "offset": "0km",
          "decay": 0.33
    }
}

在上面的示例中,该字段是geo_point类型,并且可以以geo格式提供起点。在这种情况下,必须使用单位指定比例和偏移。如果您的字段是日期字段,则可以将比例和偏移量设置为天,周等。例:

一个完整的样例

GET /_search
{
    "query": {
        "function_score": {
            "gauss": {
                "date": {
                      "origin": "2013-09-17", 
                      "scale": "10d",
                      "offset": "5d", 
                      "decay" : 0.5 
                }
            }
        }
    }
}

参数解析

origin: 用于计算距离的原点。对于数字字段,参数必须为数字;对于日期字段,参数必须为日期;对于地理字段,必须指定为地理点。地理位置和数字字段必填。对于日期字段,默认值为现在。支持日期数学(例如now-1h)作为源。

scale: 所有类型均必需。定义到原点的距离+偏移,计算出的分数将等于衰减参数。对于地理字段:可以定义为数字+单位(1km,12m,…)。默认单位是米。对于日期字段:可以定义为数字+单位(“ 1h”,“ 10d”,…。)。默认单位是毫秒。对于数字字段:任何数字。这个字段主要是配合decay使用,表示距离origin为scale的doc的衰减后的score应该为正常的decay定义的数值

offset:
如果定义了偏移量,则衰减函数将仅计算距离大于所定义偏移量的文档的衰减函数。默认值为0。这个就是说距离origin在offset范围内的值不进行衰减

decay
衰减参数定义了如何结合scale在距离上对文档进行评分。如果未定义decay,则距离为scale的文档将获得0.5分。

在第一个示例中,您的文档可能代表酒店,并且包含地理位置字段。您要根据酒店距指定位置的距离来计算衰减函数。您可能不会立即看到为高斯功能选择哪种比例,但是您可以说:“在距所需位置2公里的距离处,分数应降低到三分之一。”然后将自动调整参数“规模”,以确保得分函数为距所需位置2公里的酒店计算出0.33的得分。

在第二个示例中,字段值在2013-09-12和2013-09-22之间的文档的权重为1.0,从origin日期起15天的文档的权重为0.5。

6. 衰减函数支持

这个有很多图片,参考这里
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/query-dsl-function-score-query.html#_supported_decay_functions

高斯衰减,线性衰减,exp衰减

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值