倒排索引

倒排索引源于实际应用中需要根据属性的值来查找记录。

这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。

由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。

带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。

概述

在关系数据库系统里,索引是检索数据最有效率的方式。

但对于搜索引擎,它并不能满足其特殊要求:

1)海量数据:搜索引擎面对的是海量数据,像Google,百度这样大型的商业搜索引擎索引都是亿级甚至百亿级的网页数量 ,面对如此海量数据 ,使得数据库系统很难有效的管理。

2)数据操作简单:搜索引擎使用的数据操作简单,一般而言 ,只需要增、 删、 改、 查几个功能 ,而且数据都有特定的格式,可以针对这些应用设计出简单高效的应用程序。

而一般的数据库系统则支持大而全的功能 ,同时损失了速度和空间。

最后 ,搜索引擎面临大量的用户检索需求 ,这要求搜索引擎在检索程序的设计上要分秒必争, 尽可能的将大运算量的工作在索引建立时完成, 使检索运算尽量的少。

一般的数据库系统很难承受如此大量的用户请求,而且在检索响应时间和检索并发度上都不及我们专门设计的索引系统。

相关概念

倒排列表概念

倒排列表用来记录有哪些文档包含了某个单词。

一般在文档集合里会有很多文档包含某个单词,每个文档会记录文档编号(DocID),单词在这个文档中出现的次数(TF)及单词在文档中哪些位置出现过等信息,这样与一个文档相关的信息被称做倒排索引项(Posting),包含这个单词的一系列倒排索引项形成了列表结构,这就是某个单词对应的倒排列表。右图是倒排列表的示意图,在文档集合中出现过的所有单词及其对应的倒排列表组成了倒排索引。

在实际的搜索引擎系统中,并不存储倒排索引项中的实际文档编号,而是代之以文档编号差值(D-Gap)。

文档编号差值是倒排列表中相邻的两个倒排索引项文档编号的差值,一般在索引构建过程中,可以保证倒排列表中后面出现的文档编号大于之前出现的文档编号,所以文档编号差值总是大于0的整数。

如图2所示的例子中,原始的 3个文档编号分别是187、196和199,通过编号差值计算,在实际存储的时候就转化成了:187、9、3。

之所以要对文档编号进行差值计算,主要原因是为了更好地对数据进行压缩,原始文档编号一般都是大数值,通过差值计算,就有效地将大数值转换为了小数值,而这有助于增加数据的压缩率。

倒排索引概念

倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。

它是文档检索系统中最常用的数据结构。

通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。

倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。    倒排索引有两种不同的反向索引形式:

  1. 一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表。

  2. 一个单词的水平反向索引(或者完全反向索引)又包含每个单词在一个文档中的位置。

后者的形式提供了更多的兼容性(比如短语搜索),但是需要更多的时间和空间来创建。

现代搜索引擎的索引都是基于倒排索引。

相比“签名文件”、“后缀树”等索引结构,“倒排索引”是实现单词到文档映射关系的最佳实现方式和最有效的索引结构。

构建方法

简单法

索引的构建相当于从正排表到倒排表的建立过程。

当我们分析完网页时, 得到的是以网页为主码的索引表。

当索引建立完成后, 应得到倒排表。

流程描述如下:

1)将文档分析成单词term标记,

2)使用hash去重单词term

3)对单词生成倒排列表

倒排列表就是文档编号DocID,没有包含其他的信息(如词频,单词位置等),这就是简单的索引。

这个简单索引功能可以用于小数据,例如索引几千个文档。然而它有两点限制:

1)需要有足够的内存来存储倒排表,对于搜索引擎来说, 都是G级别数据,特别是当规模不断扩大时 ,我们根本不可能提供这么多的内存。

2)算法是顺序执行,不便于并行处理。

合并法

归并法,即每次将内存中数据写入磁盘时,包括词典在内的所有中间结果信息都被写入磁盘,这样内存所有内容都可以被清空,后续建立索引可以使用全部的定额内存。

合并流程:

1)页面分析,生成临时倒排数据索引A,B,当临时倒排数据索引A,B占满内存后,将内存索引A,B写入临时文件生成临时倒排文件,

2) 对生成的多个临时倒排文件,执行多路归并,输出得到最终的倒排文件(inverted file)。

索引创建过程中的页面分析,特别是中文分词为主要时间开销。

算法的第二步相对很快。

这样创建算法的优化集中在中文分词效率上。

更新策略

有四种:完全重建、再合并策略、原地更新策略以及混合策略。

完全重建策略

完全重建策略:当新增文档到达一定数量,将新增文档和原先的老文档整合,然后利用静态索引创建方法对所有文档重建索引,新索引建立完成后老索引会被遗弃。

此法代价高,但是主流商业搜索引擎一般是采用此方式来维护索引的更新(这句话是书中原话)

再合并策略

再合并策略:当新增文档进入系统,解析文档,之后更新内存中维护的临时索引,文档中出现的每个单词,在其倒排表列表末尾追加倒排表列表项;

一旦临时索引将指定内存消耗光,即进行一次索引合并,这里需要倒排文件里的倒排列表存放顺序已经按照索引单词字典顺序由低到高排序,这样直接顺序扫描合并即可。

其缺点是:因为要生成新的倒排索引文件,所以对老索引中的很多单词,尽管其在倒排列表并未发生任何变化,也需要将其从老索引中取出来并写入新索引中,这样对磁盘消耗是没必要的。

原地更新策略

原地更新策略:试图改进再合并策略,在原地合并倒排表,这需要提前分配一定的空间给未来插入,如果提前分配的空间不够了需要迁移。

实际显示,其索引更新的效率比再合并策略要低。

混合策略

混合策略:出发点是能够结合不同索引更新策略的长处,将不同索引更新策略混合,以形成更高效的方法。

倒排索引基本概念

文档(Document)

一般搜索引擎的处理对象是互联网网页,而文档这个概念要更宽泛些,代表以文本形式存在的存储对象,相比网页来说,涵盖更多种形式,比如Word,PDF,html,XML等不同格式的文件都可以称之为文档。再比如一封邮件,一条短信,一条微博也可以称之为文档。

在本书后续内容,很多情况下会使用文档来表征文本信息。

文档集合(Document Collection)

由若干文档构成的集合称之为文档集合。

比如海量的互联网网页或者说大量的电子邮件都是文档集合的具体例子。

文档编号(Document ID)

在搜索引擎内部,会将文档集合内每个文档赋予一个唯一的内部编号,以此编号来作为这个文档的唯一标识,这样方便内部处理,每个文档的内部编号即称之为“文档编号”,后文有时会用DocID来便捷地代表文档编号。

单词编号(Word ID)

与文档编号类似,搜索引擎内部以唯一的编号来表征某个单词,单词编号可以作为某个单词的唯一表征。

倒排索引(Inverted Index)

倒排索引是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。

单词词典(Lexicon)

搜索引擎的通常索引单位是单词,单词词典是由文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息以及指向“倒排列表”的指针。

倒排列表(PostingList)

倒排列表记载了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词。

倒排文件(Inverted File)

所有单词的倒排列表往往顺序地存储在磁盘的某个文件里,这个文件即被称之为倒排文件,倒排文件是存储倒排索引的物理文件。

关于这些概念之间的关系,通过图2可以比较清晰的看出来。

概念之间的关系

单词词典

单词词典是倒排索引中非常重要的组成部分,它用来维护文档集合中出现过的所有单词的相关信息,同时用来记载某个单词对应的倒排列表在倒排文件中的位置信息。

在支持搜索时,根据用户的查询词,去单词词典里查询,就能够获得相应的倒排列表,并以此作为后续排序的基础。

对于一个规模很大的文档集合来说,可能包含几十万甚至上百万的不同单词,能否快速定位某个单词,这直接影响搜索时的响应速度,所以需要高效的数据结构来对单词词典进行构建和查找,常用的数据结构包括哈希加链表结构和树形词典结构。

哈希加链表

这种词典结构主要由两个部分构成:

主体部分是哈希表,每个哈希表项保存一个指针,指针指向冲突链表,在冲突链表里,相同哈希值的单词形成链表结构。

之所以会有冲突链表,是因为两个不同单词获得相同的哈希值,如果是这样,在哈希方法里被称做是一次冲突,可以将相同哈希值的单词存储在链表里,以供后续查找。

在建立索引的过程中,词典结构也会相应地被构建出来。

比如在解析一个新文档的时候,对于某个在文档中出现的单词T,首先利用哈希函数获得其哈希值,之后根据哈希值对应的哈希表项读取其中保存的指针,就找到了对应的冲突链表。

如果冲突链表里已经存在这个单词,说明单词在之前解析的文档里已经出现过。如果在冲突链表里没有发现这个单词,说明该单词是首次碰到,则将其加入冲突链表里。

通过这种方式,当文档集合内所有文档解析完毕时,相应的词典结构也就建立起来了。

在响应用户查询请求时,其过程与建立词典类似,不同点在于即使词典里没出现过某个单词,也不会添加到词典内。

树形结构

B 树(或者B+树)是另外一种高效查找结构

B 树与哈希方式查找不同,需要字典项能够按照大小排序(数字或者字符序),而哈希方式则无须数据满足此项要求。

B 树形成了层级查找结构,中间节点用于指出一定顺序范围的词典项目存储在哪个子树中,起到根据词典项比较大小进行导航的作用,最底层的叶子节点存储单词的地址信息,根据这个地址就可以提取出单词字符串。

拓展阅读

Hash

B 树

lucence

ES

参考资料

倒排索引

什么是倒排索引?

https://www.elastic.co/guide/cn/elasticsearch/guide/current/inverted-index.html

一文掌握“倒排索引”创建方法

倒排索引/全文搜索基本原理