建立倒排索引的过程称为索引构建,负责构建索引的程序或计算机称为索引器。操作系统往往以数据块为单位进行读写,因此从磁盘读取一个字节和读一个数据块所耗费的时间可能一样多。采用一种高效的解压缩算法然后读磁盘压缩数据再解压所花的时间往往会比直接读取为压缩数据的时间少。

基于块的排序索引方法(blocked sort-based indexing)(BSBI):

      对于很多大型语料库来说,即使使用压缩算法压缩后的倒排记录表也不可能全部加载到内存中。由于内存的不足,我们必须使用基于磁盘的外部排序算法。为了达到可以接受的速度,对该算法的核心要求是:在排序时尽量减少磁盘随机寻道的次数。基于块的排序索引算法就是一种解决方案。其基本步骤:

  1. 将文档集分割成几个大小相等的部分
  2. 将每个部分的词项ID-文档ID对排序
  3. 将中间产生的临时排序结果存放到磁盘中
  4. 将所有中间文档合并成最终的索引

      该算法将文档解析称词项ID-文档ID对,并在内存中进行处理,直到累积至放满一个固定大小的块空间为止,我们选用合适大小的块,使之能方便地加载到内存并允许在内存中快速排序,排序后的块转换成倒排索引格式后写入磁盘。看完这部分我第一个反应是看过的面经:教你如何迅速秒杀掉:99%的海量数据处理面试题。可以看到也是采用了分而治之的思想,其实很多面试常考的问题在实际生产中也有很大的用处。

内存式单遍扫描索引构建方法(single-pass in-memory indexing)(SPIMI):

      基于块的排序索引方法需要将词项映射成其ID,这需要的数据结构对于大规模的文档集来说会大到内存中难以存放。内存式单遍扫描索引算法(SPIMI)更具扩展性。SPIMI算法使用词项而不是其ID,它将每个块的词典写入磁盘,对于下一个块则采用新的词典,只要硬盘空间足够大,SPIMI就能够索引任何大小的文档集。具体实施时算法逐一处理词条流中每个词项,如果词项是第一次出现,那么将之加入词典(最好采用哈希表实现),同时建立一个新的倒排记录表;如果该词项不是第一次出现则直接返回其倒排记录表。

      可以看到SPIMI算法不是一开始就整理出所有词项ID-文档ID并排序,而是动态的创建倒排记录表或在记录表追加新的文档ID。不需要排序带来的好处就是处理速度更快。词项与倒排记录表直接建立归属关系,不需要词项ID,更节省内存。扫描直至内存不足时对所有词项进行一次排序即可。

      并且SPIMI算法有一个重要的第三方组件:压缩。使用压缩技术后,倒排记录表与词项都可以在磁盘上压缩存储,进一步提高算法效率。

分布式索引构建方法(distributed indexing):

      实际当中,文档集通常都很大,在单台计算机上很难高效地构建索引,往往需要大规模的计算机集群(cluster),使用分布式索引构建。其索引结果也是分布式的,往往是按照词项或文档进行分割后的索引生成。对于大部分大型搜索引擎来说,更倾向于采用基于文档分割的索引。本节主要介绍基于词项分割的分布式索引构建。

      本节中作者介绍了一种叫MapReduce的分布式索引构建方法。刚好笔者之前看过Google 2003年发表的 GFS 论文。其实就是介绍了GFS的架构,不过讲的非常简略,感兴趣可以到链接中看下原文。