搜索排序结果的控制

Lucnen作为搜索引擎中,应用最为广泛和成功的开源框架,它对搜索结果的排序,有一套十分完整的机制来控制;但我们控制搜索结果排序的目的永远只有一个,那就是信息过滤,让用户快速,准确的找到其想要的结果,丰富用户体验。

以前看过一个牛人的博客,总结了4个地方,可对Lucene检索结果的排序进行控制,现在已经记不住。我自己简单整理了下面几个,若有疏漏,欢迎补充:

1.    通过Lucene自有的查询表达式:Lucene提供相当丰富的表达式解析,要细讲就多了去了;这里只强调下,我在项目中用的比较多的是通过对指定域的加权,来影响检索结果(例如:field1:(XXX)^10 or field2:(XXX)^5;其中XXX是用户提交的检索)

2.    权重的控制:这是在建索引的时候就写入索引的,查询时只是读取出来,用乘的方式来对一些检索结果加分。据我自己看Lucene代码,Similarity中也能在建索引时,对权重的写入进行控制;后面会细讲。

3.    Controller 模块:Lucene的排序流程控制模块,里面提供的一些接口能让你对打分后的搜索结果进行一些筛选和调整。

4.    Similarity 模块:Lucene的搜索结果打分控制模块,也是这里要详细分析的模块。他能让你对一个检索结果的打分进行优化,或面目全非,哈哈。

Lucene的打分公式

要理解Similarity模块对打分结果控制,首先要了解Lucene自己评分原理:相似度评分公式;次公式是目前公认的用户体验较好的一个,原理是根据余弦定理,我在以前的博文中有介绍过。下面是在摘自《Lucene实战》(第二版)的公式表达式:

其中q 为查询语句,t 是q 分词后的每一项, d为去匹配的文档。

接下来对公式中的每一个函数,进行详解,他们都能在 Similarity 模块中进行控制。

Lucene打分流程

首先,我简单说明下,Lucene对一次查询是如何封装;这涉及到对打分公式是如何调用的,如此一来更能全面的了解打分流程:

第一步的处理肯定是分词,查询语句 => term_1, term_2 …  term_n(n∈[1,∞]),紧接着是将这些term 封装成Query对象,总的Query对象是BooleanQuery,它里面包含和分词数相同TermQuery,和分词后的词项一一对应;这是对一个域的查询,若你多个域联合查询,那就会有多个这样的BooleanQuery,被一个更大的BooleanQuery包裹着。

而打分公式,贯穿所有Query,其中一部分在TermQuery中计算,一部分在BooleanQuery计算,最后按此计算出的得分进行排序,就得到了我们的搜索结果。

下面是我通过explain(Query query, int doc) 导出的打分解释:

对照Lucene的打分解释,我们一层一层往里拨(上述每个缩进为一层),每一个函数都能在Similarity中进行控制。

1.      首先第一层:3.3936599 = (MATCH) product of:,是此条记录的总得分。

2.      第二层:8.48414992 = (MATCH) sum of: 它对应一个BooleanQuery,它把它包含的TermQuery的得分累加起来,由于TermQuery总共有5个,此条结果中只匹配了2个,所以最后一行将得分乘以了0.4得到最后的打分,coord()在Similarity中的默认实现如下:

1 /** Implemented as <code>overlap / maxOverlap</code>. */
2 @Override
3 public float coord(int overlap, int maxOverlap) {
4   return overlap / (float)maxOverlap;
5 }

你也可以继承Similarity对此方法重写。

3.      第三层:(MATCH) weight(field:XXX in m), product of: 有2个,它们分别是“三国”、“无双”对应的词项查询TermQuery的得分。

再往里,就是TermQuery的打分规则了,里面的函数已经和公式有所对应了,下面就详细介绍TermQuery中每一项计算的作用。

Similarity 函数详解

TermQuery中有4个函数,都是Similarity里可以控制的函数,他们分别是queryNorm、tf、idf、fieldNorm;其中queryNorm对于某一次搜索中结果的排序没有影响,在一次搜索中queryNorm的值是固定的。这里就不介绍了

tf(t in q)

此函数表示词项T 在该文档中的该字段里 出现的频率;对应到上图的例子中:既是分词后的词项(三国 或 无双)在此条记录中Name字段里出现的频率。当然出现的次数越多,它返回的值越大,也正好反映了此文档的重要性。下面是DefaultSimilarity中的默认实现的默认实现。

1 /** Implemented as <code>sqrt(freq)</code>. */
2 @Override
3 public float tf(float freq) {
4   return (float)Math.sqrt(freq);
5 }

默认实现是开平方。同样你可以重写此函数。

它实际对结果排序的影响,表现和它的意义一样,一个搜索结果包含的搜索关键词越多,得分越高。

idf(t)

此函数出现了两次,也刚好对应公式中的 idf(t)^2;

这个函数被称作倒频率,表示词项T 在所有文档中出现的频率。若它在所有文档中出现的次数越多,表明这个词项T 越不重要;以下是DefaultSimilarity的默认实现。

1 /** Implemented as <code>log(numDocs/(docFreq+1)) + 1</code>. */
2 @Override
3 public float idf(int docFreq, int numDocs) {
4   return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
5 }

此函数实际对结果排序的影响,在于当一次搜索包含多个词项时,文档A和B分别包含了其中一个词项;比如A包含“三国”,B包含“无双”;那么“三国”和“无双”的倒频率就会影响,让A、B的得分产生差异了。若词项只有一个,那本次搜索idf(t) 实际对结果排序不会产生影响。

fieldNorm (t)

它的值对应着公式中 boost(t.field in d)×lengthNorm(t.field in d) 的值。其中boost(t.field in d)的值,在创建索引时就被记录下来,而lengthNorm(t.field in d)得值,会在查询过程中计算;它表示此条搜索结果中,给定字段中包含词项的总数;若值越大,得分越低;你可以这么理解;若A文档有包含了1000个词项,关键词出现的频率为10;而B文档包20个词项,相同关键词出现的频率为8;很明显B文档的打分应该要高一些;由此函数可以起到这样的效果。以下是Similarity 的默认实现,函数名在3.0以后变了,原来就叫lengthNorm

01 /** Decodes a normalization factor stored in an index.
02  * <p>
03  * <b>WARNING: If you override this method, you should change the default
04  *    Similarity to your implementation with {<a href="http://my.oschina.net/link1212" target="_blank" rel="nofollow">@link</a> Similarity#setDefault(Similarity)}.
05  *    Otherwise, your method may not always be called, especially if you omit norms
06  *    for some fields.</b>
07  * <a href="http://my.oschina.net/u/244147" target="_blank" rel="nofollow">@see</a> #encodeNormValue(float)
08  */
09 public float decodeNormValue(byte b) {
10   return NORM_TABLE[b & 0xFF];  // & 0xFF maps negative bytes to positive above 127
11 }

至此Lucene打分流程和Similarity模块的函数已经将的差不多了。可以通过这些函数让你的搜索展示出完全不一样的效果,这也需要根据不同的业务慢慢调试,才能得出最优化的搜索结果

原创博客,转载请注明http://my.oschina.net/BreathL/blog/51498

Lucene打分规则与Similarity模块详解的更多相关文章

  1. lucene、lucene.NET详细使用与优化详解

    lucene.lucene.NET详细使用与优化详解 2010-02-01 13:51:11 分类: Linux 1 lucene简介1.1 什么是luceneLucene是一个全文搜索框架,而不是应 ...

  2. Node入门教程(8)第六章:path 模块详解

    path 模块详解 path 模块提供了一些工具函数,用于处理文件与目录的路径.由于windows和其他系统之间路径不统一,path模块还专门做了相关处理,屏蔽了彼此之间的差异. 可移植操作系统接口( ...

  3. (转)python之os,sys模块详解

    python之sys模块详解 原文:http://www.cnblogs.com/cherishry/p/5725184.html sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和 ...

  4. Burpsuite模块—-Intruder模块详解

    一.简介 Burp Intruder是一个强大的工具,用于自动对Web应用程序自定义的攻击,Burp Intruder 是高度可配置的,并被用来在广范围内进行自动化攻击.你可以使用 Burp Intr ...

  5. lucene.NET详细使用与优化详解

    lucene.NET详细使用与优化详解 http://www.cnblogs.com/qq4004229/archive/2010/05/21/1741025.html http://www.shan ...

  6. Kali linux 2016.2(Rolling)中的payloads模块详解

    不多说,直接上干货! 前期博客 Kali linux 2016.2(Rolling)中的Exploits模块详解 payloads模块,也就是shellcode,就是在漏洞利用成功后所要做的事情.在M ...

  7. Python中操作mysql的pymysql模块详解

    Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ...

  8. python之OS模块详解

    python之OS模块详解 ^_^,步入第二个模块世界----->OS 常见函数列表 os.sep:取代操作系统特定的路径分隔符 os.name:指示你正在使用的工作平台.比如对于Windows ...

  9. python之sys模块详解

    python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...

随机推荐

  1. kettle工具同步数据乱码-Linux下乱码问题二

    将写好的kettle工程部署到Linux下后,同步的数据都成了乱码,幸运的是数据库有备份. 下面就说一下,kettle工程如何同步两端编码格式都是utf8的数据库. 我们只需要更改kettle数据库连 ...

  2. cocos2d-x-2.2.5项目创建--命令行创建

    Gavin:downloads DavidLik$ cd cocos2d-x-2.2.5/ Gavin:cocos2d-x-2.2.5 DavidLik$ cd tools/ Gavin:tools ...

  3. static静态属性和静态方法的原理与调用技巧

    这篇文章主要介绍了php面向对象中static静态属性和静态方法的调用,实例分析了static静态属性和静态方法的原理与调用技巧,需要的朋友可以参考下     本文实例讲述了php中static静态属 ...

  4. PHP反射ReflectionClass、ReflectionMethod 入门教程

    PHP反射ReflectionClass.ReflectionMethod 入门教程 作者:SNSGOU 发布于:2014-03-16 16:44:00  分类:PHP   浏览(6145) PHP5 ...

  5. Android Studio Errors

    1.The import org.apache.http.client; tip: cannot be resolved; resolve: add this line in build.gradle ...

  6. cc1plus: fatal error: emeralddb-pmdMain.d: No such file or directory

    签名autoscan, aclocal, config啥的都没错,最后make 报下面的错,查了各个文件没发现有啥问题,请哪位帮忙卡看 make[1]: Entering directory `/ro ...

  7. JQ 替换节点

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. 求一组数字序列的分布情况(java)

    最近需要做一个正态分布的函数图像所以要处理一段double序列 写了这个算法  先上效果图: 核心思想: 1先根据步长计算每一个区间 2循环进行判断序列中每个数属于哪个区间 3用一个数组来保存每一个区 ...

  9. BeanUtils 以及BeanUtils.populate使用

    Apache Jakarta Commons项目非常有用.我曾在许多不同的项目上或直接或间接地使用各种流行的commons组件.其中的一个强大的组件就是BeanUtils.我将说明如何使用BeanUt ...

  10. GDAL的安装和配置(编译proj.4)

    1.下载地址 http://trac.osgeo.org/gdal/wiki/DownloadSource 下面是两个版本: http://pan.baidu.com/s/1bntuXER  (1.1 ...