文章转自:http://blog.csdn.net/duck_genuine/article/details/6257540

首先说一下lucene对文档的评分规则:

score(q,d)   =   coord(q,d) ·  queryNorm(q) · ( tf(t in d) ·  idf(t)2 ·  t.getBoost() ·  norm(t,d) )

具体可以查看相关文章:http://blog.chenlb.com/2009/08/lucene-scoring-architecture.html

这里先考虑三个因素coord(q,d)与tf(t in d),当查询串中,命中的词越多,coord计算的值则越大,某个词在文档中出现的次数越多则tf的值越大。还有就是norm(t,d),这个主要是文档boost与字段boost的影响。值越大,对整体评分的影响越重。

首先说tf对搜索结果的影响:

这里是在于本站使用的搜索评分开始是默认的评分器的情况下,但发现有些不足之处。因为站内搜索主要是视频的标题与标签。对于一个视频文档来说,标题或者与标签重复的词本身就是无意义的,比如标题为"美女美女美女美女",标签为“美女”,如果让tf 的作用变大,明显示会使得它的评分更大,而其实并不是视频网站想要的效果。因为我们更想让它更加发散,这样,用户的点击率才会高。所以我们应该让所有命中词的文档的tf 不受频率的影响,使其tf=1.0f;如下自定义的评分器

  1. /**
  2. * @author yuzhy
  3. * 实现自已的评分器
  4. * 文档中重复多少个词不影响分数
  5. *
  6. */
  7. public class MySolrSimilarity extends DefaultSimilarity {
  8. @Override
  9. public float tf(float freq) {
  10. return 1.0f;
  11. }
  12. @Override
  13. public float tf(int freq) {
  14. return 1.0f;
  15. }
  16. }

别小看这段代码 ,因为使用这种评分,对于一个文档来说,一个term在文档出现的频率并不影响,即是不用担心作弊的情况,因为在这方面上他们的分数都是一样的。之前还考虑了对标题与标签的重复字符串的处理,采用后缀树结构来处理公共子串,后来发现这种方法来得更简洁。

因为使用的是solr来作搜索服务来架构,所以首先修改solr默认的Similarity类。在solr 的配置文件schemal.xml,最后中修改或增加:

<similarity class="com.wole.solr.search.MySimilarity"/>

设置为自定义的评分器,重启solr服务后,自定义的评分器就生效了。搜索" 美女"后,不再出现“美女美女美女美女”文档靠前排的效果了。

接着说一下coord的影响:

搜索“htc Incredible S” 三个词,由于没有这完全命中,则使用了宽松规则,即命中一个词也返回进行排序,之前的评分,前几条的结果为:

  1. <doc>
  2. <str name="Subject">S.H.E爱而为一的魔力 幕后全纪录</str>
  3. <str name="tag">she selina hebe ella 爱而为一</str>
  4. <int name="public_time">1103150000</int>
  5. <int name="times">370</int>
  6. <int name="hd">1</int>
  7. </doc>
  8. <doc>
  9. <str name="Subject">1000种死法-S04-01.1024X576.x264</str>
  10. <str name="tag">1000种死法    </str>
  11. <int name="public_time">1103140000</int>
  12. <int name="times">692</int>
  13. <int name="hd">1</int>
  14. </doc>
  15. <doc>
  16. <str name="Subject">p-s-1</str>
  17. <str name="tag">    </str>
  18. <int name="public_time">1103150000</int>
  19. <int name="times">58</int>
  20. <int name="hd">1</int>
  21. </doc>

可以看到,命中的词S 的文档给排到较前,本应该让命中越来的词的文档分数更高,但因为这三个文档在其它方面影响到评分,使得它的最后分数高于命中多个词的文档,而排到最前,所以这样的搜索体验不够好,好的体验应该是让命中的词越多排得越高,所以我首先降低计算norm(t,d)的值。测试调了其权重值,让coord占更大的比例值,效果马上出来更好的,其前三条记录为:

  1. <doc>
  2. <str name="Subject">不可思议htc Incredible 对比 apple iphone4</str>
  3. <str name="tag">Incredible htc apple iphone4 苹果</str>
  4. <int name="public_time">1009250000</int>
  5. <int name="times">29758</int>
  6. <int name="hd">0</int>
  7. </doc>
  8. <doc>
  9. <str name="Subject">不可思议 htc Incredible 比拼 苹果 iphone 3gs</str>
  10. <str name="tag">不可思议 Incredible htc 苹果 apple</str>
  11. <int name="public_time">1009250000</int>
  12. <int name="times">20231</int>
  13. <int name="hd">0</int>
  14. </doc>
  15. <doc>
  16. <str name="Subject">HTC incredible拆解全过程</str>
  17. <str name="tag">手机 HTC incredible DROID系列 </str>
  18. <int name="public_time">1005030000</int>
  19. <int name="times">3649</int>
  20. <int name="hd">0</int>
  21. </doc>

这里命中两个词htc Incredible的文档给排到最前面来,显然这才更符合用户需要的。即使没有完全命中,它的相关性会更逼近。

最后讲一下norm(t,d):

没有norms 意味着
索引阶段禁用了文档boost 和域的boost 及长度标准化。好处在于节省内存,不用在搜索阶
段为索引中的每篇文档的每个域都占用一个字节来保存norms 信息了。但是对norms 信息
的禁用是必须全部域都禁用的,一旦有一个域不禁用,则其他禁用的域也会存放默认的
norms 值。因为为了加快norms 的搜索速度,Lucene 是根据文档号乘以每篇文档的norms
信息所占用的大小来计算偏移量的,中间少一篇文档,偏移量将无法计算。也即norms 信
息要么都保存,要么都不保存。

norm(t,d) 压缩几个索引期间的加权和长度因子:

  • Document boost - 文档加权,在索引之前使用 doc.setBoost()
  • Field boost - 字段加权,也在索引之前调用 field.setBoost()
  • lengthNorm(field) - 由字段内的 Token 的个数来计算此值,字段越短,评分越高,在做索引的时候由 Similarity.lengthNorm 计算。

以上所有因子相乘得出 norm 值,如果文档中有相同的字段,它们的加权也会相乘:

norm(t,d)   =   doc.getBoost() ·  lengthNorm(field) · f.getBoost()
  field f in d named as t  

搜索组件为dismax,其中文档bf的计算是由三个字段

public_time (视频发布时间)^15,times(视频播放数)^15,hd(视频高清)^4

字段的bf值为

qf=Subject^1+tag^0.3

如果想让coord的值靠前,计算文档 boost 与字段boost  的值应该降低一个级别。

改为:

public_time (视频发布时间)^1.5,times(视频播放数)^1.5,hd(视频高清)^0.4

这样 norm计算的值就远远小于 coord ,使命中越多词分数越高的效果

norm(t,d)   =   doc.getBoost() ·  lengthNorm(field) · f.getBoost()
  field f in d named as t

自定义评分器Similarity,提高搜索体验(转)的更多相关文章

  1. lucene正向索引(续)——域(Field)的元数据信息在.fnm里,在倒排表里,利用跳跃表,有利于大大提高搜索速度。

    4.1.2. 域(Field)的元数据信息(.fnm) 一个段(Segment)包含多个域,每个域都有一些元数据信息,保存在.fnm文件中,.fnm文件的格式如下: FNMVersion 是fnm文件 ...

  2. Solutions:如何运用Elastic App Search快速建立出色的React搜索体验

    建立搜索体验是一项艰苦的工作. 乍一看似乎很容易:建立一个搜索栏,将数据放入数据库,然后让用户输入对该数据库的查询. 但是,在数据建模,底层逻辑以及(当然)总体设计和用户体验方面,有很多事情要考虑. ...

  3. HTML5+CSS3+JQuery打造自定义视频播放器

    来源:http://www.html5china.com/HTML5features/video/201109206_1994.html 简介HTML5的<video>标签已经被目前大多数 ...

  4. Struts2透过自定义拦截器实现登录之后跳转到原页面

    Struts2通过自定义拦截器实现登录之后跳转到原页面 这个功能对用户体验来说是非常重要的.实现起来其实很简单. 拦截器的代码如下: package go.derek.advice; import g ...

  5. lucene全文搜索之四:创建索引搜索器、6种文档搜索器实现以及搜索结果分析(结合IKAnalyzer分词器的搜索器)基于lucene5.5.3

    前言: 前面几章已经很详细的讲解了如何创建索引器对索引进行增删查(没有更新操作).如何管理索引目录以及如何使用分词器,上一章讲解了如何生成索引字段和创建索引文档,并把创建的索引文档保存到索引目录,到这 ...

  6. Iterator、for..of,for...in和自定义遍历器**

    Iterator.for..of,for...in和自定义遍历器 Iterator: var arr = [1,2,3,4,5]; var ite = arr[Symbol.iterator](); ...

  7. struts2--实现自定义拦截器

    前言: 本篇文章,我想说清实现拦截器的办法,还有为什么要这样做: 目录: 1.需求目的 2.实现步骤及原理(文字怕描述不清,画图描述) 3.代码 4.总结 一.需求目的 规范或限制越级访问(例如:一个 ...

  8. Java内存管理-掌握自定义类加载器的实现(七)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇分析了ClassLoader的类加载相关的核心源码,也简单介绍了ClassLoa ...

  9. cena评测系统:自定义校验器(自定义评测插件编写)

    Cena评测系统,最受欢迎的信息学竞赛离线评测系统. 它是开放源程序的信息学竞赛评测系统,能满足大多数程序设计竞赛的测评需求. 特色功能: 通过局域网自动收取选手程序. 高效率的数据文件配置工具. 自 ...

随机推荐

  1. vsftp "上传 553 Could not create file"

    我在LINUX下VSftp建立一个FTP服务器,但从WINDOWS使用FTP时,无法上传也无法下载!出错如下 ftp>; ls 200 PORT command successful. Cons ...

  2. 网站开发中很实用的 HTML5 & jQuery 插件

    这篇文章挑选了15款在网站开发中很实用的 HTML5 & jQuery 插件,如果你正在寻找能优化网站,使其更具创造力和视觉冲击,那么本文正是你需要的.这些优秀的 jQuery 插件能为你的网 ...

  3. BeeFree - 在线轻松创建电子邮件消息

    Beefree 可以很容易地创建一个电子邮件消息,可以被用来发送企业简讯,宣布一个新产品,促进销售等.可以免费使用,您甚至不需要创建任何类型的帐户.您可以使用 Beefree 创建创新的,易于使用的电 ...

  4. 【初探Underscore】再说模版引擎

    前言 Underscore 是一个JavaScript实用库,提供了类似Prototype.js (或 Ruby)的一些功能,但是没有扩展任何JavaScript内置对象. 它弥补了部分jQuery没 ...

  5. 送给我的朋友——Cry on my shoulder

    If the hero never comes to you如果你的真命天子仍未来到 If you need someone you"re feeling blue如果你情绪低落需要有人陪伴 ...

  6. Telerik JustDecompile 2014.1.255.0 开发版(.NET反编译神器,免费下载)

    Telerik JustDecompile是Telerik公司推出一个免费的.NET反编译工具,支持插件与Visual Studio 2015~2013集成,还能够创建Visual Studio Pr ...

  7. [IOS]《A Swift Tour》翻译(一)

    以下翻译内容为原创,转载请注明: 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3768936.html 碎碎念... Swift是苹果在WWDC刚发 ...

  8. Android 显示意图激活另外一个Actitity

    1.跳转到一个新的Actitity 新建项目, 新建一个java类OtherScreenActivity 继承自 Activity类 package com.wuyudong.twoactivity; ...

  9. 你真的了解UIViewController跳转吗?

    一:UIViewController模态跳转 //展示模态视图 - (void)presentViewController:(UIViewController *)viewControllerToPr ...

  10. App开发流程之右滑返回手势功能续

    上一篇记录了利用系统私有变量和方法实现右滑返回手势功能:http://www.cnblogs.com/ALongWay/p/5893515.html 这篇继续记录另一种方案:利用UINavigatio ...