序:
Forums对用户的搜索建立了一个轻量级的全文检索引擎,之所以说是轻量级的,是因为它把索引内容存储在一个sql server表中,占用空间相对sql server的全文检索文件来说要小,效率要高,但是也有一定的局限性,这将在后面的讨论中谈到。
下面首先介绍全文检索原理,接着讨论在forum中建立全文检索,然后描述一个论坛用户进行搜索的时候发生的事情,最后讨论这种形式的全文检索和sql server提供的全文检索服务的不同之处,以及对中文的支持情况。
全文检索原理:
首先要了解的是全文检索的原理,在Carfield的猫的blog中有这么一段话形象的解释了全文检索,引用如下:
大家都知道LIKE查询很慢,全文索引就是事先做好相关的索引,表示哪个主题词可以在哪些记录里找到,甚至事先计算好RANK,检索时可以把相关度高的先列出来,这可以大大提高检索的速度。
打个比方,你有很多的小抽屉,每个抽屉里面放一些杂物,假如你要找东西,最原始的方法就是一个个抽屉翻,这就是没有索引的情况。
假如聪明一点,给抽屉编号(唯一键),把哪个号码的抽屉有什么东西记录在纸上,找东西先看看这张纸,这就是普通索引,假如你要知道哪个抽屉有什么,你可以在纸上迅速找到 抽屉号码(大家知道这是使用查找树),然后得到相关的信息,这种情况普通索引是很快的;但是要找到一个特定的东西哪些抽屉有,你就要把整张纸遍历一次,这就是LIKE查询,假如你要找哪些抽屉同时有2种甚至更多种物品,LIKE就更加繁琐了。假如一个表有上千万的纪录,大家可以想象查询的代价。
可以换一个思路,另外找张纸,记录一样东西存在于哪些抽屉:
夹子:1,3,4,5,6,9,12...
钱币:2,3,4,7,12...
药丸:1,3,5,6...
这样找到某样东西或者某几样东西都很容易。
建立索引:
根据以上原理,提取帖子的内容,作者,标题,以及帖子所在版面的名称,并且提取内容格式化,例如去掉html标签,将多个连续空格换成一个空格,去掉忽略的单词,去掉数字,26个英文字母,以及下划线。然后将格式化后的内容根据空格进行分词,并将分词的结果插入到forums_SearchBarrel表中,同时插入的还有这个单词的相关信息,例如这个单词的hash值,单词所属帖子的postID,threaded,forumID,以及单词的weight,weight直译就是这个单词的重量,其实就是这个单词在这篇Post中的重要性的一个量化描述,这个单词的weight和单词所在的帖子的状态(是否lock),贴子的总单词数,回复的post数目,发帖人的性质(是否为匿名用户),单词是标题,还是版面名称,还是贴子内容等等都有关系。
建立索引表的过程可以使用下图来表示:
搜索内容:
用户对论坛内容的搜索就是建立在这张索引表forums_SearchBarrel上,在查询输入界面输入想要查询的内容,可以使用and ,or 来构建更为复杂的查询条件,还可以选择查询的版面以及作者等。然后对这些条件编码传送到查询显示页面。在查询显示页面解码查询条件,构造查询sql语句,返回查询结果。更为详细的过程可用下图来表示:
在下面的图片中,我们假设一个用户对论坛进行一个复杂的查询,使用了and和or关键字,但是没有使用*号。
与sql server提供的全文索引的区别
Forums的全文索引和sql server提供的全文索引服务是有些区别的,forums的全文检索是建立在sql server的表上,而sql server的全文检索服务是建立在windows提供的索引服务之上,存储在windows的文件系统中,是占用空间小,文检索效率也是很高的。
中文支持情况
从forums的全文检索原理就可以看出,forums对中文搜索来说是非常痛苦的,因为中文不是使用空格来分词。为了能使用全文检索,可以使用下面三种方法。
1、 根据图一的流程,我们在分词的地方作些修改,可是使用第三方的分词工具,来对中文分词。这个可能需要动用你的金库了。
2、 在分词的地方对中文的每一个词都作一个单词。这样做会使得索引表非常大,并且效率也不高。
3、 屏蔽forums中的索引服务,使用sql server的全文检索。
一些bug修改
我下载的0831中文版,在使用过程中发现进行高级搜索的使用不能使用and 和or关键字,做如下修改即可。
{
对于英文索引
1、Search.cs中的一行
函数TokenizeKeywords中
// OR code
if (wordHashCode == 5861509)
searchWords.Add(wordHashCode);
应该改为if (wordHashCode == “or”. GetHashCode())
2、
函数GetAndOrKeywords中
int OR = "||".GetHashCode();
int AND = "&&".GetHashCode();
为
int OR = "or".GetHashCode();
int AND = "and".GetHashCode();