在我们实验室老师为我们软件学院开的<<信息检索课>>上,我自己动手完成了一个小型文件检索系统的开发,包括对关键词进行散列,建立倒排索引,支持布尔(与,或,非等)查询.
在开发过程中用到了 网页正文提取,中文分词等技术.我阅读了中科院ictclas中文分词系统的源码并参考了实验室的部分程序.
下面是其设计实现方面的内容:
设计实现
Hash散列算法
使用的散列方法为ELFHash字符串散列算法,ELFHash函数能够比较均匀地把字符串分布在散列表中。
解决Hash冲突的使用的是开散列方法。
为了简化编程,大量使用了C++的标准模版库,如vector向量等。
索引结构
现在的搜索引擎使用的一般为基于倒排索引和基于签名档的
经过比较两者的优缺点,我觉得倒排索引更适合做文本检索系统的索引结构,所以我建立的索引是使用的倒排索引。
下面是我建立的索引表的结构图:
图1 索引结果图
结构体position 描述关键词在文件中的位置信息
struct position
{
//关键词在文件中出现的行数
int x;
//关键词在文件中出现的列数
int y;
};
结构体FileInfo 描述包含该关键词的文件的信息
struct info
{
//文件名
string fileName;
//关键词在文件中出现的次数
int count;
//关键词在文件中出现的位置
vector<position> p;
};
结构体Invert 描述单个倒排表项的结构
struct invert
{
//倒排表的关键字,也就是搜索时的关键字
string keyword;
//包含该关键字的文件名列表。使用vector向量存储
vector<info> fileInfo;
};
结构体HashInvertTable 描述整个倒排表项的结构
struct HashInvert
{
vector<invert> i;
};
struct HashInvertTable
{
HashInvert hashInvert[Module];
};
现在来用”Harbin”这个词插入索引的过程说明一下建立索引的过程。假设”Harbin”这个词是在文档”1.txt”中存在的,出现在第3行,第5列。则其结构体position的x值为3,y值为5,结构体FileInfo的filename为”1.txt”,count加1。倒排表项的Keyword值为索引词”Harbin”.使用ELFHash函数计算该索引词的Hash值为86,就将该倒排表项插入到HashInvertTable的86号槽中去。
结果标注
对查找的结果,按照索引表找到包含该关键词的文件名及在文件中的位置。然后抽取包含关键词的一行,通过HTML标记<font color=#ff0000>和</font>将关键词标为醒目的红色。后面显示该结果所在的文件名,然后将结果输出到一个结果文件result.html中去。如查找Harbin,找出来的结果将会这样显示:
Harbin Institute of Technology : 1.txt
I love Harbin . : 2.txt
停用词支持
停用词主要见于英文搜索引擎中,指的是使用过于频繁的单词,如:“is”、“i”、“what”、“it”等。我们一般不为这些停用词建立索引。
在本程序中,我用来过滤掉停用词使用的是最简单的方法。在为该关键词建立索引时,将该关键词与所有的停用词逐个的比较,如果该关键词没出现在停用词中时,在为该关键词建立索引。
正文提取
正文提取是在ir实验室的一位师兄的程序上改进的。该正文提取的基本思想就是对标签进行分析。观察大量的网页,观察有用的信息一般出现在哪些标签下面,而哪些标签下面的内容都是无用信息。将有用信息标签下的内容都提取出来作为正文,但这样的正文仍有很多噪声信息,通过一些关键词处理掉这些噪声信息,就可以得到质量较高的正文了。
对于不同的网站定义不同的有效标签和过滤词,实践证明,可以得到较好的效果。
中文分词
中文分词是使用的中科院ictclas开源分词软件,该程序分词效果较好,识别正确率特别是NE的识别率很高,而且处理的速度很快。其中中国人名的识别召回率接近98%,分词和词性标注处理速度为543.5KB/s。
我分析了一下该分词系统的源代码,源代码写的很巧妙,并且使用他们的两个研究成果。(通过阅读论文《HMMM-based Chinese Lexical Analyzer ICTCLAS-0711》和《基于N-最短路径方法的中文词语粗分模型》)。
他们是使用的基于N-最短路径方法进行中文词的切分,使用的借助于词典的统计模型。基本思想是快速搜索出前N个最优化路径,然后对这N个路径求概率,概率最高的那条路径就是切分的路径。基本思想是:根据词典,找出字串中所有可能的词,构造词语切分有向无环图。每个词对应图中的一条有向边,并赋给相应的边长(权值)。然后针对该切分图,在起点到终点的所有路径中,求出长度值按严格升序排列(任何两个不同位置上的值一定不等,下同)依次为第1, 第2,… ,第i,… ,第N 的路径集合作为相应的粗分结果集。如果两条或两条以上路径长度相等,那么他们的长度并列第i,都要列入粗分结果集,而且不影响其他路径的排列序号,最后的粗分结果集合大小大于或等于N。
使用HHMM方法进行词性标注。使用了多层的HMM模型(总共五层)。
布尔查询
布尔查询是通过对各个关键词查询的结果集进行并、交、差等操作进行的。
如求 (关键词Key1 || 关键词Key2)的操作,先求出关键词Key1的检索结果Set1,然后求出关键词Key2的检索结果Set2,对这两个结果集求并操作Set3 = Set2 ∪ Set1. 将Set3返回做查询的结果。