相关性介绍
搜索的相关性算分,描述了一个文档和查询语句匹配的程度。ES 会对每个匹配查询条件的结果进行算分_score。打分的本质是排序,需要把最符合用户需求的文档排在前面。
如下例子:显而易见,查询JAVA多线程设计模式,文档id为2,3的文档的算分更高
如何衡量相关性:
- Precision(查准率)―尽可能返回较少的无关文档
- Recall(查全率)–尽量返回较多的相关文档
- Ranking -是否能够按照相关度进行排序
相关性算法
在 es5 之前默认的相关性算分采用TF-IDF,现在采用BM 25。
TF-IDF
TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。
- TF-IDF被公认为是信息检索领域最重要的发明,除了在信息检索,在文献分类和其他相关领域有着非常广泛的应用。
- IDF的概念,最早是剑桥大学的“斯巴克.琼斯”提出
- 1972年——“关键词特殊性的统计解释和它在文献检索中的应用”,但是没有从理论上解释IDF应该是用log(全部文档数/检索词出现过的文档总数),而不是其他函数,也没有做进一步的研究
- 1970,1980年代萨尔顿和罗宾逊,进行了进一步的证明和研究,并用香农信息论做了证明http://www.staff.city.ac.uk/~sb317/papers/foundations_bm25_review.pdf
- 现代搜索引擎,对TF-IDF进行了大量细微的优化
Lucene中的TF-IDF评分公式:
- TF是词频(Term Frequency)
检索词在文档中出现的频率越高,相关性也越高。
词频(TF) = 某个词在文档中出现的次数 / 文档的总词数
- IDF是逆向文本频率(Inverse Document Frequency)
每个检索词在索引中出现的频率,频率越高,相关性越低。总文档中有些词比如“是”、“的” 、“在” 在所有文档中出现频率都很高,并不重要,可以减少多个文档中都频繁出现的词的权重。
逆向文本频率(IDF)= log (语料库的文档总数 / (包含该词的文档数+1))
- 字段长度归一值( field-length norm)
检索词出现在一个内容短的 title 要比同样的词出现在一个内容长的 content 字段权重更大。
以上三个因素——词频(term frequency)、逆向文本频率(inverse document frequency)和字段长度归一值(field-length norm)——是在索引时计算并存储的,最后将它们结合在一起计算单个词在特定文档中的权重。
BM25
BM25 就是对 TF-IDF 算法的改进,对于 TF-IDF 算法,TF(t) 部分的值越大,整个公式返回的值就会越大。BM25 就针对这点进行来优化,随着TF(t) 的逐步加大,该算法的返回值会趋于一个数值。
- 从ES 5开始,默认算法改为BM 25
- 和经典的TF-IDF相比,当TF无限增加时,BM 25算分会趋于一个数值
- BM 25的公式
通过Explain API查看TF-IDF
示例:
PUT /test_score/_bulk
{"index":{"_id":1}}
{"content":"we use Elasticsearch to power the search"}
{"index":{"_id":2}}
{"content":"we like elasticsearch"}
{"index":{"_id":3}}
{"content":"Thre scoring of documents is caculated by the scoring formula"}
{"index":{"_id":4}}
{"content":"you know,for search"}
GET /test_score/_search
{
"explain": true,
"query": {
"match": {
"content": "elasticsearch"
}
}
}
GET /test_score/_explain/2
{
"query": {
"match": {
"content": "elasticsearch"
}
}
}
Boosting Query
Boosting是控制相关度的一种手段。可以通过指定字段的boost值影响查询结果
参数boost的含义:
- 当boost > 1时,打分的权重相对性提升
- 当0 < boost
- 当boost
应用场景:希望包含了某项内容的结果不是不出现,而是排序靠后。
下面示例可以看到,设置 content 的权重高一些,查询的结果根据 content 匹配度高一些
#批量插入数据
POST /blogs/_bulk
{"index": {"_id": 1}}
{"title":"Apple iPad", "content": "Apple iPad,Apple iPad"}
{"index": {"_id": 2}}
{"title": "Apple iPad,Apple iPad", "content": "Apple iPad"}
#使用 boost 控制权重
GET /blogs/_search
{
"query": {
"bool": {
"should": [
{"match": {
"title": {
"query": "apple,ipad",
"boost": 4
}
}},
{
"match": {
"content": {
"query": "apple,ipad",
"boost": 1
}
}
}
]
}
}
}
案例:要求苹果公司的产品信息优先展示
示例数据
#批量插入数据
POST /news/_bulk
{"ineex": {"_id": 1}}
{"content": "Apple Mac"}
{"index": {"_id": 2}}
{"content": "Apple Phone"}
{"index": {"_id": 3}}
{"content": "Apple employee like Apple Pie and Apple Juice"}
普通查询都是 id 为 3 的数据排名靠前,但是我希望另外两个 排名靠前
方式一:
使用 must not 排除不是苹果公司产品的文档
下面示例,可以看到排除了第三条数据。
GET /news/_search
{
"query": {
"bool": {
"must": [
{"match": {
"content": "apple"
}}
],
"must_not": [
{"match": {
"content": "pie"
}}
]
}
}
}
方式二
方式一这种方式是直接排除了,我希望的是不排除,只是排名靠后。
可以利用negative_boost降低相关性
对某些返回结果不满意,但又不想排除掉( must_not),可以考虑boosting query的negative_boost。
- negative_boost 对 negative部分query生效
- 计算评分时,boosting部分评分不修改,negative部分query乘以negative_boost值
- negative_boost取值:0-1.0,举例:0.3
可以看到,此时再次查询,第三条数据算分就比较低了,满足我们的需求
GET /news/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"content": "apple"
}
},
"negative": {
"match": {
"content": "pie"
}
},
"negative_boost": 0.2
}
}
}
感谢观看!!!感兴趣的小伙伴可以关注收藏,持续更新中~~~