Lucene打分规则与Similarity模块详解

搜索排序结果的控制

      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_nn[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中的默认实现如下:

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

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

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

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

Similarity 函数详解

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

tf(t in q)

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

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

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

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

idf(t)

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

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

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

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

/** Decodes a normalization factor stored in an index.
   * <p>
   * <b>WARNING: If you override this method, you should change the default
   *    Similarity to your implementation with {@link Similarity#setDefault(Similarity)}. 
   *    Otherwise, your method may not always be called, especially if you omit norms 
   *    for some fields.</b>
   * @see #encodeNormValue(float)
   */
  public float decodeNormValue(byte b) {
    return NORM_TABLE[b & 0xFF];  // & 0xFF maps negative bytes to positive above 127
  }

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

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

转载于:https://my.oschina.net/BreathL/blog/51498

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自己动手写搜索引擎 1 第1章 了解搜索引擎 1 1.1 Google神话 1 1.2 体验搜索引擎 1 1.3 你也可以做搜索引擎 4 1.4 本章小结 4 第2章 遍历搜索引擎技术 5 2.1 30分钟实现的搜索引擎 5 2.1.1 准备工作环境(10分钟) 5 2.1.2 编写代码(15分钟) 6 2.1.3 发布运行(5分钟) 9 2.2 搜索引擎基本技术 14 2.2.1 网络蜘蛛 14 2.2.2 全文索引结构 14 2.2.3 Lucene 全文检索引擎 15 2.2.4 Nutch网络搜索软件 15 2.2.5 用户界面 17 2.3 商业搜索引擎技术介绍 17 2.3.1 通用搜索 17 2.3.2 垂直搜索 18 2.3.3 站内搜索 19 2.3.4 桌面搜索 21 2.4 本章小结 21 第3章 获得海量数据 22 3.1 自己的网络蜘蛛 22 3.1.1 BerkeleyDB介绍 27 3.1.2 抓取网页 28 3.1.3 MP3 抓取 29 3.1.4 RSS 抓取 30 3.1.5 图片抓取 33 3.1.6 垂直行业抓取 34 3.2 抓取数据库中的内容 36 3.2.1 建立数据视图 36 3.2.2 JDBC数据库连接 36 3.2.3 增量抓取 40 3.3 抓取本地硬盘上的文件 41 3.3.1 目录遍历 41 3.4 本章小结 42 第4章 提取文档中的文本内容 43 4.1 从HTML文件中提取文本 43 4.1.1 HtmlParser介绍 51 4.1.2 结构化信息提取 54 4.1.3 网页去噪 60 4.1.4 网页结构相似度计算 63 4.1.5 正文提取的工具FireBug 64 4.1.6 正文提取的工具NekoHTML 66 4.1.7 正文提取 68 4.2 从非HTML文件中提取文本 73 4.2.1 TEXT文件 73 4.2.2 PDF文件 73 4.2.3 Word文件 82 4.2.4 Rtf文件 82 4.2.5 Excel文件 83 4.2.6 PowerPoint文件 84 4.3 流媒体内容提取 85 4.3.1 音频流内容提取 85 4.3.2 视频流内容提取 87 4.4 抓取限制应对方法 89 4.5 本章小结 90 第5章 自然语言处理 91 5.1 中文分词处理 91 5.1.1 Lucene 中的中文分词 91 5.1.2 Lietu中文分词的使用 92 5.1.3 中文分词的原理 92 5.1.4 查找词典算法 95 5.1.5 最大概率分词方法 98 5.1.6 新词发现 101 5.1.7 隐马尔可夫模型 102 5.2 语法解析树 104 5.3 文档排重 105 5.4 中文关键词提取 106 5.4.1 关键词提取的基本方法 106 5.4.2 关键词提取的设计 107 5.4.3 从网页提取关键词 107 5.5 相关搜索 107 5.6 拼写检查 110 5.6.1 英文拼写检查 110 5.6.2 中文拼写检查 112 5.7 自动摘要 116 5.7.1 自动摘要技术 117 5.7.2 自动摘要的设计 117 5.7.3 Lucene中的动态摘要 124 5.8 自动分类 125 5.8.1 Classifier4J 126 5.8.2 自动分类的接口定义 127 5.8.3 自动分类的SVM方法实现 128 5.8.4 多级分类 128 5.9 自动聚类 131 5.9.1 聚类的定义 131 5.9.2 K均值聚类方法 131 5.9.3 K均值实现 133 5.10 拼音转换 138 5.11 语义搜索 139 5.12 跨语言搜索 143 5.13 本章小结 144 第6章 创建索引库 145 6.1 设计索引库结构 146 6.1.1 理解 Lucene 的索引库结构 146 6.1.2 设计一个简单的索引库 148 6.2 创建和维护索引库 149 6.2.1 创建索引库 149 6.2.2 向索引库中添加索引文档 149 6.2.3 删除索引库中的索引文档 151 6.2.4 更新索引库中的索引文档 151 6.2.5 索引的合并 151 6.2.6 索引的定时更新 152 6.2.7 索引的备份和恢复 153 6.2.8 修复索引 154 6.3 读写并发控制 154 6.4 优化使用 Lucene 155 6.4.1 索引优化 155 6.4.2 查询优化 157 6.4.3 实现时间加权排序 162 6.4.4 实现字词混合索引 163 6.4.5 定制Similarity 170 6.4.6 定制Tokenizer 171 6.5 查询大容量索引 173 6.6 本章小结 174 第7章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值