Lucene4.3进阶开发之礼敬如来(十三)

2019-03-27 01:22|来源: 网路

评分功能,在全文检索中也算是一个非常重要的模块,因为评分的好坏,直接决定着用户搜索匹配的相关性,试想一下假如用户输入了一个搜索词,搜索引擎返回了一大堆不相关的信息,或者没有层次性,重点性的结果,那么看起来将是一件多么糟糕的事情。 

lucene默认的评分机制,用的VSM(Vector  Space Model)空间向量模型,基于TF-IDF的评选方式,TF-IDF(term frequency–inverse document frequency)是一种用于资讯检索与资讯探勘的常用加权技术。用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。除了TF-IDF以外,因特网上的搜索引擎还会使用基于链接分析的评级方法,以确定文件在搜寻结果中出现的顺序。 

TF-IDF模型,作为一种加权策略,在信息检索,搜索引擎,数据挖掘方面被广泛应用,这种模型在lucene中也得到了很好的实现。 

我们先来看下,一般常用的方法加权,在索引时给某个 

Field加权 

 Field field= new Field("title", "过程", type);
 field.setBoost(10.0f);

这种方式在lucene4.x之前可以给文档和域分别进行加权,但是在4.x之后,只能给域加权,废弃了文档加权的方式,如果想给文档加权,就需要对每个域分别加权,来提升这个文档的权重。 

对比索引时的加权,我们在检索时也可以设置加权boost,代码示例如下: 

Query q=parser.parse(term);
q.setBoost(8f);//检索时加权

或者也可以用,queryparse的解析表达式表示: 

Query q=parser.parse("lucene^10 solr^5");

除了,上面的几种方式外,我们还可以自定义评分在源码级别改变一些打分策略: 

1,coord(int overlap, int maxOverlap),协调因子,这个因素起什么作用呢, 

举个例子现在我索引里面有2条数据: 

(1)中国一个多民族国家 

(2)中国是世界人口大国 

当我们检索“中国”的时候,会发现这两个文档的评分一样,因为他们的长度也相等, 

而当我们检索“中国   民族”的时候会发现第一个文档会排在前面而且得分要高,为什么呢? 

overlap的个数,代表我们在文档中命中的个数 

maxOverlap的个数,代表着检索条件里面的个数==>“中国   民族”2个 

由此我们假设其他的条件一样的情况下可以推算出1的得分=2/2=1 

而第二个的评分是=1/2=0.5 

所以文档1的评分会更好,因为它命中了更多的term。 

在源码里方法如下: 

 public float coord(int overlap, int maxOverlap) {
    return overlap / (float)maxOverlap;
  }

2,影响评分的第二个因素queryNorm,这个因素,影响评分,但不影响排序的结果,举个例子,如果我们想要把lucene的所有的记录得分的结果,给整体变大,或变小一些,那么我们就可以调整个参数,来控制整体的得分比率。 

在lucene的源码里表示如下方法: 

 public float queryNorm(float sumOfSquaredWeights) {
    return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
  }

3,影响评分的第三个因素,TF,这个因素代表着一个term在某一篇文档中,如果它出现的频次越大,那么对应的评分就越高,我们假设,其他的评分因子都一样,有如下2篇文档: 

(1)中国人的一天是怎么度过的呀? 

(2)我们是中国人,他们也是中国人 

我们检索“中国人”,会发现文档2的得分会比文档1的高,因为中国人的这个term,在文档2中出现了2次,在文档1中,只出现了一次。由此计算评分得: 

假设基数都一样是10,那么文档1的得分=10*1=10 

而文档二的得分则是=10*2=20,假设其他因子都一样,那么此时 

文档2的总体评分就会高于文档1,在显示结果时,会优先排在命中结果集的上方。 

lucene源码里的方法如下: 

 public float tf(float freq) {
    return (float)Math.sqrt(freq);
  }

4,影响评分的第四个因素IDF,这个参数代表的含义是,在所有的文档中,如果某个term频繁出现,那么这个term就被认为是普遍词,所以它的得分就要被减免。 

举例如下3个文档: 

(1)狗是一种聪明的动物。 

(2)猫和狗你更喜欢那个。 

(3)狗的种类也有许多种。 

现在我们检索“狗  猫”,结果呢,我们会发现文档2排在结果集的首位,为什么呢? 

这其实就是IDF的思想,因为狗这个term在所有的文档中出现的次数大于猫,所以在IDF进行评分时,会降低其的评分。 

在lucene源码里,idf的方法如下: 

注意加1的二个作用第一个是为了避免除数的为0的情况,第二个是为了这个文档在整个文档中不存在的时候,避免其的评分为0的情况存在。 

 public float idf(long docFreq, long numDocs) {
    return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
  }

5,影响评分的第五个因素lengthNorm,这个因素是基于文档内容的长度计算的。举例如下: 

有2个文档: 

(1)中国 

(2)中国人 

这个时候我们在检索“中国”的时候,文档1就会排在文档2的前面,为什么会这样呢,明明中国一词在他们中间都出现了一次,造成这样情况出现,恰恰是由于lucene在计算评分,会将文档的长度计算在里面,因为根据常识,较短文本里,出现命中的词,说明这个词更加重要。 

lucene源码里的代码如下: 

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)));
  }

6,lucene里影响评分的第六个因素,载荷Payload,这个功能是一个高级的功能,可以存储时,存储额外的信息,从而在检索时,达到从某种类型的数据动态加权。 

举个例子,我们可能希望某个XML里面被如果含有<keyword></keywrod>标记的词从而拥有更高的加权,这时候我们就可以利用载荷实现了,在索引的时候,我们判断term里的标签标记,如果出现了这个特定标签的标记的term,我们就额外存储它的加权载荷信息,从而再检索时,来达到一个良好的检索结果。这时候使用载荷,是一个再好不过的选择了。 

lucene的源码里对载荷的方法描述如下: 

  public float scorePayload(int doc, int start, int end, BytesRef payload) {
    return 1;
  }

除了散仙,上文介绍的6种因素外,加上散仙在文章开始部位介绍的boost放权,目前已经介绍了7种影响打分的因素,当然到这里,并不意味着,这些就是全部的影响评分的方法了,事实上除了这些,还有一些其他的自定义评分的方式,这个散仙会在后续的文章里介绍,大部分的时候,我们了解,利用这些信息,就能解决狠多业务上的需求了,所以我们可以在我们需要的任何时候,都可以继承DefaultSimilarity类,来重写和我们业务相关的最好的打分策略。 



转自:http://my.oschina.net/heroShane/blog/201968

相关问答

更多
  • Java程序员 高级特性 反射、泛型、注释符、自动装箱和拆箱、枚举类、可变 参数、可变返回类型、增强循环、静态导入 核心编程 IO、多线程、实体类、 集合类、正则表达式、 XML和属性文件 图形编程 AWT(Java2D/JavaSound/JMF)、Swing、SWT、JFace 网路编程 Applet、Socket/TCP/UDP、NIO、RMI、CORBA Java语法基础 类、抽象类、接口、最终类、静态类、匿名类、内部类、异常类、编码规范 Java开发环境 JDK、JVM、Eclipse、Linux ...
  • java貌似只能开发手机游戏啊,建议向J2EE发展,J2EE现在还是比较主流的
  • MYSQL现在都支持中文的全文检索为什么不用??match against 对一般的网站来说 速度也不是很慢。。或者你直接上JAVA的lucene
  • lucene怎么用[2022-07-03]

    Lucene是一个全文检索系统框架,开源的。 用起来比较方便,去Lucene的官网上下一个包并导入到你的工程中就可以调用包里面的类了。 一般的书里面介绍的版本都是1.4.3或者稍微高级一点的,不过现在lucene3.0正式发布,一些函数调用方法已经改变了,你可以下载一个版本低一点的Lucene比较适合学习~ 当然你直接从3.0入手的话网上资料也是非常丰富的~
  • 想学好Lucene技术的话,我推荐你学习tom5老师的《深入浅出Lucene4.X实战开发大型企业文档中心管理系统》,整套教程一共31课时,教程系统的讲解了lucene4的新特性与原理,先原理,再示例,再结合项目实战,真正做到由浅入深,使用的技术相对前沿,高端,国内关于lucene视频课程像如此全面,深入,高端,实战的几乎没有。以下是教程大纲,需要的话我给传给你: 一、概述:什么是Lucene 二、Lucene系统架构 三、 Lucene索引里有什么 四、Lucene索引深入 五、 Lucene索引深入优化 ...
  • Document doc = new Document(); doc.add(new LongField(FN_ID, obj.id(), Field.Store.YES)); doc.add(new StoredField(FN_CLASSNAME, obj.getClass().getName())); 4.0以后创建Document是这样创建的,好处是分类型了,而不是所有的都是String类型。具体可以参见api
  • 更应该去阅读源码,通过Android Studio跟一下继承关系,比看书来得快。 Android方面进阶的书籍很少,如果要推荐只推荐两本: 《Android开发艺术探索》 《APP研发录》 《Android高级进阶》 《深入理解Android内核设计思想》 这几本书非常值得一读。
  • 6个月前的正式答案似乎是“不”: 我们正在努力开发一个外部API,但会提醒您不要进行自定义更改,因为事情仍然会变得非常快,并且即使在修补程序版本中,内部API可能也会发生更改。 另外 ,“现在没有公共插件API”(8/2015) The official answer from 6+ months ago seems to be "don't": We're working to develop an external API but would caution you away from making c ...
  • 不太确定为什么你有IllegalStateException ,但有一些可能的可能性。 通常,您的分析器将在标记生成器之上构建过滤器。 你这样做,然后创建另一个标记化器并将其传回,因此传回的过滤器与标记生成器没有直接关系。 此外,你构建的过滤器在它被传回时已经到了最后,所以你可能会尝试reset它,我想。 但主要问题是createComponents实际上并不是实现解析逻辑的好地方。 这是你设置Tokenizer和过滤器堆栈的地方。 在Filter中实现自定义过滤逻辑更有意义,扩展TokenStream ( ...
  • 错误信息很清楚你的选择是什么...... 我建议你升级到Xcode 4.2和iOS 5 SDK。 这仍然允许您为iOS 4.x编写应用程序,但是您可以获得更好的Xcode版本和更好的编译器(LLVM 3.0)以及在iOS 5设备上开发的能力。 The error message is pretty clear about what your options are... I suggest you upgrade to Xcode 4.2 and the iOS 5 SDK. That still allo ...