博客
关于我
【Elasticsearch】相关度控制
阅读量:483 次
发布时间:2019-03-07

本文共 9802 字,大约阅读时间需要 32 分钟。

一.数据导入

  • 本人测试数据集下载https://download.csdn.net/download/qq_30285985/12645770
  • 更多数据集下载https://www.cluebenchmarks.com/dataSet_search.html

二.创建索引

#GET http://192.168.16.128:9200/es_news{       "settings": {           "number_of_shards" :   1,        "number_of_replicas" : 0    },  "mappings":{       "properties":{         "id":{   "type":"long"},      "title":{   "type":"text","analyzer":"ik_max_word",       "search_analyzer": "ik_smart" },      "content":{   "type":"text","analyzer":"ik_smart"},      "shortname":{   "type":"text","analyzer":"ik_max_word"},      "location":{   "type":"geo_point"}    }  }    }

数据导入->

自定义添加数据。

POST http://192.168.16.128:9200/es_news/_doc{     "title": "我中了一个奖品",  "content":  "奖品内容是苹果电脑",  "location": "88.884874,29.263792",   "shortname": "日喀则"}

三.什么是相关性?

每个文档都有相关性评分,用一个正浮点数字段 _score 来表示 。 _score 的评分越高,相关性越高。换句话说,就是_score 越高,就离我们想要搜索到的结果越相近。

Elasticsearch 的相似度算法被定义为检索词频率/反向文档频率, TF/IDF ,包括以下内容:

  • 检索词频率

    检索词在该字段出现的频率?出现频率越高,相关性也越高。 字段中出现过 5 次要比只出现过 1 次的相关性高。如:检索词 honeymoon 在这个文档的 tweet 字段中的出现次数。

  • 反向文档频率

    每个检索词在索引中出现的频率?频率越高,相关性越低。检索词出现在多数文档中会比出现在少数文档中的权重更低。如:检索词 honeymoon 在索引上所有文档的 tweet 字段中出现的次数。

  • 字段长度准则

    字段的长度是多少?长度越长,相关性越低。 检索词出现在一个短的 title 要比同样的词出现在一个长的 content 字段权重更大。如:在这个文档中, tweet 字段内容的长度 -- 内容越长,值越小。

通过explain为true可查看分数是如何计算的。

#GET http://192.168.16.128:9200/es_news/_search{       "explain":"true",    "query":{           "match":{               "content":"奖品"        }    }}

查询结果如下:

{       "took":5,    "timed_out":false,    "_shards":{           "total":1,        "successful":1,        "skipped":0,        "failed":0    },    "hits":{           "total":{               "value":3,            "relation":"eq"        },        "max_score":9.761058,        "hits":[            {                   "_shard":"[es_news][0]",                "_node":"VkN6WwZZQISzsHaUZA5EBw",                "_index":"es_news",                "_type":"_doc",                "_id":"BFY7b3MB_Kk3jjQO7RPr",                "_score":9.761058,                "_source":{                       "title":"我中了一个奖品",                    "content":"奖品内容是苹果电脑",                    "location":"88.884874,29.263792",                    "shortname":"日喀则"                },                "_explanation":{                       "value":9.761058,                    "description":"weight(content:奖品 in 1400) [PerFieldSimilarity], result of:",                    "details":[                        {                               "value":9.761058,                            "description":"score(freq=1.0), computed as boost * idf * tf from:",                            "details":[                                {                                       "value":2.2,                                    "description":"boost",                                    "details":[                                    ]                                },                                {                                       "value":5.9928923,                                    "description":"idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",                                    "details":[                                        {                                               "value":3,                                            "description":"n, number of documents containing term",                                            "details":[                                            ]                                        },                                        {                                               "value":1401,                                            "description":"N, total number of documents with field",                                            "details":[                                            ]                                        }                                    ]                                },                                {                                       "value":0.7403511,                                    "description":"tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",                                    "details":[                                        {                                               "value":1,                                            "description":"freq, occurrences of term within document",                                            "details":[                                            ]                                        },                                        {                                               "value":1.2,                                            "description":"k1, term saturation parameter",                                            "details":[                                            ]                                        },                                        {                                               "value":0.75,                                            "description":"b, length normalization parameter",                                            "details":[                                            ]                                        },                                        {                                               "value":3,                                            "description":"dl, length of field",                                            "details":[                                            ]                                        },                                        {                                               "value":53.243397,                                            "description":"avgdl, average length of field",                                            "details":[                                            ]                                        }                                    ]                                }                            ]                        }                    ]                }            }         ]    }}

_explanation.details字段中说明了分数是如何计算的。score(freq=1.0), computed as boost * idf * tf from:说明分数是由 boost,idf,tf三个字段相乘得到的。boost2.2分,idf为5.9928923分,tf为0.7403511分,最后相乘为9.761058分。

四.打分控制

1.字段权重修改

在实际的搜索过程中title字段和content字段的权重一定是不一样的,就比如一篇作文,标题的权重一定比内容高。

可在^2,将权重放大2倍。

{       "query":{           "multi_match":{               "query":  "奖品",            "fields": [ "content", "title^2" ]         }    }}

2.点赞数打分

​ 遇到复杂的情况时,简单粗暴的权重翻倍就无法满足我们的需求了。

可以通过function-score来进行更详细的评分设置。
比如只按照点赞数进行打分呢?

##PUT /blogposts/post/1{     "title":   "About popularity",  "content": "In this post we will talk about...",  "votes":   6}
##GET /blogposts/post/_search{     "query": {       "function_score": {          "query": {            "multi_match": {             "query":    "popularity",          "fields": [ "title", "content" ]        }      },      "field_value_factor": {            "field": "votes" 		"missing":"1"  ## 表示没有votes字段的时候默认为1      }    }  }}

3.点赞数更加平滑

​ 按照点赞来评分排序的话,看似是一个很好的选择,但是0个赞和1个赞对比是有很大区别的,但是100个赞和101个赞对比呢?显得就没有那么大的区别了。

​ 所以可以通过modifier以平滑的方式来处理votes的值。换句话说,我们希望最开始的一些赞更重要,但是其重要性会随着数字的增加而降低。

0 个赞与 1 个赞的区别应该比 10 个赞与 11 个赞的区别大很多。

点赞数打分算法:

new_score = old_score * number_of_votes

平滑点赞算法

new_score = old_score * log(1 + number_of_votes)

在这里插入图片描述

在这里插入图片描述

请求如下:

##GET /blogposts/post/_search{     "query": {       "function_score": {         "query": {           "multi_match": {             "query":    "popularity",          "fields": [ "title", "content" ]        }      },      "field_value_factor": {           "field":    "votes",        "modifier": "log1p"       }    }  }}

修饰语 modifier 的值可以为: none (默认状态)、 loglog1plog2plnln1pln2psquaresqrt 以及 reciprocal 。想要了解更多信息请参照:

4.点赞平滑程度调节

​ 前面说modifier可以使得点赞的分数变得更加平滑,但是这个平滑的程度如何控制呢?看图!

在这里插入图片描述

默认情况下分数计算方式:

new_score = old_score * log(1 + number_of_votes)

通过factor来调节幅度:

new_score = old_score * log(1 + factor * number_of_votes)

请求方式

##GET /blogposts/post/_search{     "query": {       "function_score": {         "query": {           "multi_match": {             "query":    "popularity",          "fields": [ "title", "content" ]        }      },      "field_value_factor": {           "field":    "votes",        "modifier": "log1p",        "factor":   2       }    }  }}

5.越近越好

​ 点赞评分先告一段落,在大部分场景位置评分的权重相对会高一点,比如搜索酒店,正常来说会搜索附近的小于100块钱一晚酒店。

function_score 提供了一组衰减函数。让我们有能力在两个滑动标准,如地点和价格,之间权衡。

有三种衰减函数—— linearexpgauss (线性、指数和高斯函数),它们可以操作数值、时间以及经纬度地理坐标点这样的字段。所有三个函数都能接受以下参数:

  • origin

    中心点 或字段可能的最佳值,落在原点 origin 上的文档评分 _score 为满分 1.0

  • scale

    衰减率,即一个文档从原点 origin 下落时,评分 _score 改变的速度。(例如,每 £10 欧元或每 100 米)。

  • decay

    从原点 origin 衰减到 scale 所得的评分 _score ,默认值为 0.5

  • offset

    以原点 origin 为中心点,为其设置一个非零的偏移量 offset 覆盖一个范围,而不只是单个原点。在范围 -offset <= origin <= +offset 内的所有评分 _score 都是 1.0

在这里插入图片描述

​ 原点 origin (即中心点)的值都是 40offset5 ,也就是在范围 40 - 5 <= value <= 40 + 5 内的所有值都会被当作原点 origin 处理——所有这些点的评分都是满分 1.0

​ 在此范围之外,评分开始衰减,衰减率由 scale 值(此例中的值为 5 )和 衰减值 decay (此例中为默认值 0.5 )共同决定。结果是所有三个曲线在 origin +/- (offset + scale) 处的评分都是 0.5 ,即点 3050 处。

linearexpgauss (线性、指数和高斯)函数三者之间的区别在于范围( origin +/- (offset + scale) )之外的曲线形状:

  • linear 线性函数是条直线,一旦直线与横轴 0 相交,所有其他值的评分都是 0.0
  • exp 指数函数是先剧烈衰减然后变缓。
  • gauss 高斯函数是钟形的——它的衰减速率是先缓慢,然后变快,最后又放缓。

选择曲线的依据完全由期望评分 _score 的衰减速率来决定,即距原点 origin 的值。

如此的话搜索酒店大概可这样请求:

#GET /_search{     "query": {       "function_score": {         "functions": [        {             "gauss": {               "location": {                  "origin": {    "lat": 51.5, "lon": 0.12 },              "offset": "2km",              "scale":  "3km"            }          }        },        {             "gauss": {               "price": {                  "origin": "50",               "offset": "50",              "scale":  "20"            }          },          "weight": 2         }      ]    }  }}

但是明明想是钱是小于100块钱酒店?为什么price的origin要50呢?在这里暂且认为用户喜欢的是越低越好。如果是设置成100的话,和100偏差较大的酒店评分就会变得很低。所以设置成50,这样50左右的,都可以进行比较友好的评分。

参考文档:

转载地址:http://zygdz.baihongyu.com/

你可能感兴趣的文章
Mysql 常见错误
查看>>
mysql 常见问题
查看>>
MYSQL 幻读(Phantom Problem)不可重复读
查看>>
mysql 往字段后面加字符串
查看>>
mysql 快照读 幻读_innodb当前读 与 快照读 and rr级别是否真正避免了幻读
查看>>
MySQL 快速创建千万级测试数据
查看>>
mysql 快速自增假数据, 新增假数据,mysql自增假数据
查看>>
MySql 手动执行主从备份
查看>>
Mysql 批量修改四种方式效率对比(一)
查看>>
mysql 批量插入
查看>>
Mysql 报错 Field 'id' doesn't have a default value
查看>>
MySQL 报错:Duplicate entry 'xxx' for key 'UNIQ_XXXX'
查看>>
Mysql 拼接多个字段作为查询条件查询方法
查看>>
mysql 排序id_mysql如何按特定id排序
查看>>
Mysql 提示:Communication link failure
查看>>
mysql 插入是否成功_PDO mysql:如何知道插入是否成功
查看>>
Mysql 数据库InnoDB存储引擎中主要组件的刷新清理条件:脏页、RedoLog重做日志、Insert Buffer或ChangeBuffer、Undo Log
查看>>
mysql 数据库中 count(*),count(1),count(列名)区别和效率问题
查看>>
mysql 数据库备份及ibdata1的瘦身
查看>>
MySQL 数据库备份种类以及常用备份工具汇总
查看>>