ha3本身是阿里系针对自己的场景自己研发的搜索引擎平台,也是基于自身的技术积累之上构建的,包括依赖的系统和代码库,都是自研自足的。经历了近10年的发展,也经受了核心场景双十一的考验,已经是一套非常完善成熟的系统,值得学习和研究。 图中为ha3的基本架构,比较简洁,主要分为数据源聚合(俗称 dump)、全量/增量/实时索引构建及在线服务等部分,其中数据源聚合在 tisplus 平台和 Blink 平台完成,核心有以下几个模块:
整个ha3作为一个完善的搜索引擎,方方面面都很涉及,本文主要围绕索引和检索两个过程进行讨论,其他的包括插件、检索语法、配置、运维等方面,不在本文叙述。
索引的作用是为了增加检索速度,ha3索引主要是基于indexlib库构建的。indexlib的索引类型支持 index索引/kv索引/kkv索引/时序索引等。
在我们搜索场景中,主要使用index索引,index索引主要用于基于关键词进行文档检索召回的场景,并对召回的文档基于文档属性进行进一步的过滤、统计、排序等操作。
index索引是基于文档进行的,每个文档都会有一个docid(docid类型为int32_t,所以最多支持20亿文档)。 而每个文档都是由多个field组成,每个field会对应为:主键索引(primary key index)、倒排索引(index)、正排索引(attribute)、摘要(summary)
本章主要针对index索引,介绍其索引的结构和构建的过程,以便我们更好的理解索引的作用,以及后面的检索过程。
上图是整个索引文件列表,针对目录的说明如下:
涉及到的文件如下:
倒排索引核心解决的问题是建立关键词到doc_id的映射, 通过倒排索引,我们可以快速获取相关的文档列表,以及倒排词在文档中的位置词频等信息。 整个检索流程可以参考上图,先通过词典文件查询索引词在索引文件中的位置,在对应位置获取关联的文档列表信息,以及关键词和关键词在文档中的信息。
除了上图存在的内容外,还存在一个截断索引的概念,这是一种辅助索引,对于原始索引中高频词的倒排链,按照某些feature,截取权重较高的文档形成截断索引,提高检索速度。实际应用中,可以更具多个截断方式,生成多条截断链。
此外,在ha3中,倒排索引记录的主要信息如下, 对于不同的索引(NUMBER/TEXT/PACK/EXPACK/PRIMARYKEY64/RANGE/SPATIAL),支持也不一样,具体参看文档:
正排索引主要是简历 doc_id ->field 的映射,主要用于检索到 doc_id 后,可以根据 doc_id 快速获取关键字段的值用来统计、排序、过滤。 正派索引支持的字段类型主要包括单值类型和多值类型:
摘要索引将一片文档对应的信息存储在一起,通过docID可以定位该文档信息的存储位置,从而为用户提供摘要信息的存储获取服务。
摘要索引只有两个文件——data文件和offset文件。 通过offset可以直接定位到data中doc的信息。
从构建的角度来说,索引分为全量索引/增量索引/实时索引。ha3 通过 buildservice 来构建索引,基本的流程如下:
全量和增量索引属于离线索引,离线索引依赖于三类BS内部的worker:
实时索引属于在线索引,构建在在线服务内部,通过RealtimeBuilder模块,直接从中转swift topic(s) 中读取数据(对应图中的实时数据流)、构建索引。可以达到秒级延迟。
索引的加载方式目前只支持mmap加载和blockcache加载 2 种方式:
mmap 加载
通过系统调用mmap将索引文件映射到进程内存地址空间中。加载过程支持mmap lock到内存来保证全内存场景下数据读取完全不读取磁盘数据;也支持mmap非lock场景加载,由操作系统进行内存页缓存管理(采用系统cache方式)。
blockcache 加载
通过blockcache加载模式,可以将索引文件读取的热数据缓存到blockcache中,减少磁盘读取操作。同时数据淘汰策略采用了lru策略,加载和淘汰更加可控(对比mmap非lock的系统cache)。
检索流程更多是在线过程,整体流程参看照爷整理的流程图,如上图。检索过程主要分为2个阶段,一阶段负责文档的召回和排序,二阶段则是summary的信息不全。
对于多集群召回的结果,默认支持去重机制。 整体查询支持一些高级查询:
此外因为属于在线服务,在每个阶段都会有相应的指标监控,具体如下:
qrsSessionLatencyIndependentPhase1 : qrs 创建session -> end session
qrsProcessLatencyIndependentPhase1 : qrs begin session -> end session
searcherProcessLatencyPhase1 : searcher begin search -> end serach
sessionLatencyPhase1 : searcher 创建 session -> end search
afterRunGraphLatency :search图执行完 -> end serach
afterSearchLatency : searcher final sort完 -> end serach
beforeRunGraphLatency : searcher begin search -> 图中第一个节点IsPhaseOneOp开始
beforeSearchLatency : searcher begin search -> 图中seek op开始 multi layer search
extraRankLatency : Ha3SorterOp(final sort)耗时
mergeLatencyPhase1 : qrs result merge, run qrs graph耗时
rankLatency : multi layer search
rerankLatency :rerank 耗时, rankLatency和rerankLatency加起来是seek op 耗时
runGraphLatency :search 图执行耗时