了解搜索架构

如果你想要深入的了解和熟悉搜索引擎,我可以推荐一本书:
这就是搜索引擎

作者:张俊林
出版社:电子工业出版社
ISBN: 9787121148651

从本人了解到了知识储备而言,搜索引擎技术在工业界似乎变化不大,即使过去了很多年,整体的思想并没有发生很大的变化,来来回回都是这么个用法,召回,排序,求交,整体的信息检索水平并没有像软件工程一样分化出例如诸多的SOA,Mesh架构,也没有诞生出MVC,DDD等特定的软件设计模式,搜索引擎更多的变化在于一些性能上吗的优化,而贴合业务更做出改变。虽然本人学识并不丰富,但是也可以感觉到落后很多年了。

搜索流程

这是一般搜索从离线到在线的整条数据流处理流程:

类似于百度,Google等搜索服务商,整体来说都是这样的流程。

但是搜一搜比较特殊,搜一搜的信息来源并不需要从网络爬取,而是自行产生的,比如公众号,小程序,这些数据来源都比较规范,而且一些基本属性,都是必须有的,这让整个搜索架构在建立索引的时候,会减少很多的功夫,所以相对于网络爬虫去爬去数据,要减少不少不必要的流程。

目前六组主要负责的是富展示模块,主要是业务端,商业变现的内容。

先看整个搜索架构,

搜一搜架构中搜索常用简称释义:

  • 敏感数据
  • 敏感数据
  • 敏感数据
  • 敏感数据
  • 敏感数据
  • 敏感数据
  • 敏感数据
  • 敏感数据

整体从逻辑上也分为五层,如下:

虽然整体架构看起来非常复杂,但是总的来说还是在干这些事情:

(离线)建立索引->召回求交排序->展示

现在结合本人看到的知识,一步步推导中间的过程,中途可能还会出现不少的错误,望评论区指正

首先建立索引,这是最初步的过程,比如说我有很多的公众号文章和小程序数据,这里的每一个数据都是doc,doc_id就是每个doc的唯一标识,这些数据都是未经过处理的,没有任何意义的数据。这个时候我们肯定是需要先进行一步粗处理,将每个文档中的单词,都逐个分离出来,先变成一个正排索引:

为什么不一开始就建立倒排呢?本人理解是一个将原doc经过粗处理变成更加适合检索的doc类型,这样系统就不用存储原doc,第二个是在进行摘要检索的时候更加方便。

然后倒排索引就更加明确了:

但是要注意的是,这只是一个抽象的索引,实际上搜一搜的索引非常复杂,会涉及到诸多方面的知识和要求,一个索引不仅仅这么简单,可以参考这个:

在建立索引的过程中,还会涉及到很多的知识,这里再详细描述建立正排和倒排的过程

建立正排其实

六要素
不论索引结构如何改变,其核心依然是以下六类数据:

  1. Term词典
    提供Term到Term对应倒排链位置的查询功能,常规实现如hash map,二分查找(有序数组)
  2. 倒排索引
    保存Term->文档id列表数据,通常实现为有序数组,实际上可以有多种实现形式
  3. Payload
    Term或者文档的有效载荷,即每个Term/文档携带的额外数据,例如Term Payload通常存放Term对应文档的权重,Doc Payload则是文档的特征数据,定位是召回阶段可用的特征数据
  4. Forward
    文档正排数据,定位为存放文档在粗排打分阶段时需要访问的特征数据
  5. PosOffset
    各个Term在文档中各个域的精确位置偏移信息(原则上Pos数据也属于正排数据,同样是需要在粗排打分阶段才可访问)
  6. Abstract
    文档摘要数据,通常用于存放文档富展现数据

接着是这些doc的存储问题,在一个海量数据的数据中,这些doc也必定是分布式存储的,这些数据会被分发到一个个的分片中,分片数是固定的,但是每个分片的节点数是不固定的,一般是多个分片对应一个节点。比如说,doc_id 114514,假设分片是100个,那么该doc会进入分片14,但是整个分片群中节点只有10个。如果我的节点扩展到20个,分片也会随着节点扩张也迁移。

既然说了doc的存储,那么索引呢?其实常见的索引比如FOB,GOB,这些索引的存储一般不在磁盘中,而是在内存中,这里会采用一个LSM的方式去加速存储和当访问。

GOB全量索引库 FOB实时索引库

这里可以举一个例子去理解,比如说我们公众号每产生一个文章,就可能产生多个GOB,但是文章的更新程度其实一般不会太频繁,那如果更新了,希望现网可快速也进行更新,就产生了FOB,GOB的更新是一批一批,FOB的更新是实时的,每次GOB更新的时候都会覆盖掉所有的FOB。这个关系就像是cache和磁盘的关系一样,每次更新,先更新cache,每次落库,cache就清空。这个也是很好理解的。那么为什么不用FOB去更新GOB呢?个人感觉是这样会在现网产生很大的时延和抖动,因为会产生很大的计算量,而分别更新的话,GOB建立是离线的,只需要上线替换就好了,几乎没有计算量,综合下来还是这种方式更好。

(未完待续。。。。。。)