首先,需要学习Lucene的评分计算公式——

分值计算方式为查询语句q中每个项t与文档d的匹配分值之和,当然还有权重的因素。其中每一项的意思如下表所示:

表3.5

评分公式中的因子

评分因子

描 述

tf(t in d)

项频率因子——文档(d)中出现项(t)的频率

idf(t)

项在倒排文档中出现的频率:它被用来衡量项的“唯一”性.出现频率较高的term具有较低的idf,出现较少的term具有较高的idf

boost(t.field in d)

域和文档的加权,在索引期间设置.你可以用该方法 对某个域或文档进行静态单独加权

lengthNorm(t.field in d)

域的归一化(Normalization)值,表示域中包含的项数量.该值在索引期间计算,并保存在索引norm中.对于该因子,更短的域(或更少的语汇单元)能获得更大的加权

coord(q,d)

协调因子(Coordination factor),基于文档中包含查询的项个数.该因子会对包含更多搜索项的文档进行类似AND的加权

queryNorm(q)

每个査询的归一化值,指毎个查询项权重的平方和

通过Searcher.explain(Query query, int doc)方法可以查看某个文档的得分的具体构成。 示例:

public class ScoreSortTest {
public final static String INDEX_STORE_PATH = "index";
public static void main(String[] args) throws Exception {
IndexWriter writer = new IndexWriter(INDEX_STORE_PATH, new StandardAnalyzer(), true);
writer.setUseCompoundFile(false); Document doc1 = new Document();
Document doc2 = new Document();
Document doc3 = new Document(); Field f1 = new Field("bookname","bc bc", Field.Store.YES, Field.Index.TOKENIZED);
Field f2 = new Field("bookname","ab bc", Field.Store.YES, Field.Index.TOKENIZED);
Field f3 = new Field("bookname","ab bc cd", Field.Store.YES, Field.Index.TOKENIZED); doc1.add(f1);
doc2.add(f2);
doc3.add(f3); writer.addDocument(doc1);
writer.addDocument(doc2);
writer.addDocument(doc3); writer.close(); IndexSearcher searcher = new IndexSearcher(INDEX_STORE_PATH);
TermQuery q = new TermQuery(new Term("bookname", "bc"));
q.setBoost(2f);
Hits hits = searcher.search(q);
for(int i=0; i<hits.length();i++){
Document doc = hits.doc(i);
System.out.print(doc.get("bookname") + "\t\t");
System.out.println(hits.score(i));
System.out.println(searcher.explain(q, hits.id(i)));//
}
}
}

运行结果:

bc bc    0.629606
0.629606 = (MATCH) fieldWeight(bookname:bc in 0), product of:
1.4142135 = tf(termFreq(bookname:bc)=2)
0.71231794 = idf(docFreq=3, numDocs=3)
0.625 = fieldNorm(field=bookname, doc=0) ab bc 0.4451987
0.4451987 = (MATCH) fieldWeight(bookname:bc in 1), product of:
1.0 = tf(termFreq(bookname:bc)=1)
0.71231794 = idf(docFreq=3, numDocs=3)
0.625 = fieldNorm(field=bookname, doc=1) ab bc cd 0.35615897
0.35615897 = (MATCH) fieldWeight(bookname:bc in 2), product of:
1.0 = tf(termFreq(bookname:bc)=1)
0.71231794 = idf(docFreq=3, numDocs=3)
0.5 = fieldNorm(field=bookname, doc=2)

涉及到的源码:

idf的计算

idf是项在倒排文档中出现的频率,计算方式为

  1. /** Implemented as <code>log(numDocs/(docFreq+1)) + 1</code>. */
  2. @Override
  3. public float idf(long docFreq, long numDocs) {
  4. return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
  5. }

docFreq是根据指定关键字进行检索,检索到的Document的数量,我们测试的docFreq=14;numDocs是指索引文件中总共的Document的数量,我们测试的numDocs=1453。用计算器验证一下,没有错误,这里就不啰嗦了。

queryNorm的计算

queryNorm的计算在DefaultSimilarity类中实现,如下所示:

  1. /** Implemented as <code>1/sqrt(sumOfSquaredWeights)</code>. */
  2. public float queryNorm(float sumOfSquaredWeights) {
  3. return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
  4. }

这里,sumOfSquaredWeights的计算是在org.apache.lucene.search.TermQuery.TermWeight类中的sumOfSquaredWeights方法实现:

  1. public float sumOfSquaredWeights() {
  2. queryWeight = idf * getBoost();             // compute query weight
  3. return queryWeight * queryWeight;          // square it
  4. }

其实默认情况下,sumOfSquaredWeights = idf * idf,因为Lucune中默认的boost = 1.0。

fieldWeight的计算

在org/apache/lucene/search/similarities/TFIDFSimilarity.java的explainScore方法中有:

  1. // explain field weight
  2. Explanation fieldExpl = new Explanation();
  3. fieldExpl.setDescription("fieldWeight in "+doc+
  4. ", product of:");
  5. Explanation tfExplanation = new Explanation();
  6. tfExplanation.setValue(tf(freq.getValue()));
  7. tfExplanation.setDescription("tf(freq="+freq.getValue()+"), with freq of:");
  8. tfExplanation.addDetail(freq);
  9. fieldExpl.addDetail(tfExplanation);
  10. fieldExpl.addDetail(stats.idf);
  11. Explanation fieldNormExpl = new Explanation();
  12. float fieldNorm = norms != null ? decodeNormValue(norms.get(doc)) : 1.0f;
  13. fieldNormExpl.setValue(fieldNorm);
  14. fieldNormExpl.setDescription("fieldNorm(doc="+doc+")");
  15. fieldExpl.addDetail(fieldNormExpl);
  16. fieldExpl.setValue(tfExplanation.getValue() *
  17. stats.idf.getValue() *
  18. fieldNormExpl.getValue());
  19. result.addDetail(fieldExpl);

重点是这一句:

  1. fieldExpl.setValue(tfExplanation.getValue() *
  2. stats.idf.getValue() *
  3. fieldNormExpl.getValue());

使用计算式表示就是

fieldWeight = tf * idf * fieldNorm

tf和idf的计算参考前面的,fieldNorm的计算在索引的时候确定了,此时直接从索引文件中读取,这个方法并没有给出直接的计算。如果使用DefaultSimilarity的话,它实际上就是lengthNorm,域越长的话Norm越小,在org/apache/lucene/search/similarities/DefaultSimilarity.java里面有关于它的计算:

  1. public float lengthNorm(FieldInvertState state) {
  2. final int numTerms;
  3. if (discountOverlaps)
  4. numTerms = state.getLength() - state.getNumOverlap();
  5. else
  6. numTerms = state.getLength();
  7. return state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
  8. }

参考文献:

【1】http://www.hankcs.com/program/java/lucene-scoring-algorithm-explained.html

【2】http://grantbb.iteye.com/blog/181802

Lucene的评分(score)机制研究的更多相关文章

  1. Lucene Scoring 评分机制

    原文出处:http://blog.chenlb.com/2009/08/lucene-scoring-architecture.html Lucene 评分体系/机制(lucene scoring)是 ...

  2. lucene 的评分机制

    lucene 的评分机制 elasticsearch是基于lucene的,所以他的评分机制也是基于lucene的.评分就是我们搜索的短语和索引中每篇文档的相关度打分. 如果没有干预评分算法的时候,每次 ...

  3. Lucene TFIDFSimilarity评分公式详解

    版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/zteny/article/details/ ...

  4. Elasticsearch 评分score计算中的Boost 和 queryNorm

    本来没有这篇文章,在公司分享ES的时候遇到一个问题,使用boost的时候,怎么从评分score中知道boost的影响. 虽然我们从查询结果可以直观看到,boost起了应有的作用,但是在explain的 ...

  5. 基于python的opcode优化和模块按需加载机制研究(学习与个人思路)(原创)

    基于python的opcode优化和模块按需加载机制研究(学习与思考) 姓名:XXX 学校信息:XXX 主用编程语言:python3.5 个人技术博客:http://www.cnblogs.com/M ...

  6. Celeste 机制研究

    0. 简介.惯例.总论 Celeste (塞莱斯特) 是一个具有优秀手感的平台跳跃游戏. 虽然操作所使用的按键很少, 但是却有着复杂的组合机制. 在游戏实现上, Celeste 是一个锁定 60 帧 ...

  7. 防刷票机制研究和.NET HttpRequest Proxy

    最近应朋友之约 测试他做的投票网站 防刷票机制能力如何,下面有一些心得和体会. 朋友网站用PHP写的,走的是HttpRequest,他一开始认为IP认证应该就差不多了.但说实话这种很low,手动更换代 ...

  8. lucene 自定义评分

    摘自:http://blog.csdn.net/seven_zhao/article/details/42708953 1.基于FunctionQuery,(1)创建类并继承ValueSource:( ...

  9. NGK治理机制研究

    治理机制是区块链项目的重要设计.随着项目的运行,生态中的参与者需要根据实际运行情况对项目进行必要的更新和升级,以使项目持续良性发展.治理机制的作用是使不同参与者最终达成共识.治理机制直接决定这个网络生 ...

随机推荐

  1. 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付

    前言 最近有点空余时间,所以,就研究了一下APP支付.前面很早就搞完APP的微信支付了,但是由于时间上和应用上的情况,支付宝一直没空去研究.然后等我空了的时候,发现支付宝居然升级了支付逻辑,虽然目前还 ...

  2. 【趣事】用 JavaScript 对抗 DDOS 攻击 (下)

    上一篇:http://www.cnblogs.com/index-html/p/js-network-firewall.html 对抗 v2 之前的那些奇技淫巧,纯属娱乐而已,并不能撑多久. 但简单. ...

  3. JavaScript var关键字、变量的状态、异常处理、命名规范等介绍

    本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...

  4. Android之常见问题集锦Ⅱ

    Android问题集锦Ⅰ:http://www.cnblogs.com/AndroidJotting/p/4608025.html EditText输入内容改变事件监听 _edit.addTextCh ...

  5. 协议森林16 小美的桌号(DHCP协议)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. DHCP协议用于动态的配置电脑的网络相关参数,如主机的IP地址,路由器出口地址.DNS域名服务器地 ...

  6. 如何利用tcpdump对mysql进行抓包操作

    命令如下: tcpdump -s -l -w - dst -i eno16777736 |strings 其中-i指定监听的网络接口,在RHEL 7下,网络接口名不再是之前的eth0,而是 eno16 ...

  7. PHP之购物车的代码

    该文章记录了购物车的实现代码,仅供参考 book_sc_fns.php <?php include_once('output_fns.php'); include_once('book_fns. ...

  8. c++ pair 使用

    1. 包含头文件: #include <utility> 2. pair 的操作: pair<T1,T2> p; pair<T1,T2> p(v1,v2); pai ...

  9. Win10提示没有权限使用网络资源问题解决

    借鉴链接:http://www.cr173.com/html/67361_1.html Win10提示没有权限使用网络资源解决方法 1.打开控制面板; 2.在所有控制面板项中找到凭据管理器; 3.添加 ...

  10. 全网独家MongoDB Certified DBA Associate考试认证视频

    该视频意在让所有学员一次通过考试,避免重复考试而承担的巨额考试费用! 目前MongDB发展迅猛,有赶超mysql,和oracle看齐的苗头.在这个时候MongoDB也适时的推出了官方的认证考试&quo ...