当前位置:   article > 正文

ElasticSearch7之function_socre使用心得_functionscore

functionscore

介绍:
1、function_score是可以修改查询检索文档的分数,使用function_score必须定义​​一个查询和一个或多个函数,为查询返回的每个文档计算一个新的分数。

function_score提供的评分函数:
1、weight : 设置一个float类型的权重值,使最终分数是查询分数与该权重值的乘积

2、field_value_factor : 允许使用文档中的字段来影响分数

  1. GET /_search
  2. {
  3. "query": {
  4. "function_score": {
  5. "field_value_factor": {
  6. "field": "my-int",
  7. "factor": 1.2,
  8. "modifier": "sqrt",
  9. "missing": 1
  10. }
  11. }
  12. }
  13. }

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、单个评分函数:

  1. GET /_search
  2. {
  3. "query": {
  4. "function_score": {
  5. "query": {.....}, //主查询,查询完后这裡自己会有一个评分,就是查询分数
  6. "field_value_factor": {...}, //在查询分数的基础上,给他加上评分函数计算出来的分数,如果只有一个评分函数时,直接将评分函数写在query下面就可以了
  7. "boost_mode": "multiply", //決定查询分数和评分函数分数怎么合并
  8. "max_boost": 1.5 //限制评分函数计算出来的最高分,但是不会限制查询分数
  9. }
  10. }
  11. }

2、多个评分函数(用functions包含这些函数)

  1. GET /_search
  2. {
  3. "query": {
  4. "function_score": {
  5. "query": { "match_all": {} },
  6. "functions": [
  7. {
  8. "filter": { "match": { "test": "bar" } },
  9. "random_score": {},
  10. "weight": 23
  11. },
  12. {
  13. "filter": { "match": { "test": "cat" } },
  14. "weight": 42
  15. },
  16. {
  17. "script_score": {
  18. "script": {
  19. "source": "Math.log(2 + doc['my-int'].value)"
  20. }
  21. }
  22. }
  23. ],
  24. "max_boost": 42,
  25. "score_mode": "max",
  26. "boost_mode": "multiply",
  27. "min_score": 42
  28. }
  29. }
  30. }

特别注意:

1、如果查询条件中存在距离过滤的,查询分数为0,如果不指定boost_mode的分数合并方式(默认相乘),则计算出来的分数都是0,如下:(纠正一下,无意间看到一篇文章说“在一个查询语句里面可以同时存在queryfilter,只不过只有query的查询字段会进行相关性_score的计算,而filter仅仅用来筛选”,所以这里造成查询分时为0并不是filter的原因,而是must:[]的原因)

  1. {
  2. "query":{
  3. "function_score":{
  4. "query":{
  5. "bool":{
  6. "must":[],
  7. "filter":{
  8. "geo_distance":{
  9. "distance":"200km",
  10. "location":{
  11. "lat":23.31231,
  12. "lon":120.231231
  13. }
  14. }
  15. }
  16. }
  17. },
  18. "functions":[
  19. {
  20. "filter":{"match":{"test": "bar"}},
  21. "weight":20
  22. },
  23. {
  24. "script_score":{
  25. "script":{
  26. "lang":"painless",
  27. "params":{"value":20},
  28. "inline":"Math.log(2 + doc['my-int'].value*params.value)"
  29. }
  30. }
  31. }
  32. ],
  33. "score_mode":"sum"
  34. //"boost_mode":"sum"
  35. }
  36. },
  37. "from":0,
  38. "size":5,
  39. "sort" : [{"_score" : "asc" }],
  40. "explain": true
  41. }

结果:

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字段是作为一个整体来索引和查询的。
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/973111
推荐阅读
相关标签
  

闽ICP备14008679号