首先,需要学习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. [原]CentOS7.2部署node-mapnik

    转载请注明表作者think8848及出处(http://think8848.cnblogs.com) node-mapnik依赖项中要求g++ >= 5, toolchain (>= GL ...

  2. 干货分享:让你分分钟学会 JS 闭包

    闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...

  3. 使用SwingBench 对Oracle RAC DB性能 压力测试

    我们可以使用swingbench这个工具对数据库性能进行压力测试,得到一些性能指标作为参考. SwingBench下载: http://www.dominicgiles.com/downloads.h ...

  4. EF上下文对象线程内唯一性与优化

    在一次请求中,即一个线程内,若是用到EF数据上下文对象,就创建一个,这也加是很多人的代码中习惯在使用上下文对象时,习惯将对象建立在using中,也是为了尽早释放上下文对象, 但是如果有一个业务逻辑调用 ...

  5. iOS之开发中常用的颜色及其对应的RGB值

      R G B 值   R G B 值   R G B 值 黑色 0 0 0 #000000 黄色 255 255 0 #FFFF00 浅灰蓝色 176 224 230 #B0E0E6 象牙黑 41 ...

  6. Atitit  godaddy 文件权限 root权限设置

    Atitit  godaddy 文件权限 root权限设置 1. ubuntu需要先登录,再su切换到root1 2. sudo 授权许可使用的su,也是受限制的su1 3. ubuntu默认吗roo ...

  7. nginx代理https站点(亲测)

    nginx代理https站点(亲测) 首先,我相信大家已经搞定了nginx正常代理http站点的方法,下面重点介绍代理https站点的配置方法,以及注意事项,因为目前大部分站点有转换https的需要所 ...

  8. AutoIt实现Webdriver自动化测试文件上传

    在运用WebDriver进行自动化测试时,由于WebDriver自身的限制,对于上传文件时Windows弹出的文件选择窗口无法控制,通过在网上查找资料锁定使用AutoIt来控制文件上传窗口. Auto ...

  9. BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 8748  Solved: 3835[Submi ...

  10. spring boot1

    spring boot 玩转spring boot--快速开始   开发环境: IED环境:Eclipse JDK版本:1.8 maven版本:3.3.9 一.创建一个spring boot的mcv ...