• ElasticSearch之score打分机制原理



    Elasticsearch 的得分机制是一个基于词频和逆文档词频的公式,简称为 TF-IDF 公式,所以先来研究下 TF-IDF原理。

    1. TF-IDF原理

    TF-IDF的英文全称是:Term Frequency - Inverse Document Frequency,中文名称词频-逆文档频率。

    常用于文本挖掘,资讯检索等应用,在NLP以及推荐等领域都是一个常用的指标,用于衡量字词的重要性。

    比较直观的解释是,如果一个词本来出现的频率就很高,如the,那么它就几乎无法带给读者一些明确的信息。

    一般地,以TF-IDF衡量字词重要性时

    • 某个字词在某个文档中出现的频率越高,那么该字词对该文档就有越大的重要性,它可能会是文章的关键词(词在单个文档中出现的频率,相对于当个文档!!!)
    • 但若字词在词库中出现的频率越高,那么字词的重要性越低,如the。(相对于整个文档集合,也就是词库)

    1.1 计算公式

    TF-IDF即是两者相乘,词频乘以逆文档频率,如下:
    T F − I D F = T F ∗ I D F TF-IDF=TF*IDF TFIDF=TFIDF
    下标ij的含义:编号为j的文档中的词语i在该文档中的词频,即所占比例,n为该词语的数量。如下:

    换言之,就是词语出现的次数与文档中所有词总数的比值。
    T F i j = n i j n ∗ j TF_{ij} = \frac{n_{ij}}{n_{*j}} TFij=njnij
    N表示文档总数,Ni表示文档集中包含了词语i的文档数。

    对分子分母加一是为了避免某些词语没有在文档中出现过,导致分母为零的情况。

    IDF针对某个词计算了它的逆文档频率,即包含该词语的文档比例的倒数(再取对数),若IDF值越小,分母越大,说明这个词语在文档集中比较常见不具有鲜明的信息代表性,TF-IDF的值就小。

    总之TF-IDF的值,通常希望它越大越好,大值代表性强。如下:
    I D F i = l o g ( N + 1 N i + 1 ) IDF_i=log (\frac{N+1}{N_i+1}) IDFi=logNi+1N+1

    1.2 示例说明

    有两个文档,即doc1doc2,并去它们的并集

    doc1 = "The cat sat on my bed"
    doc2 = "The dog sat on my knees"
    # 构建词库,union是并集操作
    wordSet = set(doc1.split()).union(set(doc2.split()))
    
    • 1
    • 2
    • 3
    • 4

    两个文档的并集如下:

    {‘The’,‘bed’,‘cat’,‘dog’,‘knees’,‘my’,‘on’,‘sat’}

    doc1doc2两个文档对应的词在并集中的统计情况:

    序号catsatmyondogbedTheknees
    011110110
    101111011

    1.2.1 计算TF

    计算词频 TF,对单个文档统计:

    再理解一下,何为TF,表示单个单词占当前文档所有单词集合的比值。即1/6=0.16666666666…

    catsatmyondogbedTheknees
    11110110
    0.166666…0.166666…0.166666…0.166666…00.166666…0.166666…0

    1.2.2 计算IDF

    逆文档频率IDF,全局只有一份逆文档频率,对所有文档统计

    N表示文档总数,Ni`表示文档集中包含了词语i的文档数。

    此时N=2,共有两个文档。Ni表示含有单词的文档个数。

    catsatmyondogbedTheknees
    0.17609125…0.00.00.0…0.17609125…0.17609125…0.00.17609125…

    1.2.3 TF-IDF计算

    最终计算:TF-IDF = TF * IDF

    序号catsatmyondogbedTheknees
    00.0293490000.029349000
    10000.0293490000.029349

    2. Elasticsearch打分机制

    上面介绍了TF-IDF的原理,而ES的得分机制就是基于词频和逆文档词频的公式,即TF-IDF公式。
    s c o r e ( q , d ) = c o o r d ( q , d ) ⋅ q u e r y N o r m ( q ) ⋅ ∑ t i n q ( t f ( t i n d ) ⋅ i d f ( t ) 2 ⋅ t . g e t B o o s t ( ) ⋅ n o r m ( t , d ) ) score(q,d) = coord(q,d)\cdot queryNorm(q)\cdot \sum_{t in q}(tf(t in d)\cdot idf(t){^2}\cdot t.getBoost()\cdot norm(t,d)) score(q,d)=coord(q,d)queryNorm(q)tinq(tf(tind)idf(t)2t.getBoost()norm(t,d))
    公式中将查询作为输入,使用不同的手段来确定每一篇文档的得分,将每一个因素最后通过公式综合起来,返回该文档的最终得分。这个综合考量的过程,在ES中这种相关性称为得分。

    考虑到查询内容和文档的关系比较复杂,所以公式中需要输入的参数和条件非常得多,但是其中比较重要的其实是TF-IDF算法 ,再次解释一下。

    • TF (词频)

    Term Frequency : 搜索文本中的各个词条在查询文本中出现了多少次,次数越多,就越相关,得分会比较高

    • IDF(逆文档频率)

    Inverse Document Frequency : 搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,说明越不重要,也就越不相关,得分就比较低。

    2.1 示例说明

    在查询语句的最后加上explain=true ,会把得分过程打印。

    注:当前ElasticSearchscorpios索引里,只有一个文档。

    # 创建索引
    PUT /scorpios
    # 增加文档数据,此时索引中只有这一条数据
    PUT /scorpios/_doc/1
    {
     "text":"hello"
    }
    
    # 增加分析参数 
    GET /scoripos/_search?explain=true 
    { 
     "query": { 
         "match": { 
             "text": "hello" 
             } 
         } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行后,会发现打分机制中有 2 个重要阶段:计算 TF 值和 IDF
    在这里插入图片描述

    在这里插入图片描述

    最后的分数为:

    在这里插入图片描述

    2.2 计算 TF 值

    f r e q / ( f r e q + k 1 ∗ ( 1 − b + b ∗ d l / a v g d l ) ) freq/(freq + k1 * (1-b+b*dl/avgdl)) freq/(freq+k1(1b+bdl/avgdl))

    参数含义取值
    freq文档中出现词条的次数1.0
    k1术语饱和参数1.2(默认值)
    b长度规格参数(单词长度对于整个文档的影响程度)0.75(默认值)
    dl当前文中分解的字段长度1.0
    avgdl查询文档中分解字段数量/查询文档数量1.0
    TF(词频)1.0/(1+1.2 * (1-0.75+0.75 * 1.0/1.0))0.454545

    2.3 计算 IDF 值

    l o g ( 1 + ( N − n + 0.5 ) / ( n + 0.5 ) ) log(1+(N -n +0.5)/(n + 0.5)) log(1+(Nn+0.5)/(n+0.5))

    参数含义取值
    N包含查询字段的文档总数(不一定包含查询词条)1
    n包含查询词条的文档数1
    IDF(逆文档频率)log(1+(1-1+0.5)/(1+0.5))0.2875821

    注:这里的 log 是底数为e 的对数

    2.4 计算文档得分

    b o o s t ∗ i d f ∗ t f boost * idf * tf boostidftf

    参数含义取值
    boost词条权重2.2(基础值)*查询权重(1)
    idf逆文档频率0.2876821
    tf词频0.454545
    score(得分)2.20.28768210.4545450.2876821

    2.5 增加新的文档测试得分

    • 增加一个毫无关系的文档
    # 增加文档
    PUT /scorpios/_doc/2
    {
     "text" : "spark"
    }
    # 得分:0.6931741
    GET /scorpios/_search
    {
         "query": {
            "match": {
                "text": "hello"
            }
         } 
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    因为新文档无词条相关信息,所以匹配的文档数据得分就应该较高

    • 增加一个一模一样的文档
    # 增加文档
    PUT /scorpios/_doc/2
    {
     "text" : "hello"
    }
    
    # 得分:0.18232156
    GET /scorpios/_search
    {
     	"query": {
     		"match": {
     			"text": "hello"
     		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    因为新文档含词条相关信息,且多个文件含有词条,所以显得不是很重要,得分会变低

    • 增加一个含有词条,但是内容较多的文档
    # 增加文档
    PUT /scorpios/_doc/2 
    {
    	"text" : "hello elasticsearch" 
    }
    # 得分:0.14874382
    GET /scorpios/_search
    {
         "query": {
             "match": {
             	"text": "hello"
             }
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    因为新文档含词条相关信息,但只是其中一部分,所以查询文档的分数会变得更低一些。

    3. 案列

    3.1 需求

    查询文档标题中含有Hadoop,Elasticsearch,Spark的内容,优先选择Spark的内容

    3.2 准备数据

    # 创建索引
    PUT /test
    # 准备数据
    PUT /test/_doc/1001
    {
    	"title" : "Hadoop is a Framework",
    	"content" : "Hadoop 是一个大数据基础框架" 
    }
    PUT /test/_doc/1002
    {
    	"title" : "Hive is a SQL Tools",
    	"content" : "Hive 是一个 SQL 工具" 
    }
    PUT /test/_doc/1003
    {
    	"title" : "Spark is a Framework",
    	"content" : "Spark 是一个分布式计算引擎" 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3.3 查询数据

    # 查询文档标题中含有“Hadoop”,“Elasticsearch”,“Spark”的内容
    GET /test/_search?explain=true
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
                "title": {
                  "query": "Hadoop", "boost": 1
                }
              }
            },
            {
              "match": {
                "title": {
                  "query": "Hive", "boost": 1
                }
              }
            },
            {
              "match": {
                "title": {
                  "query": "Spark", "boost": 1
                }
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    此时会发现,Spark的结果并不会放置在最前面

    在这里插入图片描述

    此时可以更改 Spark 查询的权重参数 boost,看看查询的结果有什么不同

    # 查询文档标题中含有“Hadoop”,“Elasticsearch”,“Spark”的内容
    GET /test/_search?explain=true
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
                "title": {
                  "query": "Hadoop", "boost": 1
                }
              }
            },
            {
              "match": {
                "title": {
                  "query": "Hive", "boost": 1
                }
              }
            },
            {
              "match": {
                "title": {
                  "query": "Spark", "boost": 2
                }
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

  • 相关阅读:
    Kafka概述及使用
    YOLOv10改进 | Conv篇 | RCS-OSA替换C2f实现暴力涨点(减少通道的空间对象注意力机制)
    vs2019使用问题记录
    Mysql查看执行语句
    本地CMD命令将webp格式文件批量转换为图片格式(jpg、png、bmp、gif)
    深度学习系列53:mmdetection上手
    C++ 十进制与十六进制转换
    Python正则表达式
    开题报告:基于java企业公司网站系统 毕业设计论文开题报告模板
    【面试经典150 | 滑动窗口】长度最小的子数组
  • 原文地址:https://blog.csdn.net/zxd1435513775/article/details/126947943