赞
踩
介绍:
1、function_score是可以修改查询检索文档的分数,使用function_score必须定义一个查询和一个或多个函数,为查询返回的每个文档计算一个新的分数。
function_score提供的评分函数:
1、weight : 设置一个float类型的权重值,使最终分数是查询分数与该权重值的乘积
2、field_value_factor : 允许使用文档中的字段来影响分数
- GET /_search
- {
- "query": {
- "function_score": {
- "field_value_factor": {
- "field": "my-int",
- "factor": 1.2,
- "modifier": "sqrt",
- "missing": 1
- }
- }
- }
- }
field:要从文档中提取的字段(相乘的字段,该字段必须是数字类型)。
factor:与字段值相乘的可选因子,默认为1。
modifier:应用于字段值的修饰符,可以是以下之一:none、log、 log1p、log2p、ln、ln1p、ln2p、square、sqrt、 或reciprocal。默认为none(参考官网解释:这里)
3、random_score : 为每个用户都使用一个不同的随机评分
4、decay functions(衰减函数,如:linear、exp、guass):以某个字段的值为基准,距离某个值越近得分越高
5、script_score : 自定义脚本函数控制评分计算
function_score参数解释:
1、boost_mode : 决定查询分数和评分函数计算出来的分数如何合并,默认相乘(multiply,sum,min,max,replace)
2、score_mode : 决定functions里面的评分函数之间的分数如何合并,默认相乘(multiply,sum,min,max,avg,first(使用首个函数))
function_socre查询模板:
1、单个评分函数:
- GET /_search
- {
- "query": {
- "function_score": {
- "query": {.....}, //主查询,查询完后这裡自己会有一个评分,就是查询分数
- "field_value_factor": {...}, //在查询分数的基础上,给他加上评分函数计算出来的分数,如果只有一个评分函数时,直接将评分函数写在query下面就可以了
- "boost_mode": "multiply", //決定查询分数和评分函数分数怎么合并
- "max_boost": 1.5 //限制评分函数计算出来的最高分,但是不会限制查询分数
- }
- }
- }
2、多个评分函数(用functions包含这些函数)
- GET /_search
- {
- "query": {
- "function_score": {
- "query": { "match_all": {} },
- "functions": [
- {
- "filter": { "match": { "test": "bar" } },
- "random_score": {},
- "weight": 23
- },
- {
- "filter": { "match": { "test": "cat" } },
- "weight": 42
- },
- {
- "script_score": {
- "script": {
- "source": "Math.log(2 + doc['my-int'].value)"
- }
- }
- }
- ],
- "max_boost": 42,
- "score_mode": "max",
- "boost_mode": "multiply",
- "min_score": 42
- }
- }
- }
特别注意:
1、如果查询条件中存在距离过滤的,查询分数为0,如果不指定boost_mode的分数合并方式(默认相乘),则计算出来的分数都是0,如下:(纠正一下,无意间看到一篇文章说“在一个查询语句里面可以同时存在query
和filter
,只不过只有query
的查询字段会进行相关性_score
的计算,而filter
仅仅用来筛选”,所以这里造成查询分时为0并不是filter的原因,而是must:[]的原因)
- {
- "query":{
- "function_score":{
- "query":{
- "bool":{
- "must":[],
- "filter":{
- "geo_distance":{
- "distance":"200km",
- "location":{
- "lat":23.31231,
- "lon":120.231231
- }
- }
- }
- }
- },
- "functions":[
- {
- "filter":{"match":{"test": "bar"}},
- "weight":20
- },
- {
- "script_score":{
- "script":{
- "lang":"painless",
- "params":{"value":20},
- "inline":"Math.log(2 + doc['my-int'].value*params.value)"
- }
- }
- }
- ],
- "score_mode":"sum"
- //"boost_mode":"sum"
- }
- },
- "from":0,
- "size":5,
- "sort" : [{"_score" : "asc" }],
- "explain": true
- }
结果:
2、ES6.5版本之后(本文对应的es版本是7.10),weight不能为负值,且如果评分函数计算出来的值为负数,ES会自动过滤掉对应的数据。
3、Elasticsearch中,内置了很多分词器(analyzers),默认是standard 分词器
4、mysql与es类比
1.
must
与AND
Elasticsearch:
must
子句内的条件必须全部满足。它类似于逻辑上的AND
操作。如果你在bool
查询中使用must
,那么列出的所有条件都必须匹配,才能返回结果。MySQL: 使用
AND
操作符可以达到类似的效果。在WHERE
子句中连接多个条件时,只有当所有条件都为真时,才会返回记录。2.
should
与OR
Elasticsearch:
should
子句中的条件至少需要满足一个。它相当于逻辑上的OR
操作。在某些情况下,如果没有指定minimum_should_match
参数,should
查询在没有must
或filter
条件的情况下,至少需要匹配一个条件。MySQL:
OR
操作符用于连接两个或多个条件,如果其中任何一个条件为真,记录就会被选中。这与should
的工作方式相似。3.
terms
查询与IN
Elasticsearch:
terms
查询允许你指定一个字段应该包含的多个值中的任意一个。这对于检索多个可能值的场景非常有用。MySQL:
IN
操作符允许你在WHERE
子句中指定列必须为列表中的某一个值。这与terms
查询的作用非常相似,都是用于匹配字段值在给定的值列表中的情况。4.
filter
与AND
(但不影响评分)
Elasticsearch:
filter
上下文中的查询条件必须全部满足,但它们不会影响查询结果的评分(相关性得分)。这适用于过滤数据,而不关心返回结果的顺序。MySQL: 虽然MySQL中的
WHERE
子句也用于过滤记录,并且所有条件都必须满足,但MySQL并不直接涉及到评分的概念。在等效性的层面上,filter
相当于是使用AND
连接的多个条件,只是在Elasticsearch中,它指的是不计分的过滤。
5、ES分词对于查询的影响
在Elasticsearch中,分词器(Analyzer)对于查询的处理至关重要,尤其是在处理文本字段时。Elasticsearch中的text
和keyword
类型字段对分词的处理方式有明显的不同,这对查询条件的匹配有直接影响。
text
字段与分词
text
字段在存储到Elasticsearch之前会被分词器处理,这意味着文本被拆分成一系列的独立词项(tokens)。例如,一个句子"Quick brown fox"在默认的分词器(通常是标准分词器)下可能会被分成"quick"、"brown"、"fox"三个词项。text
字段非常适合全文搜索场景,因为它能够匹配文本中的单词或短语的部分。text
字段使用分词器,它们对于模糊匹配和部分匹配非常有效。但这也意味着对于精确匹配场景可能不够理想,因为原始文本已被拆分成多个词项。keyword
字段与不分词
keyword
字段不会被分词器处理,而是作为整体被存储和索引。这意味着它们适用于需要精确匹配的场景,如日志分析、标签、枚举值等。keyword
字段时,必须使用字段中存储的确切值进行匹配,不会进行分词处理。这使得keyword
字段非常适合于过滤、排序和聚合操作,因为这些操作需要精确的值匹配。keyword
字段不进行分词,所以它们不适合用于全文搜索或需要从文本内容中提取词项的场景。它们更适合那些需要精确值匹配的用途。keyword
字段的term
查询
当对keyword
字段执行term
查询时,Elasticsearch会寻找与查询条件完全匹配的值。由于keyword
字段不进行分词,它会将整个字段值作为一个单一的词项进行索引。因此,term
查询会在keyword
字段中查找完全匹配的单个词项。
例如,如果有一个keyword
类型的字段status
,其值为"open_issue"
,当执行如下term
查询时:
{ "query": { "term": { "status": "open_issue" } } }
这个查询将匹配所有status
字段值完全为"open_issue"
的文档。
text
字段的term
查询
相比之下,当对text
字段执行term
查询时,查询条件首先会通过与该text
字段相同的分词器进行分词。之后,Elasticsearch会尝试在倒排索引中匹配这些分词后的词项。
假设有一个text
类型的字段description
,包含文本"Quick brown fox jumps over"
。如果使用默认的标准分词器,这个文本可能会被分词为"quick"
, "brown"
, "fox"
, "jumps"
, "over"
。当执行如下term
查询时:
{ "query": { "term": { "description": "quick" } } }
由于term
查询不会对查询字符串进行分词,所以它将尝试在description
字段的倒排索引中查找完全匹配"quick"
的词项。在这个例子中,查询将成功匹配包含"Quick brown fox jumps over"
的文档,因为"quick"
是分词结果之一。
注意事项
term
查询对于text
字段可能不是最佳选择,因为它不处理文本分词后的复杂情况。对于text
字段,通常使用match
查询来充分利用分词器的能力,进行全文搜索。keyword
字段上使用term
查询时,需要确保查询条件与字段中的值完全一致,包括大小写和空格,因为keyword
字段是作为一个整体来索引和查询的。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。