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治理机制研究
治理机制是区块链项目的重要设计.随着项目的运行,生态中的参与者需要根据实际运行情况对项目进行必要的更新和升级,以使项目持续良性发展.治理机制的作用是使不同参与者最终达成共识.治理机制直接决定这个网络生 ...
随机推荐
- mobx @computed的解读
写在前面:我一开始看不懂官网的@computed的作用,因为即使我把@computed去掉,依然能正确的report,然后我百度谷歌都找不到答案,下面都是我自己的理解,如果是有问题的,不对的,请务必留 ...
- div实现自适应高度的textarea,实现angular双向绑定
相信不少同学模拟过腾讯的QQ做一个聊天应用,至少我是其中一个. 过程中我遇到的一个问题就是QQ输入框,自适应高度,最高高度为3row. 如果你也像我一样打算使用textarea,那么很抱歉,你一开始就 ...
- iOS开发之Masonry框架源码深度解析
Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...
- iOS开发之多种Cell高度自适应实现方案的UI流畅度分析
本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...
- [内核笔记1]内核文件结构与缓存——inode和对应描述
由来:公司内部外网记录日志的方式现在都是通过Nginx模块收到数据发送到系统消息队列,然后由另外一个进程来从消息队列读取然后写回磁盘这样的操作,尽量的减少Nginx的阻塞. 但是由于System/V消 ...
- Java类访问权限修饰符
一.概要 通过了解Java4种修饰符访问权限,能够进一步完善程序类,合理规划权限的范围,这样才能减少漏洞.提高安全性.具备表达力便于使用. 二.权限表 修饰符 同一个类 同一个包 不同包的子类 不同包 ...
- iOS从零开始学习直播之3.美颜
任何一款直播软件都必须进行美颜,不然哪来的那么多美女,所以技术改变世界,不只是说说而已.美颜在采集的时候就得就行,让主播实时看到直播的效果. 1.美颜原理 其实美颜的本质就是美白和磨皮,分别通 ...
- DevExpress第三方控件使用实例之ASPxPopupControl弹出子窗体
弹出页面控件:ASPxPopupControl, <dxpc:ASPxPopupControl ID="popubCtr" runat="server" ...
- Hadoop的安装与设置(1)
在Ubuntu下安装与设置Hadoop的主要过程. 1. 创建Hadoop用户 创建一个用户,用户名为hadoop,在home下创建该用户的主目录,就不详细介绍了. 2. 安装Java环境 下载Lin ...
- Spring mvc @initBinder 类型转化器的使用
一.单日期格式 因为是用注解完完成的后台访问,所以必须在大配置中配置包扫描器: 1.applicactionContext.xml <?xml version="1.0" e ...