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
转载于:https://www.cnblogs.com/davidwang456/p/6150388.html
Lucene的评分(score)机制研究相关推荐
- Lucene的评分(score)机制的简单解释
Lucene的评分(score)机制的简单解释 博客分类: Lucene lucene编程Apachethread 通过Searcher.explain(Query query, int do ...
- 《深入理解Elasticsearch(原书第2版)》——第2章 查询DSL进阶 2.1 Apache Lucene默认评分公式解释...
本节书摘来自华章计算机<深入理解Elasticsearch(原书第2版)>一书中的第2章,第2.1节,作者 [美]拉斐尔·酷奇(Rafal Ku)马雷克·罗戈任斯基(Marek Rogoz ...
- 肠道菌群机制研究及国自然课题设计专题会议
肠道菌群机制研究及国自然课题设计专题会议 如何设计测序方案.测序后的数据如何应用和延伸 时间:3.13-3.14 线上直播,赠送回放视频,长期答疑群 报名方式请下拉至文末 学习背景介绍 "肠 ...
- linux kernel and user space通信机制,Linux内核与用户空间通信机制研究.pdf
ISSN 1009-3044 E-mail:info@CCCC.net.CR ComputerKnowledgeandTechnology电脑知识与技术 http://www.dnzs.net.cn ...
- 多溴联苯醚内分泌干扰效应机制研究取得进展
中国科学院生态环境研究中心环境化学与生态毒理学国家重点实验室郭良宏研究组在多溴联苯醚 (PBDEs) 内分泌干扰效应的机制研究中取得新进展,相关成果近日发表于国际期刊Environmental Hea ...
- c++容器共性机制研究
容器共性机制研究 容器的共通能力 各个容器的使用时机 容器的共通能力 C++模板是容器的概念. 理论提高:所有容器提供的都是值(value)语意,而非引用(reference)语意.容器执行插入元素的 ...
- Linux内存管理机制研究
Linux内存管理机制研究 查看linux系统中处于free状态的内存有两个角度,一个是从内核的角度来看,一个是从应用层的角度来看的. 1.从内核的角度来看free的内存,就是内核目前可以直接分配到, ...
- [开源]FreeSCADA的通道数据与控件属性关联以及自动刷新机制研究
[开源]FreeSCADA的通道数据与控件属性关联以及自动刷新机制研究 [参考文章]: 1. WPF之Binding深入探讨, 地址:http://www.cnblogs.com/cappuccino ...
- linux26内核,Linux26内核对象机制研究.pdf
Linux26内核对象机制研究.pdf 第二篇 嵌入式操作系统技术 第二篇嵌入式操作系统技术 4l Linux2.6内核对象机制研究 康涌泉 桑楠 邹楚雄 电子科技大学计算机科学与工程学院,成都,61 ...
最新文章
- boost::allocate_unique相关的测试程序
- oracle--导出、导入blob类型的字段
- JPA与Hibernate的关系
- Arduino笔记-人体感应灯项目
- OpenJudge NOI 1.5 08:多边形内角和
- 配置keepalived+LVS_DR
- php安装redis扩展报错,CentOS 67下php5+安装redis扩展组件
- ubuntu快速清理磁盘垃圾
- 寻找安全漏洞?谨慎为之
- 从零基础入门Tensorflow2.0 ----七、34 embedding rnn
- 【工具】telnet用法
- 海康/大华/宇视等网络摄像头云台控制功能探测方法解析
- 处于停机等非正常状态_汽轮机运行最重要的启动与停机阶段,你得了解这些实际经验...
- html+css+js制作原神官网,web前端大作业(流风眷堇庭+6个页面+链接)
- 小米造车follow苹果路线?智能驾驶能力是个关键问题
- Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN
- 1 月 9 日:iPhone 问世
- 快数据如何在物联网高速公路上驱动分析
- 项目管理系统Cynthia
- 2022-2028年中国医药零售行业市场研究及前瞻分析报告
热门文章
- 小而美的个人博客——前端——types and archives
- matlab程序求一个正交的相似变换矩阵,图像的等距变换,相似变换,仿射变换,射影变换及其matlab实现...
- cron表达式 每天0点10分和30分_“提前2小时下班”:学会这10个函数,办公效率提升了10倍!...
- php单表查询语句,单表查询
- docker 安装nacos_「Java Spring Cloud 实战之路」 使用nacos配置网关
- mysql的编译_Mysql编译安装
- 互斥信号量的原理与创建
- 电脑计算机无法找到脚本文件夹,我的电脑开机为什么出现无法找到脚本呢?
- python语言核心技术_python核心技术
- 前端微信签名验证工具_微信jssdk 签名错误排查方法