ElasticSearch7之function_socre使用心得

介绍:
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,如下:(纠正一下,无意间看到一篇文章说“在一个查询语句里面可以同时存在queryfilter,只不过只有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. mustAND

  • Elasticsearch: must子句内的条件必须全部满足。它类似于逻辑上的AND操作。如果你在bool查询中使用must,那么列出的所有条件都必须匹配,才能返回结果。

  • MySQL: 使用AND操作符可以达到类似的效果。在WHERE子句中连接多个条件时,只有当所有条件都为真时,才会返回记录。

2. shouldOR

  • Elasticsearch: should子句中的条件至少需要满足一个。它相当于逻辑上的OR操作。在某些情况下,如果没有指定minimum_should_match参数,should查询在没有mustfilter条件的情况下,至少需要匹配一个条件。

  • MySQL: OR操作符用于连接两个或多个条件,如果其中任何一个条件为真,记录就会被选中。这与should的工作方式相似。

3. terms查询与IN

  • Elasticsearch: terms查询允许你指定一个字段应该包含的多个值中的任意一个。这对于检索多个可能值的场景非常有用。

  • MySQL: IN操作符允许你在WHERE子句中指定列必须为列表中的某一个值。这与terms查询的作用非常相似,都是用于匹配字段值在给定的值列表中的情况。

4. filterAND(但不影响评分)

  • Elasticsearch: filter上下文中的查询条件必须全部满足,但它们不会影响查询结果的评分(相关性得分)。这适用于过滤数据,而不关心返回结果的顺序。

  • MySQL: 虽然MySQL中的WHERE子句也用于过滤记录,并且所有条件都必须满足,但MySQL并不直接涉及到评分的概念。在等效性的层面上,filter相当于是使用AND连接的多个条件,只是在Elasticsearch中,它指的是不计分的过滤。

5、ES分词对于查询的影响

在Elasticsearch中,分词器(Analyzer)对于查询的处理至关重要,尤其是在处理文本字段时。Elasticsearch中的textkeyword类型字段对分词的处理方式有明显的不同,这对查询条件的匹配有直接影响。

text字段与分词

  • text字段在存储到Elasticsearch之前会被分词器处理,这意味着文本被拆分成一系列的独立词项(tokens)。例如,一个句子"Quick brown fox"在默认的分词器(通常是标准分词器)下可能会被分成"quick"、"brown"、"fox"三个词项。
  • 在执行查询时,查询条件也会经过相同的分词过程,然后Elasticsearch会查找匹配的词项。因此,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字段是作为一个整体来索引和查询的。
  • 在 Elasticsearch 中创建索引时,如果没有显式定义字段的映射(mapping),​​字符串类型的字段默认会被映射为 text 类型,并自动生成一个 keyword 子字段​​。这是由 Elasticsearch 的动态映射(Dynamic Mapping)机制决定的。
  • 使用默认分词器(standard Analyzer)对text字段进行分词时,“.;,”这三个字符在一些特定场景下时不会对字段进行分词的,如“123,123”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值