本文主要介绍了全文信息检索的概念、应用领域、算法分类、技术难点和算法比较。及一款实现全文检索的数据结构和算法。
二、什么是全文数据库和全文信息检索
保存在数据库中的记录数据,从类型上可以分为两种。其一是结构化数据,象字符、日期、数值、货币等,这些数据都是具有有限长度或固定格式的数据;其二是非结构化数据,也叫全文数据,象简历、简介、论文等,这些数据都是以不定长、非固定格式保存的字符型数据。
现有的数据库系统,都是以结构化数据为检索的主要目标,因为实现相对简单。比如数值检索,可以建立一张排序好的索引表,以二分法实现查找,速度很快。但对于非结构化数据,即全文数据,要想实现检索,相对难度要大的很多了。
当然,你也许会说:“这个多简单呀,把全文数据读到内存,然后进行比较查找不就可以了?”。不错,的确是一个很朴素想法。不过最严重的问题是,如果数据库中有1万条,10万条,100万条记录的话,可以想象一下检索所消耗的时间了吧?!如果一个全文数据库系统,对一条检索命令的响应时间超过了半分钟,那么没有用户是能够容忍的了。
因此,全文检索的主要目的,就是实现对大容量的非结构化数据的快速查找。三、应用领域
现在,随着计算机使用的越来越普及,数据的积累越来越多,全文检索的要求也就越来越迫切了。目前,主要的应用领域是:图书馆数据库、情报数据库、专利数据库、医药数据库、办公自动化、历史资料库、电子出版系统、等等。
四、算法和算法比较
目前,实现全文信息检索的算法有两大基本方案,词索引和字索引。
词索引,以单词为索引单位的检索算法。这个技术是全文检索技术的鼻祖(60年代,就已经有产品问世)。道理很简单,计算机是适合于英语语言环境的,而英语又是以单词为语言要素。说的更通俗一些,就是每个英文单词之间都有一个空格。因此,在对全文数据库建立索引的时候,按照单词划分建立索引,是即简单又自然的。我们国家最开始引入全文检索技术的时候,是汉化英文的数据库系统,因此也就自然使用了词索引技术。但由于中英文环境中语素的不同特点,使得中文必须要解决分词的问题。比如对一句话“我是中国人”,那么必须要切分出“我 是 中国 人”这样的单词形式。如果是人的大脑来进行分词判断,那真是太简单了,只要有小学二年级的中文水平,就足够了。但是,如果想让计算机能够进行分词,却非常困难。计算机分词的大致算法是:由文章切分出段落,由段落切分出句子,由句子切分出短语,然后查找词库,根据动词、连词、形容词再进行切分得到所有的单词。在某些情况下,计算机是根本无法正确进行分词的。下面是计算机自动分词所闹的笑话:
(1)我们要积极地主动作好计划生育工作
计算机愚蠢的分词结果:我们 要 积极 地主 动作 好 计划 生育 工作
评论:我胡汉三又回来啦
后果:检索“地主”的时候,产生误查结果
(2)吉林省长春市的人民
计算机愚蠢的分词结果:吉林 省长 春市 的 人民
评论:我知道了,吉林有个省长叫“春市”
后果:检索“吉林省”的时候,产生漏查结果
因此,词索引的技术难点是分词算法。Oracle 和 Notes 等汉化的数据库系统,虽然也都提供了部分全文检索功能,但都出现了这样或那样的问题。分词算法的提升空间还是有的,需要加入人工智能分析、上下文判断等技术。但还有一个致命的弱点,那就是对地名,人名的判断。
字索引,以汉语单字为索引单位的检索算法。这个也是我推荐的算法,较词索引更适合于中文环境。这也就是为什么英文汉化版的全文检索软件没有占领中国市场的主要原因。(目前,本土民族化的软件,比如手写板,汉字扫描识别,中文全文信息检索......还是比国外的同类产品领先很多的。)但字索引也不是没有缺点,最主要的问题是:
(1)、检索“华人”,会误查出“中华人民共和国”
(2)、检索中药“大黄”,会误查出“大黄缄”,“大黄麻”等完全不同概念的药品。而这些单词在英文中是不会出现错误的,因为根本就是不同的拼写。
字索引的多查错误,也是可以更正的。比如检索“大黄”的同时,也检索“大黄缄”,然后排除“大黄缄”的检索命中点,但这需要付出检索时间的代价。下表,是字、词索引方案各项性能的比较:
索引方式 | 索引比 | 索引速度 | 检索速度 | 误查 | 漏查 |
词索引 | 0.8 ~ 2.0 | 慢 | 快 | 有 | 有 |
字索引 | 0.3 ~ 2.0 | 稍快 | 稍慢 | 有 | 无 |
五、一款中文全文信息检索算法的实现
这个算法是1993年设计并实现的。十年过去了,新版本中使用了更高级的技术,因此该算法已经废弃,并得以公开给大家。计算机界有一个著名的命题:程序 = 数据结构 + 算法。而公开的这个设计,正是数据结构和算法的完美体现。呵呵,不吹牛了,看看如何实现的吧。
I 基本原理
图(一) 展示了在数据结构中,最标准的一个单向链表的结构示意图。
图(二) 在标准的单向链表中,如果结点内容A、B......N 完全相同的时候,那么我们可以进行变换了,用图(二)表示,为叙述方便,称为“单一结点内容链表”。即,只需要在头结点中表示出内容,链表中后续的结点只有 NEXT 指针域,而省略掉内容域。
图(三) 在图二的“单一结点内容链表”中有一个缺点:如果我们得到了任意的一个非头结点指针的话,由于是单向链表,因此无法回溯得到该结点所表示的内容。因此再次变换,改进为图(三)的方式,称为“接续单向链表”。这样结构的链表有如下的特征:
(1)从头结点出发,可以得到后续所有结点的地址;
(2)从任意一个结点出发,当沿着指针跳转到“接续”结点的时候,就可以得到该结点所表示的内容;
(3)“接续链表”的存储空间,比标准的单向链表的存储空间要小很多。
II 构造头结点
设计一个数组,用来存储所有汉字链表的头结点。GB2312包容了汉字共7673个,用2个字节来表示一个汉字的内码,第一个字节的范围是A0~F7,第二个字节的范围是A0~FE。恰好的是,7673个汉字,加上一些常用符号,制表符号,再刨除一些未定义的空区,正好完全可以用16K字节的存储空间来全部表示出来。
和带有接点内容的链表有所不同的是,在这个头结点中,只有指针而没有结点内容。结点内容(汉字)其实是用数组的偏移地址来间接表示的。如上图所示,数组中偏移为 0000 的指针所表示的汉字是 A0A0 (即,全角空格)。
III 链表结构
由于每个指针只用2个字节表示,因此,链表指针的范围是 0000 - FFFF,64K大小。为了使链表能超越 64K 的范围,那么现在正好可以用“接续链表”构造出来了。下图表现了整个数据库的结构。
IV 实现检索
在下图的一个数据库结构中,我们实现单字“中”的检索和单词“中国”的检索。三种颜色,分别表示数据库中的三条记录的内容区域。
检索“中”。根据“中”的内码 D6D0 可以在头指针区域中定位到起点指针,然后按照链表分别在数据库第一条记录找到2个命中点,在第二条记录中找到1个命中点,而第三条记录没有命中。这时,指针到达“接续的头指针”区域,然后就可以继续检索下一个数据区了......直到结束。
检索“中国”。根据“中”和“国”的内码,定位头指针。这一对指针连续在链表中跳转,如果两个指针在跳转的时候恰好在数据区的地址偏移中相邻,则表示命中这个单词了(第一条记录中,画红圈部分)。然后,这对指针继续向后跳转,直到结束。
V 提取记录内容
由于记录内容中的汉字,已经用链表的指针表示了,那么如何提取还原出原始的汉字文章那?从数据区记录的开始,按照链表向后跳转,肯定会跳转到“接续头指针”的区域中,那么这时候根据指针所在地址,计算出相对偏移,就得到它表示的汉字了。重复操作,就能把原始的汉字文章全部还原出来。
VI 记录的入库
不用多说了吧?把指向“接续头指针”的链表断开,连接上新的地址,而该地址的存储的指针指向“接续头指针”。
VII 算法特点
(1)算法呈现出字索引方式。能够满足“查全”的功能。
(2)原始文本数据追加入库时,由于入库就是构造指针的过程,并同时建立了索引。入库数据量和处理时间呈线性关系。速度很快。
(3)文字信息在数据库中全部以指针存储,本身具有加密的功能。
(4)如果有某个指针在存取过程中发生错误,则该指针的后续必将产生连续错误且无法纠正,这是该算法的主要缺陷。
(5)数据区48K,头指针(接续)区16K,索引比为33%。这是全世界现有全文算法中,索引比最小的。
(6)该算法只适合于GB2312字符集。由于GBK,UNICODE,BIG5包含更多的汉字,会导致头指针(接续)区域的扩大,而数据区被压缩,因此失去了算法意义。
(7)检索时,需要按照64K为单位读取数据库文件(这正好适用于16位操作系统),检索效率会随着数据库的增大而减小。因此该算法适合于小型数据库的全文检索系统(10万条记录以内,总容量200M以下)。六、结束语
学习计算机软件设计,最重要的一门课程就是《数据结构》。这套全文检索算法,正是依靠精妙的数据结构构建出来的,其实说起来也很简单,就是链表数组。1993年的时候,PC机大多运行着 DOS + WINDOWS 3.1 + 中文环境(GB2312),这套算法正是适应当时的环境而设计的。现在十年过去了,随着计算机软硬环境的提升和全文数据量的增长,该算法虽然已经废弃,但通过该算法,大家一定能体会出“数据结构”的重要性。1998年,我又设计了新的全文检索算法,使用的是“数据结构”中的“散列表”。不过现在保密,也许10年后再公布吧。