3.这就是搜索引擎:核心技术详解 --- 搜索引擎索引

索引,是实现 单词---文档的具体数据结构。
倒排索引:包含 单词词典,倒排项,倒排文件。
单词词典: 哈希加链表,树形词典结构。
倒排列表,用来记录哪些文档包含了某个单词。
建立索引:
	1.两边文档遍历法
	2.排序法
	3.归并法
动态索引:倒排索引,临时索引和已删除文档列表
索引更新策略:完全重建策略,再合并策略,原地更新策略和混合策略
查询处理机制:一次一文档,一次一单词,跳跃指针
多字段索引:
	1.多索引方式
	2.倒排列表方式
	3.扩展列表方式
短语查询:
	1.位置信息索引
	2.双词索引
	3.短语索引
	4.混合方式
分布式索引:
	1.按文档划分
	2.按单词划分


1.索引基础
	1.单词-文档矩阵
		单词-文档矩阵是表达两者之间所具有的一种包含关系的概念模型。列代表文档,每行代表一个单词。

		搜索引擎的索引其实就是实现单词-文档矩阵的具体数据结构。可以有不同的方式来实现上述概念模型,比如倒排索引,签名文件,后缀树等。但是各项实现数据表明,
	  倒排索引是单词到文档映射关系的最佳实现方式。

	2.倒排索引的基本概念
		文档:一般搜索引擎的处理对象是互联网网页,而文档这个概念更泛一些,代表以文本形式存在的存储对象。
		文档集合:由若干文档构成的集合称为文档集合。
		文档编号:在搜索引擎内部,会为文档集合内的每一个文档赋予一个唯一的内部编号。
		单词编号:与文档编号相似,搜素引擎内部以唯一的编号来表征某个单词
		倒排索引:倒排索引是实现单词-文档矩阵的一种具体存储形式。通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:单词词典和
	  倒排文件。
	  	单词词典:搜索引擎通常的索引单位是单词,单词词典是由文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息及指向倒排索引列表的指针。
	  	倒排列表:倒排列表记载了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项。根据倒排列表,即可获知哪些文档包含某个单词。
	    倒排文件:所有单词的倒排列表往往顺序的存储在磁盘的某个文件里,这个文件即被称为倒排文件,倒排文件是存储倒排索引的物理文件。

	3.倒排索引简单实例
	  (单词ID,单词,文档频率,倒排列表(文档id;词频;<位置>))
		有了这个索引系统,搜索引擎可以很方便的响应用户的查询,比如输入"facebook",搜索系统查找倒排索引,从中可以读出包含这个单词的文档,,这些文档就是提供给用户的搜索结果,
	  而利用单词频率信息,文档频率信息即可对这些候选搜索结果进行排序,计算文档和查询的相似性,按照相似性得分由高到低排序输出,此即为搜索系统的部门内部流程。


2.单词词典
	单词词典是倒排索引中很重要的组成部分,它用来维护文档集合中出现过的所有单词的相关信息,同时用来记载某个单词对应的倒排列表在倒排文件中的位置信息。在支持搜索时,根据用户的
  查询词,去单词词典里查询,就能够获得相应的倒排列表,并以此作为后续排序的基础。
  	对于一个规模很大的文档集合来说,可能包含几十万甚至上百万的不同单词,能够快速定位某个单词,这直接影响搜索时的响应速度,所以需要高效的数据结构来对单词此地啊你进行构建和
  查找,常用的数据结构包括哈希加链表结构和树形词典结构。	  

  1.哈希加链表
  	这种词典结构主要由两个部分组成,主体部分是哈希表,每个哈希表保存一个指针,指针指向冲突链表,在冲突链表里面,相同的哈希值的单词形成链表结构。之所以会有冲突链表,是因为两个
  不同单词获得的相同的哈希值,如果是这样,在哈希方法里称作是一次冲突,可以将相同哈希值的单词存储在链表里,以供后续查找。
  	对于某个在文档中出现的单词T,首先利用哈希函数获得其哈希值,之后根据哈希值对应的哈希表读取其中保存的指针,就找到了对应的冲突链表。如果冲突链表里已经存在这个单词,说明单词在
  之前解析的文档中出现过。如果在冲突链表里没有发现这个单词,说明单词是首次碰到,则将其加入冲突链表中。通过这种方式,当文档集合内所有的文档解析完毕后,相应的词典结构也就建立起来了。
  	在响应用户查询请求时,其过程与建立词典类似,不同点在于即使词典里没有出现过某个单词,也不会添加到词典内。

  2.树形结构
  	B树(或者B+树)是另外一种高效的查找结构。与哈希方式不同,需要字典能够按照大小顺序(数字或者字符序),而哈希方式则无需数据满足此要求。
  	B树形成了层级查找结构,中间节点用于指出一定顺序范围的词典项目存储在哪个子树中,起到根据词典比较大小进行导航的作用,最底层的叶子节点存储单词的地址信息,根据这个地址就可以提取出
  单词字符串。


3.倒排列表
	倒排列表用来记录有哪些文档包含了某个单词。一般在文档集合里会有很多文档包含某个单词,每个文档会记录文档编号(DocID),单词在这个文档中出现的次数(TF)及单词在文档中哪些位置出现过的
  等信息,这样与一个文档相关的信息被称作倒排索引项,包含这个单词的一系列倒排索引项形成了列表结构,这就是某个单词对应的倒排列表。
  	在实际的搜索引擎中,并不存储倒排索引项中的实际文档编号,而是取而代之以文档编号差值(D-Gap)。文档编号差值是倒排列表中相邻两个倒排索引项文档编号的差值。之所以要对文档编号进行差值计算,
  主要原因是为了更好的对数据进行压缩,原始文档编号一般都是大数值,通过差值计算,将有效的将大数值转换为小数值,有助于增加数据的压缩率。


4.建立索引
	1.两边文档遍历法
		顾名思义,此方法需要对文档集合进行扫描两边。此方法完全是在内存里完成索引的创建过程的,而另外两种方法则是通过内存和磁盘互相配合来完成索引建立任务的。

		第一遍文档遍历
			第一遍遍历的时候,该方法并没有立即开始创建索引,而是收集一些全局的统计信息。比如文档集包含的文档个数N,文档集合包含的不同单词个数M,每个单词在
		  多少文档内出现过的信息DF。将所有单词对应的DF值全部相加,就可以知道建立最终索引所需的内存大小是多少,因为一个单词对应的DF值如果是10,说明有10个文档
		  包含这个单词,那么这个单词对应的倒排列表应该包含10项内容,每一项记载某个文档的文档id和单词在该文档对应的出现次数TF。
		  	在获得了以上3类信息后,就可以知道最终索引的大小,于是在内存中分配足够大的空间,用来存储倒排索引的内容。

		第二遍文档遍历
			在第二遍扫描的时候,开始真正建立每个单词的倒排列表信息,即对某个单词而言,获得包含这个单词的每个文档的文档id,以及这个单词在文档中出现的次数TF,这样就
		  可以不断的填充第一遍扫码所分配的内存空间。当第二遍扫描结束的时候,分配的内存空间正好被填充满,而这个单词用指针指向的内存区域'片段',其实位置和终止位置
		  之间的数据就是这个单词对应的倒排列表。
		  	经过2遍扫描完成索引建立后,即可将内存的倒排列表和词典信息写入磁盘,这样就完成了建立索引的过程。从另外一个角度看,在建立索引的过程中,从磁盘读取文档
		  并解析文档基本是最消耗时间的一个步骤,而2遍扫描因为要对文档集合进行扫描2遍,所以从速度上并不占优。

    2.排序法
    	两遍遍历法在建立索引过程中,对内存的消耗要求比较高,不同的文档集合包含文档数量大小不同,所需的内存大小是不确定的。当文档集合非常大的时候,可能因为内存不够,
      导致无法创建索引。排序法对此作出了改进,该方法在建立索引的过程中,始终在内存中分配固定大小的空间,用来存放磁盘信息和索引的中间结果,当分配的空间被消耗光的时候,
      把中间结果写入到磁盘,清空内存里的中间结果所占空间,用作下一轮存放索引中间结果的存储区。这种方法由于只需要固定大小的内存,所以可以对任意大小的文档集合建立索引。

      	中间结果内存排序
      		读入文档后,对文档进行编号,赋予唯一的文档id,并对文档内容进行解析。对于文档中出现的单词,通过查询词典将单词转换为对应的单词id,如果词典中没有这个单词,说明
      	  是第一次碰到,则赋予单词以唯一的单词id并插入词典。在完成了由单词映射为单词id的过程中,就可以对该文档内的每个单词建立一个(单词id,文档id,单词频率)三元组,这个
      	  三元组就是单词对应文档的倒排列表项,将这个三元组追加进中间结果存储区域末尾。如果文档内的所有单词都经过如果处理,形成三元组序列的形式,则该文档被处理完成,开始
      	  依次处理下一个文档。
      	  	随着新的文档不断的被处理完成,存储三元组集合的中间结果所占用的内存会越来越大,词典包含的新单词也越来越多,当分配的内存定额被占满时,该方法对三元组中间结果进行
      	  排序。排序的原则是:主键是单词id,即首先要按照单词id有小到大排序;次键是文档id,即在相同单词id的情况下,按照文档id有小到大排序。通过以上方式,三元组变为有序形式。
      	  为了腾出内存,将排序好的三元组写入到磁盘临时文件中,这样就腾出内存来进行后续文档的处理。这里需要注意的是:在建立索引的过程中,词典是一直存储在内存中的,每次清空
      	  内存只是将中间结果写入到磁盘。随着处理文档的增加,词典占用的内存会增加,由于内存分配是固定大小,而词典占用内存越来越大,也就说,越往后,可用来存储三元组的空间是
      	  越来越少的。
      	  	之所以要对中间结果进行排序,主要是为了方便后续的处理。因为每一轮处理都会在磁盘产生一个对应的中间结果文件,当所有文档处理完成后,在磁盘中会有多个中间结果文件,
      	  为了产生最终的索引,需要将这些中间结果文件合并。

      	合并中间结果
      		在合并中间结果的过程中,系统为每个中间结果文件在内存中开辟一个数据缓冲区,用来存放文件的部分数据。因为在形成中间结果文件前,已经按照单词id和文件id进行了排序。
      	  所以进入缓冲区的数据已经是有序的。在合并过程中,将不同缓冲区中包含的同一个单词id的三元组进行合并,如果某个单词id的所有三元组全部合并完成后,说明这个单词的倒排列表
      	  已经构建完成,则将其写入最终索引中,同时将各个缓冲区中对应这个单词id的三元组清空,这样缓冲区就可以继续从中间结果文件中读入后续的三元组来进行下一个单词的三元组合并。
      	  当所有中间结果文件都依次被读入缓冲区,在合并完成后,就形成了最终的索引文件。

    3.归并法
    	排序法分配固定大小内存来建立索引,所以无论要建立索引的文档集合有多大,都可以通过这种方法完成。但是如上所述,在分配的内存定额被消耗光时,排序法只是将中间结果写入磁盘,
      而词典信息一直在内存中进行维护,随着处理的文档越来越多,词典包含的词典项越来越多,所以占用内存越来越大,导致后期中间结果可用内存越来越少。归并发对此作出了改进,即每次将
      内存中数据写入磁盘时,包括词典在内的所有中间结果信息都被写入磁盘,这样内存所有的内容都可以被清空,后续建立索引可以使用全部的定额内存。
      	归并发大体流程,也分两个阶段,首先在内存里维护中间结果,当内存占满后,将内存数据写入磁盘临时文件,第二阶段对临时文件进行归并并形成最终索引。

      	跟排序法的差异:
      		首先,排序法在内存中存放的是词典信息和三元组信息,在建立索引的过程中,词典和三元组数据并没有直接联系,词典只是为了将单词映射为单词id。而归并法则是在内存中建立
      	  一个完整的内存索引结构,相当于对目前处理的文档子集进行单独在内存中建立起了一整套排序索引,和最终索引比,其结构和形式是相同的,区别只是这个索引只是部分文档的索引而
      	  非全部文档的索引。
      	  	其次,在将中间结果写入磁盘临时文件时,归并法会将整个内存的倒排索引写入临时文件。
      	  	在最后的临时文件合并为最终索引的过程中,两者也有差异。排序法因为保存的是有序三元组信息,所以再合并时,是对同一单词的三元组依次进行合并;而归并法的临时文件则是每个
      	  单词对应的部分排序列表,所以在合并时针对每个单词的排序列表进行合并,形成这个单词的最终倒排列表。另外,归并法在最后的合并过程中形成最终的词典信息。

5.动态索引
	如果搜索引擎需要处理的文档集合是静态集合,那么在索引建立好之后,就可以一直用建好的索引响应用户的查询请求。但是,在真实环境中,搜索引擎需要处理的文档集合往往是动态集合,
  即在建立好初始的索引之后,后续不段有新的文档进入系统,同时原有的文档集合内有些文档可能被删除或者内容被更改。
  	索引系统如何能够做到实时反应这种变化呢?动态索引可以实现这种实时性要求。在这种索引中,有3个关键的索引结构:倒排索引,临时索引和已删除文档列表。
  	倒排索引就是对初始文档集合建立好的索引结构,一般单词词典存储在内存,对应的倒排索引存储在磁盘文件中。临时索引是在内存中实时建立的倒排索引,其结构和前述的倒排索引是一样的,
  区别在于词典和倒排列表都在内存中存储。当有新文档进入系统的时候,实时解析文档并将其追加进这个临时索引结构中。已删除文档列表则用来存储已被删除文档的相应文档id,形成一个文档
  id列表。这里需要注意的是:当一篇文档内容被更改,可以被认为是旧文档先被删除,之后向系统内增加一篇新的文档,通过这种间接的方式实现对内存更改的支持。
  	当系统发现有新文档进入时,立即将其加入临时索引中。有文档被删除时,则将其加入删除文档队列。文档被修改时,则将原先文档放入删除队列,解析后更改的文档内容,并将其加入临时
  索引中。通过这种方式满足实时性的要求。
  	如果用户输入查询请求,则搜索引擎同时从倒排索引和临时索引中读取用户查询单词的倒排列表,找到包含用户查询的文档集合,并对两个结果进行合并,之后利用删除文档列表进行过滤,
  将搜索结果中那些已经被删除的文档从结果中过滤,形成最终的搜索结果,并返回给用户。这样就能够实现动态环境下的准实时搜索功能。


6.索引更新策略
	动态索引通过在内存中维护临时索引,可以实现对动态文档和实时搜索的支持。但是服务器内存总是有限的,随着新加入系统的文档越来越多,临时索引消耗的内存也会随之增加。
  随着新加入系统的文档越来越多,临时索引消耗的内存也会随着增加。当最初分配的内存将被使用完时,要考虑将临时索引的内容更新到磁盘索引中,以释放内存空间来容纳后续的新进
  文档,此时要考虑合理有效的索引更新策略。
  	常用的索引更新策略有4种:完全重建策略,再合并策略,原地更新策略及混合策略。

  	1.完全重建策略
  		完全重建策略是一个相当直观的方法,当新增文档到一个数量,将新增文档和原先的老文档进行合并,然后利用前述章节提到的建立索引的方式,对所有文档重新建立索引。新索引建立
  	  完成后,老的索引被遗弃释放,之后对用户查询的响应完全由新的索引负责。
  	  	因为重建索引需要较长时间,在进行索引重建的过程中,内容仍然需要维护老的索引,来对用户的查询做出响应。只有当新索引完全建立完成后,才能释放老的索引。
  	  	这种重建策略比较适合小的文档集合,因为完全重建索引的代价比较高,但是目前主流商业搜索引擎一般是采用此方式来维护索引的更新的,这与互联网本身的特性有关。

  	2.再合并策略
  		有新增文档进入搜索系统时,搜索系统在内存维护临时倒排索引来记录其信息,当新增文档到达一定数量,或者指定大小的内存被消耗完,则把临时索引和老文档的倒排索引进行合并,
  	  以生成新的索引。
  	  	在实际的搜索系统中,再合并策略按照以下步骤进行索引内容的更新。
  	  	1.当新增文档进入系统,解析文档,之后更新内存中维护的临时索引,文档中出现的每个单词,在其倒排列表末尾追加倒排列表项,这个临时索引可称为增量索引。
  	  	2.一旦增量索引将指定的内存消耗光,此时需要进行一次索引合并,即增量索引和老的倒排索引内容进行合并。

  	3.原地更新策略
  		原地更新策略的基本出发点,可以认为是试图改进再合并策略的缺点。也就是说,在索引更新过程中,如果老索引的倒排表没有变化,可以不需要读取这些信息,而只对那些倒排列表
  	  变化的单词进行处理。甚至希望能更进一步:即使老索引的倒排列表发生变化,是否可以只在其末尾进行追加操作,而不需要读取原先的倒排列表并重写到磁盘的另一个位置?如果能达到
  	  这个目标,明显可以大量减少磁盘读/写操作,提升系统执行效率。
  	  	为了达到上述目标,原地更新策略在索引合并时,并不生成新的索引文件,而是直接在原先老的索引文件里追加操作,将增量索引单词的倒排列表项追加到老索引相应位置的末尾,这样就
  	  可以达到上述目标,即只更新增量索引里出现的单词相关的信息,其他单词相关信息不做变动。

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


7.查询处理
	目前有2种常见的查询处理机制:一种被称作一次一文档方式,另外一种别称作一次一单词方式。除了两种基本的查询处理过程,还介绍了跳跃指针这种查询优化过程。

	1.一次一文档 (先纵向再横向)
		搜索引擎接收到用户的查询后,首先将两个单词的倒排列表从磁盘读入内存。所谓的一次一文档,就是以倒排列表中包含的文档为单位,每次将其中某个文档与查询
	  的最终相似性得分计算完毕,然后开始计算另外一个文档的最终得分,直到所有文档的得分都计算完毕为止。

	2.一次一单词 (先横向再纵向)
		一次一单词的计算过程与一次一文档不同,一次一文档可以直观理解为在单词一文档矩阵中,以文档为单位,纵向进行分数累计,之后移动到后续文档接着计算,即
	  计算过程是'先纵向再横向';而一次一单词则采取的是'先横向 再纵向'的方式,即首先将某个单词对应的倒排列表中的每个文档id都计算一个部分相似性得分,也就是
	  说,在单词---文档矩阵中首先进行横向移动,在计算完毕某个单词倒排列表中包含的所有文档后,接着计算下一个单词倒排列表中包含的文档id,即进行纵向计算,如果
	  发现某个文档id已经有了得分,则在原先得分基础上进行累加。当所有单词都处理完毕后,每个文档最终的相似性得分计算结束,之后按照大小排序,输出得分最高的k个
	  文档作为搜索结果。

	3.跳跃指针
		如果用户输入的查询包含多个查询词,搜索引擎一般默认是采取与逻辑来判断文档是否满足要求,即要求相关网页必须包含所有的查询词。很明显,对应于这种
	  应用场景,一次一文档的查询处理方式是比较合适的。对于多词查询,找到包含所有查询词的文档,等价于求查询词对应的倒排列表的交集。
	  	跳跃指针的基本思想是将一个倒排列表数据化整为零,切分为若干个固定大小的数据块,一个数据块作为一组,对于每个数据组,增加元信息来记录关于这个块的
	  一些信息,这样即使是面对压缩后的倒排列表,在进行倒排列表合并的时候也能有两个好处:一个好处是无需解压缩所有的倒排列表项,只解压部分数据即可;另外
	  一个好处是无需比较任意两个文档id,通过这种方式有效节省了计算资源和存储资源。



8.多字段索引
	在很多实际的搜索应用领域,搜索引擎所要处理的文档是有一定结构的,即文档包含明确区分的多个字段。比如'发件人','收件人','标题'等。

	1.多索引方式
		多索引方式针对每个不同的字段,分别建立一个索引,当用户指定某个字段作为搜索范围时,可以从相应的索引里提取结果。
	2.倒排列表方式
		为了能够支持对指定字段的搜索,也可以将字段信息存储在某个关键词对应的倒排列表内,在倒排列表中每个文档索引项信息的末尾追加字段信息。
	3.扩展列表方式
		扩展列表方式是实际中应用得比较多的支持多字段索引的方法。这个方法为每个字段建立一个列表,这个列表记载了每个文档这个字段对应出现的位置。


9.短语查询
	短语是很常见的现象,几个经常连在一起被使用的单词就构成了短语,比如'你懂的',短语强调单词之间的顺序,有时尽管是相同的单词,顺序颠倒后会产生完全不一样的含义。
	搜索引擎如何能够支持短语呢?如果单词的倒排列表只存储文档编号和单词词频信息,其保留的信息是不足以支持短语搜索的,因为单词之间的顺序关系没有保留。搜索引擎支持
  短语查询,本质问题是如何在索引中维护单词之间的顺序关系或者位置信息。比较常见的支持短语查询的技术包括:位置信息索引,双词索引及短语索引这3类。

	1.位置信息索引
	2.双词索引
	3.短语索引
	4.混合方式

10.分布式索引
	当搜索引擎需要处理的文档集合数量非常庞大的时候,靠单机往往难以承当如此重任,此时需要考虑分布式解决方案。即每台机器维护整个索引的一部分,由多台机器协作完成索引的
  建立和对查询的响应。至于多台机器如何分工协作,目前常用的分布式索引包含两个方案:按文档对索引划分和按单词对索引划分。

	1.按文档划分
	2.按单词划分
	3.两种方式比较

 

搜索引擎索引:

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值