Lucene.NET和HubbleDotNet匹配相关度的比较

开发 后端
在这里,我们将要讨论的是Lucene.NET和HubbleDotNet匹配相关度的比较的问题。不匹配的信息对于用户来说是毫无意义的。

很多网友在使用 Lucene.net (Lucene java 版本也是一样)后会感觉Lucene.net 的匹配相关度存在问题,搜索得到的结果往往不是希望的结果,不完全匹配的记录往往比完全匹配的记录排序还要靠前,很多人试图通过分词来解决,中文环境搜索,分词确实能解决一些问题,但不能根本解决问题,而英文环境下,分词根本无法解决任何问题。问题的本质是由于Lucene的得分算法缺陷造成的,不改进得分算法根本不能根本解决问题。HubbleDotNet的得分算法参考了Lucene的得分算法并做了重大改进,匹配相关度比Lucene.net 有了显著提高。本文结合一个极端的例子来分析两者得分算法的异同,并从原理上讲解为什么HubbleDotNet 的匹配相关度要比Lucene.net 的高。

先看例子

我们对下面两条记录分别用 Lucene.net 2.9.1 和 HubbleDotNet 0.9.7.1 进行索引。

记录1

教育问题一直是国家最关心的,我们要长抓不懈

记录2

教育独生子女问题,这是很多家长要关心的问题

分词采用盘古分词,分词参数中关闭多元分词。

两个句子的分词结果分别为:

教育/问题/一直/是/国家/最/关心/的/我们/要/长抓/不懈/

教育/独生子女/问题/这/是/很多/家长/要/关心/的/问题/

要搜索的句子是:教育问题

其分词结果为:教育/问题/

从直观上看,记录1 是完全匹配,应该得分比记录2高,这也是我们希望的排序结果,即记录1排在第一个,记录2排第二个。

下面看看实际的排序结果:

Lucene.net 的排序结果:(这是盘古分词带的Lucene.net 的例子稍作改动后(将得分输出了)的输出结果) 从结果我们可以看出记录2被排在了第一位,得分

为 0.042 而记录1 的得分为 0.034 排第二位,这个显然不是我们希望的结果。

image

再看HubbleDotNet的结果

image

这里我们看到记录1被排在第一位,得分为 390218522

记录2 排第二位,得分 85937

原因分析

要分析两者匹配相关度的差异,我们需要比较两者的基础得分算法

Lucene 的基础得分算法

image

coord(q,d): 文档d中,q中命中的项数除以查询q的项总数

queryNorm(q): 只在不同query比较时影响score的normalizing因素

tf(t in d):单文本词汇频率,t在文档d中出现的次数除以d中所有的项总数的平方根

idf(t):逆文本频率指数,log(numDocs/docFreq+1)+1.0

image

If the document has multiple fields with the same name, all their boosts are multiplied together

从Lucene的得分算法公式我们可以看出,得分算法和单词在文档中的位置没有任何关系,也就是说Lucene 的得分算法只关心单词分量的出现频率,不关心出现位置。这就不难理解为什么文档2的得分比文档1高了,因为文档2中 “教育”分量出现了1次,“问题”分量出现了2次,而文档1中这两个分量各出现了一次,另外idf 和 norm(t,d) 在当前环境中又几乎相等,于是文档2的得分就超过了文档1。这是Lucene得分算法的重大缺陷,因为文档的匹配相关度不仅与频率有关还与位置有关。

HubbleDotNet 的基础得分算法

HubbleDotNet 在设计得分算法时充分考虑到了Lucene 的这个缺陷,在得分算法中加入了位置函数 fp(t,d,q) ,这个位置函数的加入使HubbleDotNet 的匹配相关度比Lucene有了大幅的提高。 

HubbleDotNet 的基础得分算法公式如下:

image

这个算法其实是以 TF-IDF 算法为基础并增加了位置函数 fp(t,d,q)

其中

  • FieldRank 为字段权值
  • Rank(t,q) 为单词分量(term)的在查询字符串中的权值,即 教育^1^0 中的 1
  • Rank(t,d) 为单词分量(term)所在文档的权值,默认为1,如果要指定文档权值,需要在表中增加一个 rank int untokenized 字段。
  • TF(t,d) : 为单文本词汇频率,要查询的单词分量(term)在文档中的出现的次数除以文档所有单词分量出现的次数。

公式如下:

image

  • IDF(t) 为逆文本频率指数。

公式如下:

image

|D|: 文本集合的文档总数

image : 为含有单词分类(term)的文档总数

HubbleDotNet 的 tf idf 算法是根据标准算法来写的,和Lucene 的算法有不同。参考 tf-idf

  • Sum(t) = 单词分量(term) 在所有文档中出现的总数的平方根。

公式如下:

image

  • fp(t,d,q) 是单词分量在文档中的位置与在查询字符串中的位置关系函数,位置越接近,则返回值越大。

除去 fp(t,d,q) 以外的部分和 Lucene 的得分算法是近似的,都是基于余弦定理来做的,只是在实现上有点区别而已。

而 fp(t,d,q) 则是Lucene 得分算法所没有的,这个函数是单词分量在文档中的位置与在查询字符串中的位置关系函数,位置越接近,则返回值越大。

就拿上面的例子来说,教育 和 问题 这两个单词分量在文档1 中的位置关系和查询字符串 “教育问题” 的位置关系是一致的,这时 fp(t,d,q) 函数的返回值就会很大,而文档2中,两个单词分量的位置关系和查询字符串“教育问题” 的位置关系不一致,这时返回值就比较小。这也就是我们看到文档1的得分要比文档2大几个数量级的原因。

关于fp(t,d,q)这个函数的实现原理我将在另外的文章中阐述,主要思路就是计算相同向量在文档中和查询字符串中的向量夹角然后求积,不过说起来简单,这里面要考虑的问题还是比较多,比如如何控制返回值不能太大,查询字符串中有多个相同单词分量怎么处理等等。

原文标题:HubbleDotNet 和 Lucene.Net 匹配相关度的比较

链接:http://www.cnblogs.com/eaglet/archive/2010/09/07/1820267.html

【编辑推荐】

  1. 用Lucene做一个简单的Java搜索工具
  2. Linq存储过程返回详解
  3. Linq调用LoadProducts方法
  4. Linq使用数据表简单描述
  5. Linq对象引用简单介绍
责任编辑:彭凡 来源: 博客园
相关推荐

2012-07-31 10:37:31

Lucene.net

2012-08-30 10:20:55

Lucene分布式全文检索

2009-09-09 14:20:49

LINQ To Luc

2009-02-04 09:31:30

SocketNetworkStreTcpClient

2010-03-11 11:10:14

Python函数式

2009-10-29 14:02:24

VB和VB.NET比较

2009-08-12 18:16:47

C#类型比较

2009-09-07 15:04:07

2009-07-30 12:42:19

html控件和web控

2009-12-24 09:56:01

JDK.NET CLR

2024-05-06 12:52:30

2012-06-21 10:18:43

索引搜索Java

2009-12-22 15:03:51

ADO.NET使用

2010-01-08 17:00:22

VB.NET变量和常数

2014-03-10 10:06:40

WebSocket.Net

2024-07-29 09:46:00

2009-07-06 10:43:51

ADO.NET

2009-02-13 09:45:27

程序员JavaPHP

2009-06-12 09:22:44

VB.NET类型C#

2009-07-28 14:10:14

点赞
收藏

51CTO技术栈公众号