刚工作满一周年,从一年前从零开始接触搜索系统[2],到现在初步对搜索系统有所认识,感觉还是积累了一些也许可以拿来分享的内容。总的来说,笔者认为搜索系统就是由各种打分与条件规则组合成的复杂系统,本文也会尽可能对此进行解释。在前文[1]中,我初步对搜索业务进行了简单的介绍,从中提到了
商业搜索引擎本身不带来太多盈利,但是成功的商业搜索引擎将带来巨大的流量,而流量变现就是它最主要的盈利方式,流量变现最主要的手段就是广告推广
Fig 1. 用户借助检索词,在搜索系统上直接表明了用户需求,因此广告系统可以根据广告的相关程度,广告质量以及广告竞价,在搜索系统自然结果的基础上插入广告,至于哪些广告才能插入哪些位置,这个由广告系统决定,搜索系统一般只会发送广告请求(以及部分用户检索相关信息)给广告服务器请求广告插入。
如Fig 1. 所示,通过竞价广告的形式,可以将广告主的广告插入到对应的自然结果中,借助搜索系统的竞价广告,通常大型商业搜索公司都可以赚得盆满钵满。广告系统会处理从不同业务线发送的广告请求,并为此提供广告服务,这个系统同样非常复杂,包括有复杂的资源召回,广告质量评估,竞价策略,内容投放策略,流量预估,CTR预估等,在此不展开介绍了。
总而言之,巨大的流量是商业搜索引擎盈利的前提,而搜索引擎只有能够满足用户方方面面对于信息的需求,才能在激烈的市场中分到一杯羹。这一点并不简单,用户的信息需求方方面面,在搜索引擎中经常见到以下几类需求:
不同需求对于资源的时效性和权威性需求强度是不同的,而有些比较高频并且和公司战略方向一致的大型垂类需求(比如视频,图片,汽车,财经等)可能会独立拉出一个团队,负责该品类需求下的内容排序。用户在主页上搜索的某次检索,将会触发需求检测,从而判断是否会触发某类垂类需求的排序。如Fig 2. 所示,当用户搜索一个需求,比如“折纸的做法”的时候,搜索引擎判断其有视频和图片的需求,因此触发了视频排序和图片排序模块,分别进行了视频和图片排序然后作为一个卡片,与其他网页结果参与主页排序后呈现出来。同样的,对于query “白兔糖”,系统判断其具有知识需求和视频需求,因此出来了百科卡片与视频卡片。
Fig 2. 在主页上搜索某个需求“折纸的做法”,头条搜索判断其有视频需求和图片需求,因此弹出了视频和图片的需求卡片,与其他网页自然结果一起参与主页排序。
而对于检索词“白兔糖”,系统判断其有知识需求和视频需求。垂类卡片与其他网页结果在主页上互相竞争,互相pk排序位置,而排序的依据会考虑结果的相关性,质量性,权威性,时效性等等。由于主页搜索上用户的需求各类各样,query分析会提取出用户的需求,对于某些垂类强需的query(比如query里面写明了视频需求的,“秒速五厘米 视频高清”),将会优先把视频卡片扶持到靠前位置(比如top 4)。
在这个综合搜索的体系下,我们需要query分析能够对用户需求进行判断,通常会考虑对query进行需求分类,并且可能是多层级的需求分类,并由此收集数据建立模型(需求判断模型)。同时,还需要对query的需求强度进行判断,建立需求强度模型,由此判断某个垂类卡片是否应该在主页进行扶持或者打压(当该垂类排序结果都不尽人意的时候,将会进行打压)。垂类卡片内的排序结果通常是由该垂类业务团队负责的,该团队可能需要负责该垂类资源的检索库建库、召回、粗排、精排、混排等全链路,并且在不同阶段都可能会需要考虑相关性,质量性,权威性时效性等,而这就需要各种各样的模型产生各类型的打分,同时伴随着各类型的过滤、打压、调权策略介入了。
信息检索的基础是信息的建库,根据信息的质量高低,业务类别等多个维度,建库方式可以多种多样,比如按照数据的时效,质量高低等,建立类似于漏斗形的库层。如Fig 3. 所示,质量越高得到库层往往数据数量越少,也集中着最为高频的用户需求资源,而相反的,海量的低质量资源库层可能集中着用户的长尾需求,虽然这些需求并不常见,但是这些长尾需求严重影响了用户体验,能否满足这些长尾需求将是在商业搜索市场中争抢分额的关键因素。
Fig 3. 通常搜索引擎会将检索到的资源进行分层,在每次检索时,首先查找数量较少质量较高的库层,如果没有检索到足够满意的结果再穿透到下一层的库层。
在同一个库层中,同样可以按照资源的不同垂类需求,进行库种建库,如Fig 4. 所示,至于对哪些垂类进行库种建库,取决于公司的战略规划,以及对某类垂类的资源倾向。
Fig 4. 在同一个库层里面,可以在建库阶段按照不同的业务垂类进行库种建库。
对于有些资源,比如时政敏感类,色情敏感类,恶俗低质类,诈骗类资源,可以在建库端就提前过滤掉,以避免浪费储存,并且减少政策风险。为了对这些恶意低质量资源进行判断,需要建立不同的模型进行资源分类,这里统称为低质资源分类模型。我们在建库的时候将待建库资源进行模型打分,如果被判断为恶意低质内容,就予以过滤。在建库的时候,由于可以见到所有索引库资源,此时可以对这些建库资源进行某些基础正排特征的打分刷库,此处的正排打分可以在召回和排序阶段使用。不同的库种依赖的正排特征可能不同,需要根据不同的策略进行独立的正排特征刷库。
有了索引库,对于某次检索,就可以从中召回出需要的内容了。如Fig 5. 所示,召回阶段通常都会采用多队列召回,笔者认为这一点设计主要基于几点考虑:
- 用户的query可能包含有多种层次的需求,比如搜索“白鹿原”,用户需要的既可能是书籍,也可能是影视作品,搜索“苹果”,既可能是食物苹果,有可能是苹果科技公司,通过采用不同召回队列进行召回,可以为排序模块降低排序压力。
- 用户的query并不一定能完美地表达自己的需求,极可能需要进行query分析,query分析分为很多维度,包括query扩展,query纠错,同义词近义词扩展等等,如果将不同的query分析结果都用同一个召回队列进行召回显然是不合理的。
- 向量化召回(也称之为语义召回,ANN召回)通常和基于term match的召回结果差别较大,如果都用同一个召回队列,很多需要特别对向量化召回进行的策略将难以进行。
- 时效性结果通常也会独立一个召回队列进行召回,时效性结果需要根据query需求进行排序,如果都用一个召回队列,那么时效性结果可能会竞争不赢其他结果(这些结果可能相关性,质量性较好,但是时效差),因此拉出一个单独的时效队列进行召回会方便后续的处理。
- 方便后续的需求迭代,如果对于某类型的query,突然有新的产品需求,希望把某类的资源排序上去,但是当前的召回结果里面很少该类资源,那么就可以考虑通过新增一个召回队列进行该类资源的召回,这样也会方便后续的排序操作。
- 方便后续的策略迭代,相同召回队列的结果通常都具有某类共性,适合采用类似的策略进行队列内去重,调权,过滤,打压等等,而不同的召回队列之间差别比较大,会在多队列的组合PK阶段进行结果汇总。通过多队列召回的设计,我们通常只需要对某个队列进行策略迭代,而不用过于担心其影响了其他队列的结果,因此迭代的影响是可控的。
Fig 5. 在召回阶段,有多个召回队列从索引库里面进行召回,在经历各队列间的去重,排序后进行多队列间的组合PK得到最终组合结果,对组合结果进行去重得到最终召回结果。
由于召回的结果大部分基于term match,或者语义匹配进行召回,召回结果中容易出现相同的内容,显然用户也不希望出来的结果里面都是相同的,或者是雷同的,因此结果去重是必须进行的。最简单直接的去重策略就是判断资源标题的相同程度,对于图片搜索或者视频搜索而言,内容雷同而标题不同的情况(转载内容,盗资源的情况,通过简单裁剪,镜像翻转,添加水印转载)也时有发生,因此还需要判断图片/视频的内容相似程度,常见的有视频指纹对比,封面图对比,预览图对比等。
待各个召回队列完成了去重,就可以进行排序了。排序通常按照特征粒度,资源数量分为粗排和精排。粗排中,通常资源数量较多(几百到一千级别),因此采用的特征都是较为轻量级的,粗排阶段同样需要考虑相关性,质量性等多个维度的综合排序,而一旦涉及到相关性,就需要引入当前用户的检索Query。这意味着通常需要在线计算Query和文档Doc的相关性,由于在线计算资源和延迟(latency)的限制,通常都会采用双塔模型进行相关性建模。如Fig 6. 所示,相关性双塔模型通常分为Query塔和Doc塔,其中Doc塔由于输入和用户Query无关,可以进行离线Embedding特征刷库,记为 ,而Query塔由于受到实时用户检索的影响,难以离线刷库解决,因此需要在线计算Embedding特征,记为。在线时,在计算完Query的Embedding特征后,通过余弦相似度计算Query和Doc之间的相关性,如式子(1-1)所示。
余弦相似度表示了向量和向量的夹角的余弦值,其越大表示越相关。这块有许多优化手段,首先双塔模型虽然强大,但是由于Query和Doc不能交互(参考Transformer),某些细粒度的相关性匹配将无法建模。难以建模细粒度和长尾资源,这一点其实并不难理解,参考笔者之前博文[4],Doc塔需要提前进行刷库,在线上应用时候采用相似度度量的方式和Query塔进行匹配,而刷库产生的向量也就固定了,一些长尾语义或者细粒度语义,由于受到训练数据的天然限制,导致模型无法学习出合适的表征。而采用单塔交互模型,由于可以实时进行交互匹配,对细粒度和长尾需求通常能解决得更好。
Fig 6. 在粗排阶段,鉴于在线计算资源和延迟的考虑,经常采用双塔模型进行相关性建模。
而在精排阶段,由于待排序资源通常比粗排少很多,因此可以采用单塔交互模型进行在线相关性计算。因此想办法在粗排阶段引入单塔交互模型是符合直觉的,思路主要有两种:1. 开源,2. 节流。 开源指的是尽可能增加线上计算的资源(GPU,TPU等异构计算资源),节流指的是在保证模型效果的同时尽可能减少计算量。由于开源收到了经费限制,节流通常是更容易操作,也是更常被采用的方式。通常减少模型计算复杂度的方法无非几类:
降低模型规模,采用更小的模型,比如3层的Transformer等。适配现代GPU的运算特点,采用int8量化的方式提高GPU计算效率。模型剪枝。缓存技术,将过去一段时间内的计算结果进行缓存,在有需求的时候直接查询返回。轻量化模型设计,以CV为例子就是MobileNet,SqueezeNet等[8],以NLP为例子就是Linformer[6,7]等,图网络操作的Shift-GCN[11,12], Shift卷积算子[9,10]等,这些不完全能在搜索系统中应用,只能提供参考。其中的1、2、3、5都可以看成是对模型的小型化,为了保证模型的效果(performance),必须采取一些其他手段。小型模型,比如三层的Transformer效果理论上是不如更深的Transformer网络的,可以考虑在更深的Transformer网络上进行完整的模型训练,然后通过蒸馏的方式将知识蒸馏到小型化网络中。对于某些较大的交互模型,也可以采用近线计算(Nearline)的方式,这个详细介绍可见百度官方的CSDN博客介绍 [5],简单而言,Nearline计算是介于在线计算(online)和离线计算(offline)之间的一种计算方式,通过query触发大模型运算后会将结果缓存起来,当有用户进行相同的查询的时候,会将结果从缓存中返回。int8量化同样也是广泛采用的技术,现代GPU对于int8计算通常作了底层优化,能以若干倍数的程度增加计算速度,而量化通常也分为在线量化,离线量化,对称/非对称量化,静态量化,动态量化等等,是一门复杂的技术。
即便单塔模型通常效果上比双塔模型好,从预训练的角度出发,双塔模型有一个独有的优势——能够采用大规模的对比学习进行表征学习。参考笔者之前的博文[13-15],如Fig 7. 所示,双塔模型由于可以进行双塔的打分矩阵计算,可以产生大量的负样本,n个正样本对应有个负样本,通过all_gather操作汇聚多卡之间的双塔特征,可以把n nn做的很大。海量的负样本为表征学习提供了极好的预训练样本,其中的难负样本能与正样本进行更为充分的“对比”,让大规模对比学习能够学习到很好的表征。而单塔交互模型由于不能进行打分矩阵的构造,在负样本构造数量上天然吃亏,只能想办法通过设计更好的负采样策略进行弥补。目前也有些尝试结合单塔模型和双塔模型的工作,如单双塔构架[4]。
简单介绍下对比学习的训练过程。假设Query塔的特征为,Doc塔的特征为,其中的n为训练时的batch size大小(通过all_gather可聚合不同GPU上的特征从而扩增batch size),d为特征维度,那么训练时候构造出的打分矩阵为 ,其中的对角线都为正样本,而非对角线样本皆为负样本。一般通过infoNCE损失、hinge损失等进行建模,详见[13]。
Fig 7. 采用双塔模型,可以通过all_gather的方式,通过多卡之间汇聚特征,形成超大规模的打分矩阵。
然而通过增大GPU数量的方式去增大对比学习的batch size终究不是一个可持续的做法,能不能在维持GPU数量的情况下尽可能地增大batch size,从而增大负样本数量呢?MoCo [14] 在图像表征自监督学习任务中进行了尝试,通过维护一个负样本队列,将历史负样本压入该队列,从而增大了训练时的负样本数量并且理论上不受GPU数量的限制,WenLan [15] 则将这个思路延伸到了图文匹配任务中,详细内容见[14,15]。
即便从相关性的角度出发,在粗排里面也远不是一个双塔模型就能解决所有类型的相关性问题的,双塔模型是内容的语义匹配(Semantic Match),比如Query与Title是否语义相关,如Fig 8. 所示,用户搜索“苹果糖怎么做”中的“怎么做”与标题中的“制作教程”属于语义上的相关(字面上不匹配,但是语义上匹配)。然而有些Query还有精确匹配的需求,比如搜索一首歌的歌词,歌词通常是连续的并且不希望进行语义上的扩展。还有一大部分Query是Term的散弹组合,比如“烈日灼心 小丰”,当用户不知道如何精确表达需求的时候(或者没有明显需求倾向的时候),会倾向于用一些简短词组的组合去检索,这个时候的匹配结果大多是散弹匹配上的。这类型的匹配属于字词的字面匹配,同时会考虑匹配的紧密度,基础命中信号等,在粗排中仍然会占据一定的影响。为了综合描述各类型相关性的影响,通常会用GBRank或者GBDT[16],LambdaMART这类型的树模型进行建模综合相关性。同时,为了在粗排阶段也把权威性,质量性等考虑进来,通常会将相关性,质量性和权威性算子通过树模型建模形成最终的粗排打分。
Fig 8. Query “苹果糖怎么做” 中的“怎么做”和Title中的“制作教程”属于语义上匹配。查找歌词的时候通常要求完美匹配。
采用树模型进行综合特征打分的建模,有许多优势。第一点,树模型具有较好的可解释性,在训练时候可以通过每个特征的分裂增益(split gain)进行该特征重要性的判断(特征权重),对于线上出现的bad case能分析是否是输入中某个特征的影响,为模型特征的进一步迭代提供方向。第二点,树模型具有足够的拟合能力,能够挖掘出特征中的复杂模式关系,通过pointwise,pairwise,listwise等不同的样本构造和训练方式,树模型能在不同的排序需求中发挥重要作用。与此同时树模型也有些缺点,第一点,树模型无法进行特征交叉,输入特征之间的更为深层次的交互信息无法通过树模型建模(也许也不应该由它建模?)。第二点,树模型容易过拟合,需要恰当地构造训练数据进行去偏。第三点,树模型无法利用稠密向量特征,比如embedding特征。
不管怎么说,树模型由于其解释性(模型迭代的友好性)成为了普遍采用的技术,不光是相关性树模型,也可以对综合满意度进行建模,比如输入质量相关特征,权威相关特征等。内容的质量性是一个和业务强相关的特征,对于网页质量而言,对网页的结构化信息更为看重,对于视频图片,对于其视觉信息更为看重,对于音乐内容则更关心其音频相关特征。由于其具有显著的业务特点,在此科普类文章就不展开了。
通过树模型,我们在粗排阶段拿到了综合相关性打分,综合质量性打分,综合权威性打分,综合时效性打分,通过阈值筛选可以将这些打分(score)划分到不同的分档(level)上,比如都划分到0、1、2、3这四个分档上。划分分档有一些好处,最主要的就是可以屏蔽打分分布的影响,在模型迭代过程中,模型的打分分布是可能发生变化的,有时候可能还是剧烈的变化。而下游的一些过滤策略,打压策略,豁免策略可能依赖于这些打分,一旦打分分布发生变化,那么将会导致下游策略产生毁灭性的打击。而采用了分档之后,各个方向的同学只需要保证分档的分布是不变的,那么就能保证下游策略不会受到影响。保证分档分布不变只需要调整分档阈值就能实现,因此代价远比采用原始打分的来得小。通过阈值分档后,我们得到了各类型分档后,我们就开始考虑一些规则策略了,规则策略是必要的,因为某些类型的bad case很难用模型进行解决。比如说某些query比较长尾,导致其相关结果很少,如果此时还过多考虑质量性的影响,那么可能就没有结果能够被排上来了,此时需要豁免质量的影响。再比如某些query有强烈的时效需求,但是由于模型中无法(或者难以)对时效进行很好的建模(由于样本不容易收集),导致相关的时效结果被其他影响因子给排下去了,此时就需要进行规则提权,将时效结果提权上来。模型虽然看起来“高大上”,但模型不是万能的,作为搜索系统这种复杂系统,如果不引入这些规则策略进行保驾护航,那么解决这些corner case的成本是非常高的。
粗排是对多队列进行粗排序,在每个队列中选择一些结果出来组合成几十个到一百个结果送到精排模型参与精排序。精排除了考虑相关性,质量性,权威性时效性等外,还会考虑用户的行为特征,比如CTR(Click Through Rate)预估,用户后验信号等。在精排中,由于待排序条目进一步缩小到了几十条,除了将粗排信号透传至精排外,还可以采用更复杂的模型进行建模,比如更深的Transformer模型。由于在精排里面排序是最接近用户需求的结果,需要更兼顾相关性,质量,权威时效,用户行为等几个目标的影响,也称为多目标排序。为什么在精排里面要引入用户行为特征呢?想象一个场景,如Fig 9.所示,在2014年《小苹果》一曲刚发行的时候,用户搜索了“小苹果”,此时query分析中的NLP模块由于不可能每天都进行迭代,仍无法将“小苹果”视为一首歌曲(Embedding中没有歌曲的语义信息),此时就需要通过用户的后验信号进行query的主要需求判断。不同资源的用户点击率,停留时长,跳转率,评论数,点赞数,转发数,投币数等用户后验信号(User Posterior Signal,不同产品的后验信号可能不同)都是不一样的,这些用户后验信号可以帮助搜索系统判断当前query下用户的主要需求,主要需求此时也就被定义为是大多数用户会想要的结果。通过用户后验信号的指引,即便系统在理解Query的时候并没有明白到歌曲需求,同样可以把当前大部分用户想要的结果进行召回和排序。但是用户后验信号通常是遵循28原则的,大部分非热点资源,非高频资源是没有后验信号的,甚至连点击数都非常少,我们称之为用户信号稀疏,此时就需要想办法进行用户信号的预估。CTR点击率预估就是这样一种对用户点击某个资源的概率进行预测的一种技术,通常会考虑将用户历史行为信息,用户画像,站点信息,甚至是用户之间的相似程度(进行FM矩阵分解,推荐系统中的经典操作)引入进行CTR预估。用户后验信号不仅可用于解决资源的主需求问题,还可以解决一部分资源的质量判断问题,对于某些资源质量敏感的需求,在高质量的内容下用户的行为会比低质量内容的显著正向,通常可以用于挖掘资源的高质信号。
Fig 9. 不同搜索引擎对于小苹果的返回结果。好像写得比预期中的要多不少内容,剩下的内容后续拾遗篇再继续吧。
Reference
[1]. https://fesian.blog.csdn.net/article/details/125078683, 《【见闻录系列】我所理解的“业务”》
[2]. https://blog.csdn.net/LoseInVain/article/details/116377189,《从零开始的搜索系统学习笔记》
[3]. https://blog.csdn.net/LoseInVain/article/details/123615027, 《工作一年时期的土豆总结——复杂度和困难度》
[4]. https://blog.csdn.net/LoseInVain/article/details/122735603, 《图文多模态语义融合前的语义对齐——一种单双混合塔多模态模型》
[5]. https://blog.csdn.net/lihui49/article/details/113342889, 《百度信息流和搜索业务中的弹性近线计算探索与应用》
[6]. Wang, Sinong, Belinda Li, Madian Khabsa, Han Fang, and Hao Ma. “Linformer: Self-attention with linear complexity.” arXiv preprint arXiv:2006.04768 (2020).[7]. https://blog.csdn.net/LoseInVain/article/details/116242740, 《【论文极速看】 Linformer 线性复杂性的自注意力机制》
[8]. https://blog.csdn.net/LoseInVain/article/details/96651171, 《卷积网络模型压缩的若干总结》
[9]. https://blog.csdn.net/LoseInVain/article/details/109474701, 《紧致卷积网络设计——Shift卷积算子》
[10]. Wu, B., Wan, A., Yue, X., Jin, P., Zhao, S., Golmant, N., … & Keutzer, K. (2018). Shift: A zero flop, zero parameter alternative to spatial convolutions. In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (pp. 9127-9135).[11]. https://blog.csdn.net/LoseInVain/article/details/109563113, 《Shift-GCN网络论文笔记》
[12]. Cheng, K., Zhang, Y., He, X., Chen, W., Cheng, J., & Lu, H. (2020). Skeleton-Based Action Recognition With Shift Graph Convolutional Network. In Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (pp. 183-192).
[13]. https://fesian.blog.csdn.net/article/details/119516894, 《CLIP-对比图文多模态预训练的读后感》
[14]. https://fesian.blog.csdn.net/article/details/119515146, 《MoCo 动量对比学习——一种维护超大负样本训练的框架》
[15]. https://fesian.blog.csdn.net/article/details/120364242,《图文搜索系统中的多模态模型:将MoCo应用在多模态对比学习上》
[16]. https://fesian.blog.csdn.net/article/details/123767279, 《搜索系统中的Learning To Rank模型:GBRank》
[17]. https://fesian.blog.csdn.net/article/details/113429866, 《GBDT-梯度提升决策树的一些思考》