解析Elasticsearch/lucene打分策略

最近业务上遇到重新排序制定打分策略需求,参考这篇文档,对es打分策略有所了解

在进行搜索时,对于召回的排序方式一般是两种方式:不指定sort按照相关度以及其他因素综合得到的分值排序;另外一种是完全按照指定的sort(可以使多个field,和顺序有关),此时分数是0,即没有相关性的概念。指定字段排序比较简单,按照分值排序就涉及到一些打分策略和二次评分的方式。ES采用的是lucene的打分算法(es 5.0之前默认是TF/IDF, 5.0之后 采用的是lucene6 默认是bm2.5)。

    布尔模型(Boolean model

   一个搜索query会根据query的类型进行分词、语法解析拆分,并且按照 类似 and 这种逻辑操作符,得出bool语句,这样可以先过滤出包含指定 term doc。例如:
[java]  view plain  copy
  1. "match": {  
  2.     "title""hello world"  
  3. }  
会分词拆分成 hello / world / hello & world等term,并根据term和逻辑运算符来进行doc的过滤。 这一过程是不含任何打分动作的,只是过滤出对应的文档。主要可以减少后续计算出的文档数。并为后续打分提供依据。

     TF/IDF/lnorm

            经过布尔模型的过滤、重组就会得到一堆的term,同时也会得到term和doc之间的关系。

              TF:一个term在一个doc中出现的次数(出现的次数越多,那么最后给的相关度评分就会越高)

              IDF:一个term在所有的doc中出现的次数(出现的次数越多,那么最后给的相关度评分就会越低)

              length norm:关键词搜索的那个field的长度(field长度越长,给的相关度评分越低; field长度越短,给的相关度评分越高)

    其实lucene的打分过程就是将搜索的关键词的某个term,综合TF,IDF,length norm以及设置的权重对某个文档综合计算出来一个分数。但是往往一个关键词并不是一个term,而是多个term比如hello word会是hell/word/hello word。所以就需要综合计算多个term对一个文档的总分数来作为这个文档对这个关键词的最终得分。

  空间向量模型

        对于多个term是如何决定一个文档的分数的以及一个query搜索是如何等到某个文档得分的,lucene采用的是空间向量模型:
         空间的维:一个维是代表一个term,某个term通过TF/IDF以及字段的长度会计算出一个doc的分数,那么这个分数就是这个文档在这个维的坐标。所以计算出多个term的分值(term1_score;term2_score;term3_score)就相当于确定 了一个文档在多个维的坐标,也就可以画出他的向量。
         文档向量(doc vector):假设这个文档包含3个term。也就是说这个文档在空间中有三个维度含有此文档的坐标刻度。可以得出文档在空间中的一个向量。

        索引向量(query vector):这个query同样被当成一个文档来看待,同样可以在空间中找到某个term维上的坐标,根据坐标可以构成一个空间向量。

       query对doc的得分计算:通过计算doc vector和query vector的夹角的cose值作为最终的分数。弧度越大,分数月底; 弧度越小,分数越高。

    

加上一些文档的权重、field的权重组成一个公式:


   总结打分过程

1、先根据query的语法判断是否对keyword进行分词。

2、得出keyword中包含的term

3、根据term去倒排表中找到多个doc

4、根据query的语法,通过boolean模型得到最终的文档集。

5、根据TF/RDF算法模型计算每个term对文档、query的分值,得出文档、query在某    一维的坐标。

6、根据在维度上的坐标画出文档、query的空间向量。

7、计算文档以及query空间向量的夹角余弦值,在计算的过程中加入boost,得到最终的得分score

 打分公式

假设有三个文档:
               doc1:     hello
                doc2:       hello world
                doc3 :      hello word  java
1、coord(q,d)协调因子。实际上的作用就是拉开term命中的之后的分数差距的。
[java]  view plain  copy
  1. public float coord(int overlap, int maxOverlap) {  
  2.     return overlap / (float)maxOverlap;  
  3.   }  

  overlap:匹配上的term数量。

  maxOverlap:此文档总term数量。

加入不加cooord的时候搜索 hello word java的每个文档的得分是:

        doc1->1.5

        doc2->3

        doc3->4.5

加上之后会是

      doc1->1.5 * 1/3=0.5

      doc2->3*2/3=2.0

       doc3->4.5*3/4=4.5

所以对命中比较好的doc有一些分数上的成倍奖励。

2、queryNorm(q) 

[java]  view plain  copy
  1. @Override  
  2.   public float queryNorm(float sumOfSquaredWeights) {  
  3.     return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));  
  4.   }    
  5. sumOfSquaredWeights = q.getBoost()^2·∑( idf(t)·t.getBoost() )^2   
用来让一个doc 的分数处于一个合理的区间内,不要太离谱。比如所有打分一般都是一点几,零点几。对于一个查询来讲这是个常量不会影响排序。

3、tf(t ind d)

[java]  view plain  copy
  1. @Override  
  2.  public float tf(float freq) {  
  3.    return (float)Math.sqrt(freq);  
  4.  }  
freq:这个term在一个文档中出现的次数也就是TF

4、idf(t)存在的意义是告诉打分公式一个词的稀有程度

[java]  view plain  copy
  1. @Override  
  2.  public float idf(long docFreq, long numDocs) {  
  3.    return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);  
  4.  }  
numDoc:总文档数

docFreq:有几个文档除了这个词

docFreq+1是因为docFreq可能会是0。1.0同理。

5、t.getBoost

  在执行query的时候为每个term设定的权重。term的权重在这起作用。

6、norm(t,d)

  标准化因子,匹配到的field的长度,长度越长分数越低。索引时就确定了,更改的话需要重建索引。

norm(t,d) = doc.getBoost()· lengthNorm· ∏ f.getBoost()  

doc.getBoost():文档的权重5.0之后取消

lengthNorm:

[java]  view plain  copy
  1. @Override  
  2.   public float lengthNorm(FieldInvertState state) {//FieldInvertState 存储和统计当前field的所有term出现的位置position和offset信息  
  3.     final int numTerms;  
  4.     if (discountOverlaps)//同义词相关,如果是同义词会把同义词去掉留一个。  
  5.       numTerms = state.getLength() - state.getNumOverlap();  
  6.     else  
  7.       numTerms = state.getLength();  
  8.     return state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));//看代码state.getBoost()是1.0f  
  9.   }  
f.getBoost() 每个文档field的权值, ∏ f.getBoost()表示连乘。

综上可以看出每个环节分值确定的时机是:

查询时可以确定的是在:1/2/3/4/5

索引时确定的是6。

原文: https://blog.csdn.net/liyantianmin/article/details/72901317
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值