Lucene的评分(score)机制研究
首先,需要学习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是项在倒排文档中出现的频率,计算方式为
- /** Implemented as <code>log(numDocs/(docFreq+1)) + 1</code>. */
- @Override
- public float idf(long docFreq, long numDocs) {
- return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
- }
docFreq是根据指定关键字进行检索,检索到的Document的数量,我们测试的docFreq=14;numDocs是指索引文件中总共的Document的数量,我们测试的numDocs=1453。用计算器验证一下,没有错误,这里就不啰嗦了。
queryNorm的计算
queryNorm的计算在DefaultSimilarity类中实现,如下所示:
- /** Implemented as <code>1/sqrt(sumOfSquaredWeights)</code>. */
- public float queryNorm(float sumOfSquaredWeights) {
- return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
- }
这里,sumOfSquaredWeights的计算是在org.apache.lucene.search.TermQuery.TermWeight类中的sumOfSquaredWeights方法实现:
- public float sumOfSquaredWeights() {
- queryWeight = idf * getBoost(); // compute query weight
- return queryWeight * queryWeight; // square it
- }
其实默认情况下,sumOfSquaredWeights = idf * idf,因为Lucune中默认的boost = 1.0。
fieldWeight的计算
在org/apache/lucene/search/similarities/TFIDFSimilarity.java的explainScore方法中有:
- // explain field weight
- Explanation fieldExpl = new Explanation();
- fieldExpl.setDescription("fieldWeight in "+doc+
- ", product of:");
- Explanation tfExplanation = new Explanation();
- tfExplanation.setValue(tf(freq.getValue()));
- tfExplanation.setDescription("tf(freq="+freq.getValue()+"), with freq of:");
- tfExplanation.addDetail(freq);
- fieldExpl.addDetail(tfExplanation);
- fieldExpl.addDetail(stats.idf);
- Explanation fieldNormExpl = new Explanation();
- float fieldNorm = norms != null ? decodeNormValue(norms.get(doc)) : 1.0f;
- fieldNormExpl.setValue(fieldNorm);
- fieldNormExpl.setDescription("fieldNorm(doc="+doc+")");
- fieldExpl.addDetail(fieldNormExpl);
- fieldExpl.setValue(tfExplanation.getValue() *
- stats.idf.getValue() *
- fieldNormExpl.getValue());
- result.addDetail(fieldExpl);
重点是这一句:
- fieldExpl.setValue(tfExplanation.getValue() *
- stats.idf.getValue() *
- fieldNormExpl.getValue());
使用计算式表示就是
fieldWeight = tf * idf * fieldNorm
tf和idf的计算参考前面的,fieldNorm的计算在索引的时候确定了,此时直接从索引文件中读取,这个方法并没有给出直接的计算。如果使用DefaultSimilarity的话,它实际上就是lengthNorm,域越长的话Norm越小,在org/apache/lucene/search/similarities/DefaultSimilarity.java里面有关于它的计算:
- public float lengthNorm(FieldInvertState state) {
- final int numTerms;
- if (discountOverlaps)
- numTerms = state.getLength() - state.getNumOverlap();
- else
- numTerms = state.getLength();
- return state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
- }
参考文献:
【1】http://www.hankcs.com/program/java/lucene-scoring-algorithm-explained.html
【2】http://grantbb.iteye.com/blog/181802
Lucene的评分(score)机制研究的更多相关文章
- Lucene Scoring 评分机制
原文出处:http://blog.chenlb.com/2009/08/lucene-scoring-architecture.html Lucene 评分体系/机制(lucene scoring)是 ...
- lucene 的评分机制
lucene 的评分机制 elasticsearch是基于lucene的,所以他的评分机制也是基于lucene的.评分就是我们搜索的短语和索引中每篇文档的相关度打分. 如果没有干预评分算法的时候,每次 ...
- Lucene TFIDFSimilarity评分公式详解
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/zteny/article/details/ ...
- Elasticsearch 评分score计算中的Boost 和 queryNorm
本来没有这篇文章,在公司分享ES的时候遇到一个问题,使用boost的时候,怎么从评分score中知道boost的影响. 虽然我们从查询结果可以直观看到,boost起了应有的作用,但是在explain的 ...
- 基于python的opcode优化和模块按需加载机制研究(学习与个人思路)(原创)
基于python的opcode优化和模块按需加载机制研究(学习与思考) 姓名:XXX 学校信息:XXX 主用编程语言:python3.5 个人技术博客:http://www.cnblogs.com/M ...
- Celeste 机制研究
0. 简介.惯例.总论 Celeste (塞莱斯特) 是一个具有优秀手感的平台跳跃游戏. 虽然操作所使用的按键很少, 但是却有着复杂的组合机制. 在游戏实现上, Celeste 是一个锁定 60 帧 ...
- 防刷票机制研究和.NET HttpRequest Proxy
最近应朋友之约 测试他做的投票网站 防刷票机制能力如何,下面有一些心得和体会. 朋友网站用PHP写的,走的是HttpRequest,他一开始认为IP认证应该就差不多了.但说实话这种很low,手动更换代 ...
- lucene 自定义评分
摘自:http://blog.csdn.net/seven_zhao/article/details/42708953 1.基于FunctionQuery,(1)创建类并继承ValueSource:( ...
- NGK治理机制研究
治理机制是区块链项目的重要设计.随着项目的运行,生态中的参与者需要根据实际运行情况对项目进行必要的更新和升级,以使项目持续良性发展.治理机制的作用是使不同参与者最终达成共识.治理机制直接决定这个网络生 ...
随机推荐
- 【.net 深呼吸】细说CodeDom(1):结构大观
CodeDom 是啥东东?Html Dom听过吧,XML Dom听过吧.DOM一般可翻译为 文档对象模型,那 Code + DOM呢,自然是指代码文档模型了.如果你从来没接触过 CodeDom,你大概 ...
- 关于几个主流语音SDK的接入问题
这两周都在忙着游戏上线还有接入游戏语音,两周分别接了腾讯语音和百度语音!!! 关于腾讯语音的一些问题 由于发现腾讯语音的在录完音频后的数据是编过码的所以出现了一些问题: *不能解码(腾讯方不提供解码算 ...
- 运行执行sql文件脚本的例子
sqlcmd -s -d db_test -r -i G:\test.sql 黑色字体为关键命令,其他颜色(从左至右):服务器名称,用户名,密码,数据库,文件路径 通过select @@servern ...
- 01.LoT.UI 前后台通用框架分解系列之——小图片背景全屏显示(可自动切换背景)
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...
- 谈谈一些有趣的CSS题目(四)-- 从倒影说起,谈谈 CSS 继承 inherit
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- .net 分布式架构之分布式缓存中间件
开源git地址: http://git.oschina.net/chejiangyi/XXF.BaseService.DistributedCache 分布式缓存中间件 方便实现缓存的分布式,集群, ...
- 自定义搭建PHP开发环境
学习了一段时间php了,因为之前是刚接触php,所以用的是集成安装包(wamp).现在想进一步了解apache.mysql.php之间的关系以及提升自己所以进行自定义搭建PHP开发环境.废话不多说,请 ...
- 前端制作动画的几种方式(css3,js)
制作动态的网页是是前端工程师必备的技能,很好的实现动画能够极大的提高用户体验,增强交互效果,那么动画有多少实现方式,一直对此有选择恐惧症的我就总结一下,以便在开发的时候选择最好的实现方式. 1.css ...
- JavaScript中String对象的方法介绍
1.字符方法 1.1 charAt() 方法,返回字符串中指定位置的字符. var question = "Do you like JavaScript?"; alert(ques ...
- 28个你必须知道的HTML5的新特性,技巧以及技术
崭新新的页面布局 传统的: HTML5: 1. 新的Doctype 尽管使用<!DOCTYPE html>,即使浏览器不懂这句话也会按照标准模式去渲染 2. Figure元素 用<f ...