elasticsearch打分机制


一、 文档打分的运作机制:TF-IDF

1、Lucenees的打分机制是一个公式,将查询作为输入,使用不同的手段来确定每一篇文档的得分,将每一个因素最后通过公式综合起来,返回该文档的最终得分,这个综合考量的过程,就是希望相关的文档被优先返回的考量过程,在Lucenees中这种相关性称为得分

2、 在开始计算得分之前,es使用了被搜索词条的频率和它有多常见来影响得分,从两个方面理解

①一个词条在某篇文档中出现的次数越多,该文档就越相关,称之为词频(term frequency),TF

②一个词条如果在不同的文档中出现的次数越多,它就越不相关,称之为逆文档频率(inverse document frequency),IDF

3、词频:TF,考虑一篇文档得分的首要方式,是查看一个词条在文档中出现的次数,比如某篇文章围绕es的打分展开的,那么文章中肯定会多次出现相关字眼,当查询时,我们认为该篇文档更符合,所以,这篇文档的得分会更高

4、逆文档频率:IDF

①相对于词频,逆文档频率稍显复杂,如果一个词条在索引中的不同文档中出现的次数越多,那么它就越不重要

②示例,假如es索引中,有如下3篇文档

The rules-which require employees to work from 9 am to 9 pm
In the weeks that followed the creation of 996.ICU in March
The 996.ICU page was soon blocked on multiple platforms including the messaging tool WeChat and the UC Browser.

③词条ICU的文档频率是2,因为它出现在2篇文档中,文档的逆源自得分乘以1/DFDF是该词条的文档频率,这就意味着,由于ICU词条拥有更高的文档频率,所以,它的权重会降低

④词条the的文档频率是3,它在3篇文档中都出现了,注意,尽管the在后两篇文档出都出现两次,但是它的词频是还是3,因为,逆文档词频只检查词条是否出现在某篇文档中,而不检查它在这篇文档中出现了多少次,那是词频该干的事儿**

⑤逆文档词频是一个重要的因素,用来平衡词条的词频,比如我们搜索the 996.ICU,单词the几乎出现在所有的文档中(中文中比如),如果这个鬼东西要不被均衡一下,那么the的频率将完全淹没996.ICU,所以,逆文档词频就有效的均衡了the这个常见词的相关性影响,以达到实际的相关性得分将会对查询的词条有一个更准确地描述

5、当词频和逆文档词频计算完成。就可以使用TF-IDF公式来计算文档的得分了

二、其他的打分方法

1、TF-IDF结合向量空间模型的实用评分模式,是esLucene最为主流的评分机制,但这并不是唯一的,除了TF-IDF这种实用模型之外,还有其他模型

2、Okapi BM25

①k1和b是数值的设置,用于调整得分是如何计算的

②k1控制对于得分而言词频(TF)的重要性

③b是介于0 ~ 1之间的数值,它控制了文档篇幅对于得分的影响程度

④默认情况下,k1设置为1.2,而b则被设置为0.75

discount_overlaps的设置用于告诉es,在某个字段中,多少个分词出现在同一位置,是否应该影响长度的标准化,默认值是true

3、随机性分歧(Divergence from randomness),即DFR相似度

4、LM Dirichlet相似度

5、LM Jelinek Mercer相似度

三、配置打分模型

1、简要配置BM25打分模型

# `BM25`是一种基于概率的打分框架

PUT w2
{
  "mappings": {
    "doc": {
      "properties": {
        "title": {
          "type": "text",
          "similarity": "BM25"
        }
      }
    }
  }
}

PUT w2/doc/1
{
  "title":"The rules-which require employees to work from 9 am to 9 pm"
}

PUT w2/doc/2
{
  "title":"In the weeks that followed the creation of 996.ICU in March"
}

PUT w2/doc/3
{
  "title":"The 996.ICU page was soon blocked on multiple platforms including the messaging tool WeChat and the UC Browser."
}

GET w2/doc/_search
{
  "query": {
    "match": {
      "title": "the 996"
    }
  }
}

2、BM25高级配置

PUT w3
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer":"ik_smart"
      }
    },
    "similarity": {
      "my_custom_similarity": {
        "type": "BM25",
        "k1": 1.2,
        "b": 0.75,
        "discount_overlaps": false
      }
    }
  },
  "mappings": {
    "doc": {
      "properties": {
        "title": {
          "type": "text",
          "similarity":"my_custom_similarity"
        }
      }
    }
  }
}

PUT w3/doc/1
{
  "title":"The rules-which require employees to work from 9 am to 9 pm"
}

PUT w3/doc/2
{
  "title":"In the weeks that followed the creation of 996.ICU in March"
}

PUT w3/doc/3
{
  "title":"The 996.ICU page was soon blocked on multiple platforms including the messaging tool WeChat and the UC Browser."
}

GET w3/doc/_search
{
  "query": {
    "match": {
      "title": "the 996"
    }
  }
}

3、配置全局打分模型:如果要使用某种特定的打分模型,并且希望应用到全局,那么就在elasticsearch.yml配置文件中加入

index.similarity.default.type: BM25

四、boosting

1、简介

boosting是一个用来修改文档相关性的程序,boosting有两种使用场景

②索引的时候,比如在定义mappings的时候

③查询一篇文档的时候

④以上两种方式都可以提升一个篇文档的得分,需要注意的是,在索引期间修改的文档boosting是存储在索引中的,要想修改boosting必须重新索引该篇文档

2、索引期间的boosting

PUT w4
{
  "mappings": {
    "doc": {
      "properties": {
        "name": {
          "boost": 2.0,
          "type": "text"
        },
        "age": {
          "type": "long"
        }
      }
    }
  }
}

①一劳永逸是没错,但一般不这么推荐

②原因之一是因为一旦映射建立完成,那么所有name字段都会自动拥有一个boost值,要想修改这个值,那就必须重新索引文档

③另一个原因是,boost值是以降低精度的数值存储在Lucene内部的索引结构中,只有一个字节用于存储浮点型数值(存不下就损失精度了),所以,计算文档的最终得分时可能会损失精度

④最后,boost是应用与词条的,因此,再被boost的字段中如果匹配上了多个词条,就意味着计算多次的boost,这将会进一步增加字段的权重,可能会影响最终的文档得分

3、查询期间的boosting

①在es中,几乎所有的查询类型都支持boost,正如那些match、multi_match等等

②示例,在查询期间,使用match查询进行boosting

PUT w5
{
  "mappings":{
    "doc":{
      "properties": {
        "title": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "content": {
          "type": "text",
          "analyzer": "ik_max_word"
        }
      }
    }
  }
}

PUT w5/doc/1
{
  "title":"Lucene is cool",
  "content": "Lucene is cool"
}

PUT w5/doc/2
{
  "title":"Elasticsearch builds on top of lucene",
  "content":"Elasticsearch builds on top of lucene"
}

PUT w5/doc/3
{
  "title":"Elasticsearch rocks",
  "content":"Elasticsearch rocks"
}

GET w5/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title":{
              "query": "elasticserach rocks",
              "boost": 2.5
            }
          }
        },
        {
          "match": {
            "content": "elasticserach rocks"
          }
        }
      ]
    }
  }
}

# 就对于最终得分而言,`content`字段,加了`boost`的`title`查询更有影响力,也只有在`bool`查询中,`boost`更有意义

4、跨越多个字段的查询

boost也可以用于multi_match查询

GET w5/doc/_search
{
  "query": {
    "multi_match": {
      "query": "elasticserach rocks",
      "fields": ["title", "content"],
      "boost": 2.5
    }
  }
}

②除此之外,还可以使用特殊的语法,只为特定的字段指定一个boost,通过在字段名称后添加一个^符号和boost的值,告诉es只需对那个字段进行boost

GET w5/doc/_search
{
  "query": {
    "multi_match": {
      "query": "elasticserach rocks",
      "fields": ["title^3", "content"]
    }
  }
}

# `title`字段被`boost`了3倍
# 在使用`boost`的时候,无论是字段或者词条,都是按照相对值来`boost`的,而不是乘以乘数
# 如果对于所有的待搜索词条`boost`了同样的值,那么就好像没有`boost`一样
# 因为Lucene会标准化`boost`的值,如果`boost`一个字段`4`倍,不是意味着该字段的得分就是乘以`4`的结果
# 所以,如果你的得分不是按照严格的乘法结果,也不要担心


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM