往期回顾:
推荐系统被捧为目前算法领域的主流,推荐系统不需要用户主动进行操作就能获取自己喜欢的东西,但是实际上,搜索系统在很长一段时间占据了重要位置,大到百度的大搜,小到音乐、视频、电商、应用商店等,都有各种各样的搜索引擎,这些搜索搜索能更为精准直接的满足用户需求,即使是推荐系统如日中天,目前也仍会有搜索的一席之地。今天我来为大家介绍,搜索系统中涉及的算法问题,也让大家了解,搜索中需要什么算法。
数据预处理模块
这个很好理解吧,用户query进来,一般要做如下处理:
大小写转化。
删除标点符号(当然有的分析会保留标点,但是建议在这个场景下还是去掉更好)。
繁体转简体。
数字处理,转中文,转阿拉伯数字,甚至罗马字等,部分情况要删除数字。
长度截断。(总不能让用户输入一本西游记,然后你还在整吧?)
理解模块
query理解其实是一个非常重要的模块,好的query理解能为后续的工作提供很大的支持。这部分往往不直接应对下游,而是按需使用,有点像辅助吧。
分词。基操。
关键词抽取。会涉及丢词、排序等功能。
命名实体识别。一方面协助用户识别,另一方面可能会涉及数据库查询匹配的内容。在垂搜中比较常见,大搜也有但是相比之下没那么精准和常见。
紧密度分析,避免由于切词出现错误导致词义偏移的问题,这个其实并不少见,尤其是在人名上,这个是别的精准度会很低,近期的如“武大靖”,会被分为“武大 靖”,“曾舜晞”直接被分为了3个字,挺头疼的。
非法信息过滤。例如黄色、暴力血腥、反动等。
改写模块
改写模块其实非常关键,这是连接用户query和数据库底层数据的桥梁,数据库的存储有特定的形式,但是用户不会按照你的底层数据结构去写,例如,用户不见得会输入和平精英,而是吃鸡,数据库里可不见得会存吃鸡对吧,所以这块很重要。
同义词改写。上面的吃鸡就要改写为和平精英,这个需要通过同义词挖掘等方式去构造词典实现。
拼音改写。数据库是罗密欧与朱丽叶,但是用户输入的是罗密欧与朱莉业,拼音改写其实颇为常见,用户经常由于找不到需要的结果或者不知道应该需要哪个,于是直接输入后开始搜索。
前缀补全。非常常见,用户输入射雕,射雕英雄传就要出了,这个一般的方法也是构造词典,另外有一个很重要的需要了解的就是前缀树,这个能让你查询的时间非常低的水平(只和query长度本身有关)。
丢词和留词。结合上述关键词提取和命名实体识别完成,有些不必要的词汇需要被删除,例如“李小璐到底怎么了”,整个句子只有李小璐是关键词,其他词如果也通过and逻辑召回,就没有信息召回了,这时候其实可以直接删除或者将降级到or逻辑。留词和丢词相反,丢词如果是做减法,留词就是做加法。
近义词召回。这个召回不是从数据库中召回,而是召回近义词,具体的方法是通过embedding方法转化词汇,然后通过ball tree、simhash的方式召回与之意思相近的词汇,该模式虽然比较激进,但是能一定程度增加召回,有一定效果。
意图识别。与其说是意图,我更喜欢理解为这是直接针对底层数据结构产生的需要解决的问题,query这是一条,但是数据库有好几个,我们要去哪个数据库搜,这是需要识别的,而这个数据库的设计往往和品类、意图有关,找酒店、找景点都是不同的,所以此时就要进行意图识别,一般地方法是抽象为文本分类,但是很多时候语义本身是无法体现出真实意图的,例如少年的你,语义上其实很难分析出,有时候更复杂的会夹带一些实体识别、词性、词典之类的信息。
召回模块
结合命名实体识别、改写结果,然后开始召回,模式比较多,包括但不限于下面形式:
Elastic Search,著名的搜索平台ES,有些时候甚至简单的搜索平台直接用它管整个搜索引擎但是要精做,就只能把它当做底层的数据库和搜索平台。
关系数据库。MySQL之类的,但是在我的理解速度和并发性都不是特别好。
Redis。KV形式的数据库,速度很快,但是Key匹配必须是精确匹配,这需要改写模块具有很强的能力。
说白了,就是把用上面流程处理过的query放到数据库里面查,这个其实就是召回。
排序模块
内容是召回回来了,其实怎么展现给用户呢?这里是需要深度挖掘用户的实际需求的,很多时候甚至需要做个性化,但是更多时候是我们能够得到的只有短短的一句用户query,那么,我们就要好好利用好这个query,来做好排序,让用户喜欢的(当然,还有广告商喜欢的哈哈哈)东西放在前面,实际上就是一个学习排序的问题了,这个我之前也做过一些简单的介绍,那么在特征层面,可以考虑如下的信息:
query层面:
本身的embedding,后续迭代可以走elmo后逐渐形成的pre-train的模式。
词性、实体、词权重、offset等序列标注得到的结果。
document层面。
如果文档本身有文本,最好是标题类的,也把embeding引入,和query层面那种一样。如果只有query文本和document文本,其实就是个文本相似度模型了对吧。
综合层面:
query和document的ctr、cqr、bm25,句向量余弦相似度等匹配信息。
其他层面:
意图识别结果。
模型上,DSSM系列似乎是比较流行的方法,但是提取一些特定的特征,有点的时候简单的LR、XGBOOST就能一定程度把问题解决好了。
而在排序模块中,还会涉及一些硬规则等。
搜索引导模块
query suggestion是一个上述搜索过程非常类似的模块,只不过处理的结果大部分是放在离线,在线是指一个查字典的过程,那么离线部分,其实是做了一整个搜索过程的:预处理、query理解、改写、召回、排序。
预处理:和上面的预处理类似,不赘述。
query理解,和上述内容类似,但是有的时候会简化,直接进入改写模块。
改写模块,会进行容忍度更高的前缀匹配,去找回一些用户可能会喜欢的内容,这时候往往还会带上统计特征,从整体层面上看用户喜欢的内容,毕竟不同时间用户喜欢的可能不同,例如对热点新闻的偏好。
召回和排序模块。召回模块不是召回数据了,而是召回相似的doc信息,也可以是相似的历史用户query,尤其是后者,如果是后者,则要确认历史用户query是有结果的。
其他辅助模块
显然,整个搜索系统远远不止这些内容,在算法视角下,其实还需要很多辅助模块协助我们进行算法开发。
日志模块。无论是线上的运行日志,还是线下的模型实验和离线模型运行,都需要日志协助,对于线上运行和离线模型运行而言,出现错误可以方便追溯,找到ERROR出现的时间和具体问题,而线下的模型试验能方便我们计算运行时间、找到bug,而非每次训练模型的时候功亏一篑才来找问题。
实验模块。由于算法策略存在很多不确定性,无论是算法内存占用和时间,还是算法实际结果,因此需要利用AB实验的方式来验证,快速进行分析,对有问题的算法及时下线检查原因。
数据分析和报表模块。结合实验模块,需要对日常用户数据进行分析,这个比较好理解,不赘述。
特征生产模块。特征生产涉及两块,一个是线上的实时计算,对于一些实时数据,是需要即时生成的,例如微博热搜里面就需要一些诸如5分钟搜索量之类的特征,这个只能从实时计算模块中获取;另一个是离线模块,为了进行离线模型训练,需要定时将生肉(原始数据)转化为特征,方便进行下一步计算,如果这个能变成日常任务,那开发人员就不需要临时造轮子执行,还要长时间等待。
定时任务模块。很多任务其实是定时开始的,报表生成、特征生产,甚至是一些实时任务(说白了就是短时间内的计算),因此有定时任务模块去管理这些定时任务,将会非常方便。
模型管理模块。首先一个项目中可能存在大量模型,然后因为各个模型训练需要花费大量资源,还要结合AB试验,另外还有模型的更新和保存机制(防止模型加载失败导致的无模型可用),因此需要构建模型模块统一管理模型,这个不是每个部门都有,或者说每个模型都是各自管理,但是有一个比较好管理模型平台是非常高效的。
数据平台。额,简单地说就是写SQL的地方,但是也有类似ETL之类的内容,和特征生产模块很接近。
小结
搜索作为一个完整地系统,难度甚至比搜索要困难,在更多的场景下,搜索系统只能针对短短几个字的query进行分析,从而在海量数据中找到用户需要的东西,而由于是用户主动输入的,所以用户的预期非常高,但因为是用户主动的行为,所以不会太过复杂,甚至可能会有各种各样的歧义,只有详细分析和挖掘才能得到,因此在我看来,搜索这个事情非常具有挑战性,即使这个东西已经发展多年,年龄比推荐系统更大,还是很多可挖掘的地方。