热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

lucene的默认评分算法向量空间模型(VectorSpaceModel)

在lucene4以前,一直都是使用经典的向量空间模型作为其检索模型,这种方式虽然统一了评分算法,简化了计算,但是带来的问题是

在lucene4以前,一直都是使用经典的向量空间模型作为其检索模型,这种方式虽然统一了评分算法,简化了计算,但是带来的问题是很难去调整,一旦向量空间模型不适合,也很难去替换一种更好的算法。

  而lucene4则将检索模型与事实上的搜索做了解耦和抽象,并且加入了另外几种检索模型的实现,其中就有经典的BM25。

  经典的向量空间模型的理论基础及其在lucene中的应用

  向量空间模型是信息检索领域中一种成熟和基础的检索模型。这种方法以3维空间中的向量作为类比,维度就是做好索引的term,比如这里以3个主要的关键词奥巴马,叙利亚和战争为三个维度,通过文档在各个维度上的权重,每个文档以及查询都会在空间中有一个向量,直观的看起来,两个向量越相似,则他们的夹角越小,所以,用起反比的cos,则可以得到,cos值越大,则两个向量越相似。同理便可以将3维空间推广到多维空间去。  

  用向量空间模型,便将相关性转化为相似性,根据点积和模的定义,可以得到下式:

  

  现在的问题就变成,如何求得每个维度上的term在文档中的权重,在向量空间模型中,特征权重的计算框架是TF*IDF框架,这里TF就是term在文档中的词频,TF值越大,说明该篇文档相对于这个term来说更加重要,因此,权重应该更高;而IDF则是term在整个文档集中占的比重,即n/N,其中n是含该term的文档数,N是总文档数,但是,实际使用中往往习惯用

  

  即所包含的该term的文档数越少说明该term越重要。可以举个例子,有100篇文档,其中80篇都在说红楼梦,其中只有几篇讲到计算机,当你在这个文档集中搜索到计算机时,可以肯定这几篇讲计算机的比较重要,而搜索红楼梦时,则很难区分哪篇更加重要,换句话说,在这个文档集合中,计算机比红楼梦更有区分度,相对来说,计算机比红楼梦更有信息量,所以IDF就是评判所含信息量大小的一个值。

  一般情况,使用TF*IDF作为这里的权重w,从而计算出dj,q的相似度sim(dj,q)。

  那么,在lucene中,是如何应用这个模型的呢?根据向量空间模型的的数学推导(见参考文档3),可以看到,在lucene中实际上是将sim(dj,q)变形和调整后应用了如下一个打分公式

  

  该公式各项参数解释如下,在DefaultSimilarity中都有每一项参数的基本定义:

  coord(q,d): 协调因子,它的计算是基于文档d中所包含的所有可供查询的词条数量

  queryNorm: 在给出每个查询条目的方差和后,计算某查询的标准化值,即(关于valueForNormalization,见后面分析第a步)


  tf: 单词t在文档d中出现的词频,对词频开根号是希望对一篇出现太多相同关键词的文章进行相应的惩罚,即

  idf: 单词t在文档集中的比重。注意这个公式,首先为什么要加1,假设不加1,设想极端情况后面的log为0时(numDocs/docFreq+1 = 1), 带入打分公式,则该文档打分为0,也就是说该关键词分布得广反而一点分都没有了,事实上我们在这里只需要稍作惩罚,加1之后保证任何情况下这里都是有值的。其次,docFreq后为什么要加1呢,当然是为了防止docFreq为0作为除数的情况。所以原始的公式其实是idf(t) = log(numDocs/docFreq),与上面的分析一致


  t.getBoost(): 在搜索过程中影响评分的参数

  norm(t,d): 字段的标准化值,表明在字段中存储了多少词条,这个数值是在索引过程中计算出来的,并且也存储在索引中,可以在TFIDFSimScorer中的norms找到,其中一个参数LengthNorm是在DefaultSimilarity中定义的,另一个参数则是每次索引过程中每次处理一个field时累乘上去的。


    在3.0以前还有另一个参数用来提升Document的加权,可以在Document中找到setBoost,但是4.0以后取缔了,如需要模拟文档的加权,在IndexableField中建议应当自行加权多个Field。


  lucene中如何组织这个公式?

  在TFIDFSimScorer中,可以找到

[java] view plaincopy
print?
  1. public float score(int doc, float freq) {  
  2.   final float raw = tf(freq) * weightValue; // compute tf(f)*weight  
  3.     
  4.   return norms == null ? raw : raw * decodeNormValue(norms.get(doc));  // normalize for field  
  5. }  


  注意到weightValue其实是stats.value,即IDFStats中的value,该value的计算其实是IndexSearcher中createNormalizedWeight产生的,如下
[java] view plaincopy
print?
  1. float v = weight.getValueForNormalization();            a)  
  2. float norm = getSimilarity().queryNorm(v);              b)  
  3. weight.normalize(norm, 1.0f);                           c)  


  其中,a)的计算其实就是

  b)的计算就是


  通过这两步计算得出打分公式中的queryNorm。

  c)步的计算可以得到,可以看出来,这是打分公式的一部分


  从score()中可以看出来,score的结果其实是,其实已经基本是打分公式了。

  到这里,已经基本上解释了打分公式在代码中的组织。接下来,我们最关心的就是。


  打分公式能够如何去影响我们的文档打分和排序

  下面是彩色的打分公式,接下来打分公式如何去影响文档的打分和排序时的文字色彩就对应了该彩色打分公式的色彩:


  1. 搜索时加权,即上式中t.getBoost(),在搜索时加权,即在搜索关键字后带^和权值


  2. 索引时加权,即上式中的norm(t, d)部分中的所有field的boost之积

  如下例,将文档1的加权设置为2之后,同样的搜索条件,文档1的评分增加了


  在索引过程中可以通过下面的语句设置字段加权,这也是影响评分最常见的方式

[java] view plaincopy
print?
  1. Field.setBoost(boost)  

  3. 继承TFIDFSimilarity或DefaultSimilarity,对整个公式的控制。

   coord:当你键入搜索关键词“奥巴马 叙利亚”的时候,你一定希望同时出现两个词的文档排在只出现"奥巴马"的文档之前,某种程度上讲,同时出现两个词意味着更加精确。请看例子,第1篇文档只命中一个词,而第二篇文档同时命中2个词,因而得分较高(此处还有tf的因素,即lucene出现了两次,但是在这里影响不大)


   coord的计算是在DefaultSimilarity中定义的,因而可以修改它,maxOverlap其实就是搜索的总词数,而overlap则是该文档中实际出现了多少搜索词数

[java] view plaincopy
print?
  1. public float coord(int overlap, int maxOverlap) {  
  2.   return overlap / (float)maxOverlap;  
  3. }  

    queryNorm:queryNorm并不能影响不同文档的得分顺序,但是可以影响整体的评分大小,比如,可以修改实现,让其变为1/sumOfSquaredWeights以便减小所有文档的得分或者增大文档得分。

[java] view plaincopy
print?
  1. public float queryNorm(float sumOfSquaredWeights) {  
  2.   return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));  
  3. }  

    tf:tf的在DefaultSimilarity中的定义不能影响文档得分排序,但是它的参数freq,即词频是会影响得分的,可以看以下例子


  我们会发现它的得分提升并不是线性的,跟下式吻合

[java] view plaincopy
print?
  1. public float tf(float freq) {  
  2.   return (float)Math.sqrt(freq);  
  3. }  

   idf:idf主要跟单词在文档中的个数有关系,如下,同样搜索关键词“过程 算法”,第一个例子中由于第2篇文档长度较长,因而得分较低;但是如果加入一篇新的文档,由于第1,3篇文档都含有关键字"过程",因而增加了文档频率docFreq,故根据程序,评分会下降,而只含有"算法"的文档2评分就相对高了


[java] view plaincopy
print?
  1. public float idf(long docFreq, long numDocs) {  
  2.   return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);  
  3. }  

   lengthNorm同等的搜索条件下,文档长度较长者得分较低

   请看如下文档长度对得分和顺序影响的例子,从中可以看出来,对“索引 算法”这组关键词,文档1中有前者,文档2中有后者 ,同样搜索这组关键词,当文档2长度较长时得分较低,而当文档2长度较短时得分较高

  

   在DefaultSimilarity中程序如下

[java] view plaincopy
print?
  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. }  


推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何在不使用SearchBar display controller的情况下,单独使用SearchBar并捕获其textChange事件。作者介绍了实际状况,即左侧SliderMenu中的SearchBar需要在主页TableView中显示搜索结果。然后,作者提供了解决方案和步骤,帮助读者实现这一功能。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
author-avatar
王海937_264
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有