对于海量数据,建立倒排索引往往需要较大的磁盘空间,尤其是一些常见的单词,这些单词对应的倒排列表可能有几百兆。如果搜索引擎在相应用户查询的时候,用户查询包含了常见的单词,就需要将大量的倒排列表信息从磁盘读入内存。
由于磁盘读写速度往往是个瓶颈,所以整个过程的速度会收到影响。索引压缩则可以利用数据压缩算法,有效的将数据量减少,这样一方面可以减少索引占用的磁盘空间资源,另一方面可以减少磁盘读写的数据量。
词典压缩
为了快速响应用户查询,词典往往会全部加载到内存中。为了减少词典所占内存,一般考虑词典压缩技术。以前介绍了hash加链表、B树以及FST。一般会存储三项数据:单词本身内容,文档频率信息DF以及指向倒排列表的指针信息。(如下图所示)
对于单词来说,可长可短,有的单词需要20个字节,有的只需要4个字节。为了能容纳最长的单词,我们给单词这一项分配了20个字节,这样就造成了浪费(内碎片)。
针对单词内容存储结构的一种优化措施是:将单词连续存储在某个内存区域,原先存储单词内容的部分由指向这个存储区对应单词起始位置的指针代替,单词结尾可以用词典中下一个单词所指向位置来做判断,这样就可以将原先浪费的存储空间利用起来。(如下图所示)
继续做出改进是:将连续词典进行分块,途中的例子是将每两个单词作为一个分块,在实际开发时,可动态调整分块大小,以获取最优压缩效果。(如图所示)
倒排列表压缩算法
单词对应的倒排列表一般记载3类消息:ID,TF,以及单词位置序列信息。因为ID是递增的,所以一般存储其差值,而非原始数据。
- 压缩率:数据压缩前后大小的比例关系
- 压缩速度
- 解压速度(最重要)
这两个算法是所有倒排列表压缩算法的基本构成元素,不论压缩算法内部逻辑思路是怎样的,最终都要以这两种格式来对数据进行表示。
一元编码:对于整数X来说,使用X-1个二进制书1和末位一个数字0来表示这个整数。当然一元编码只适合表示小数字。
二进制表示:
在此基础上的算法暂时省略。
文档编号重排序
在建立索引的时候,要对每个网页赋予唯一的文档编号。文档重新排序不是随机赋予文档一个ID,而是使得到排列表中相邻的两个文档编号也尽可能相邻,这样使得D-Gap尽可能小。
所以为了达到这个目的,越相似的网站其文档编号越相邻。
通过聚类,重排序:
但面对海量数据,文本聚类的速度很难满足实际的要求。所以有一种启发式的规则:将页面URL相似的网页聚合在一起,这主要考虑到同一个网站的很多页面表达的主题内容是近似的,通过这种方式可以非常高校的将网页聚合在一起。
静态索引裁剪
前面的压缩算法都是无损压缩,即压缩后数据信息没有任何损失。静态索引剪裁则是有损压缩,通过主动抛弃一些不重要的信息来达到更好的数据压缩效果。
对于用户查询来说,搜索往往只返回相关性最高的K个网页,所以可以将那些不重要的索引项从倒排索引中清除掉。
静态剪裁有两种思路:
- 以单词为中心的剪裁
- 以文档为中心的剪裁
以查询”搜索引擎“这个单词为例:
通过函数g()来计算出每个文档相应的得分。
一个直观的裁剪方法是:得分低于某个阈值即清除该索引项。如图,如果要清除低于0.3分的文档,那么ID3和ID7都会被清除掉。
但有时候,这种按阈值裁定的方法可能会把所有索引项都清除掉,所以有时候我们需要保留至少K个。
尽管一片文章有很多单词,但是只有一部分单词为文章服务,另一部分是无关紧要的。我们可以判断单词的重要性得分,进行裁剪。