相关搜索 --- 离线和在线的结合

前面说了相关搜索底层的算法逻辑,本篇会继续以相关搜索为例子介绍一下相关搜索的的在线部分架构和一种常规的算法类系统的工程化方式。前端

0. 前面的话

在说正题以前仍是先来闲扯一下,都说产品经理的想象和最后工程师的实现之间差了十万八千里,一样的,算法的模型和最后的工程化部分也是差了十万八千里。看到一个好的算法的论文,一看卧槽这么牛逼,感受能解决一切问题,因而想尽一切办法想要用到系统中,发现实现的过程当中坑无数,这样的例子数不胜数。python

好比说推荐系统中常用的SVD矩阵分解,看上去很美好,可是实际工程化中发现计算量实在是太大,大数据规模下计算量特别大,算出来之后调个参数,又几天过去了,这样的话,须要快速上一个算法项目很难的,论文的算法不少是没考虑工程化状况的,虽然如今有hadoop,有spark,可是有些算法真算起来仍是很耗时间的,因此对算法的改进很重要。 拿到一个算法,对算法的评估很重要,并且须要找到一个可以快速验证算法有效性的方法,不至于作无用功,最好的评估办法是什么呢?呵呵,就是使用成熟的算法,你们都用过的,效果总不至于太差,好比协同过滤这种推荐算法,用了这么多年了,工程应用也不少,怎么也不会太差。redis

本篇是相关搜索的总体设计,我会从算法预研,算法选择和评估,离线算法设计,在线服务设计,总体设计,工程化实现几个部分来讲说一个包含算法的系统的工程化实现过程。算法

1. 算法预研

其实上一篇【相关搜索】介绍的那些个算法就算是算法预研了,算法的预研其实是比较考验经验和技术实力的。编程

  • 首先,你须要有必定的技术积累,你才知道哪些个算法和方法能够解决目前的这个问题,像上一篇的不少相关的算法,好比协同过滤,文本类似性计算,word2vec词向量这些东西,是须要平时的积累和理解才能知道是否能用在目前的这个场景中的。
  • 其次,若是有相关的经验的话那就更省事一点了,如今的互联网的技术栈,哪怕是这类算法类的技术栈,也基本上是有人实现过的,不多能看到一个彻底全新的领域须要你去作,因此若是有相关的经验的话,预研阶段确定是事半功倍了。
  • 通常状况下,预研阶段还须要查阅一些资料或者论文,上网搜一搜别人都怎么作的,而后总结出来一些个方法,这些就是你预研阶段的成果了。拿着这些东西到下一步作进一层的选择了。

预研阶段通常不须要写代码,大概想一想这个算法的模型就差很少了,也就说在这个阶段,你的脑子里面应该有各类算法的模型可供下一步的选择。服务器

2. 算法选择和评估

预研阶段会获得一批备选的技术方案,在这一步的评估阶段就要对这些算法进行更加深层一点的评估了,找到最适合当前场景的技术方案,而后写一些代码来帮助进行评估,好比对于相关搜索,咱们在预研阶段已经找到了一些技术方案,假设咱们找到了经过后继词直接匹配经过搜索词协同过滤经过点击的结果集协同过滤经过后继词的word2vec方法这四个方案,如何来选择呢?微信

  • 成本,做为一个工程项目,成本永远是不可忽视的部分,工程项目不像科研项目能够不计成本的进行研究,工程项目都是有最后期限的,因此成本就显得很重要了,上面四个方案中。
    • 第一个的成本最低,基本上就是一个统计逻辑
    • 第二个和第三个稍微复杂点,须要实现一下协同过滤算法,但这个算法自己仍是很容易的,因此成本稍微比第一个高一点。
    • 第四个方案若是没有现成的代码库可用的话,成本是最高的,由于你必须先完全的了解word2vec这套算法,这套算法不是像协同过滤那么简单就能够了解的,而后还须要实现它,而且还要保证正确性,最后实现出来还要保证性能,这其实是很难的。
  • 工程化可能性,就是这些个算法有没有工程化的可能性或者说好很差进行工程化,在这里的四个技术方案,都是能够方便的进行工程化的,因此在相关搜索中,不存在这个工程化可能性的问题,可是在有一些项目中,真会遇到算法没法进行工程化的状况,没法进行工程化的状况不少,常常遇到的就是计算资源不够,好比你在一小公司,一共就那么几台小内存的云主机,你必定要弄一个牛逼的算法,算法中有不少大矩阵相乘的运算,这种就属于不可能工程化的状况,还有就是你的团队技术能力不够,没法把一个复杂的算法进行工程化的编程,别说,这种状况也不占少数,如今是有各类各样的开源算法库支持,把开发的难度下降了很多,否则有些复杂算法实现起来仍是比较困难的。
  • 效果预估,这个是最难的,由于算法类的系统,除非你以前作过相似的系统,不到最后上线之后A/B测试,都不知道效果会如何。这里咱们粗略的估计一下
    • 经过后继词直接匹配,因为单个用户的数据毕竟有限,随机性太强,因此直接使用这个的话,估计效果不会太好。
    • 后面两个协同过滤中,用户的点击数据无论怎么说,都比直接使用结果集要靠谱点吧,由于用户的点击行为多少表明了用户当时场景下的意图,因此第三个方案经过结果集的协同过滤比较好一点
    • 而第四个方案属于把word2vec进行了一下领域的改变,因此效果好很差不太好直观感受,这个只有作了才知道好很差。

经过以前的成本评估,虽然word2vec的方案实现起来很复杂,可是目前有针对这个的开源实现,因此对于word2vec而言,开发成本没那么高,能够放入考虑中,这么算下来,最后肯定使用经过结果集的协同过滤word2vec两个方案进行系统开发。数据结构

3. 离线算法设计

肯定好算法之后,就要开始漫漫的离线算法设计之路了,其实离线算法设计基本上算工程化的一部分了,验证的过程当中总体的流程就须要设计好了,哪些须要在线处理的,哪些是离线处理的,这些在离线算法设计的阶段就要进行考虑了,主要是为了后续的架构设计更加顺畅。架构

算法类的系统,流程架构基本上有如下三种app

  • 第一种是最简单的,直接出结果数据,而后把结果数据推到在线服务上,生成合适的数据结构,前端来的请求直接查询数据结构获取数据,返回前端,这种适用于结果集变化不是很大的状况,好比咱们的相关搜索,每一个人搜索关键词出来的相关搜索结果都是同样的。
  • 第二种稍微复杂点,离线部分生成的除了结果数据,还有个计算模型,把二者都推送到在线服务上,提供服务的时候除了直接获取结果之外,还须要使用计算模型在线算一下结果,对结果集进行一下微调,而后在返回前端,这种主要适用于结果集改变比较频繁的场景,好比推荐广告系统,有个初步的结果集,会根据每一个用户的标签,把结果集再排排序之类的。
  • 第三种只生成计算模型,全部的结果都由在线部分实时完成,这样的场景其实不是不少,主要应用在一些个性化很是明显的场景中,好比智能问答系统,每一个问题的解答其实是根据当时的状况实时计算出来,而后再给出结果的。 固然,我这里把产出概括成结果数据计算模型两种,实际的状况中比这复杂一些,但基本上思想就是上面说的这样子。

好了,咱们来看看相关搜索的离线算法设计部分吧。

上一节咱们说了使用经过结果集的协同过滤word2vec这两个方案,那么如何来设计这个流程完成这两个算法的验证呢?

对于数据的处理,通常有两种形式,一种是状态机模式,就是根据条件在各个条件在各个状态之间跳转,还有一种是流式处理模式,就是直接一步一步往下走,算法类的离线处理流程尽可能作到流式处理,树形结构,由于方便进行任务分配,不一样人能够写不一样的模块,组合起来也很容易,并且方便进行数据验证,每一步均可以单独进行验证,而且若是目前是单机的运算,数据量大了之后,也方便进行hadoop的移植,基于这个原则,咱们能够按照如下图形来设计这个算法流程。

  • 首先,原始数据来源须要作预处理,生成一个统一的数据结构供后续的节点使用,这个至关于原始数据。
  • 从原始数据出来之后会分红两组数据进入不一样的节点,下面这个节点用来作协同过滤的,先对数据进行二次加工,上面这个节点用来作word2vec,也是对数据进行二次加工,加工成算法须要的数据格式。
  • 第三层节点就是具体的算法模块了,数据按照格式要求输入,而后输出成须要的数据格式供在线平台使用。

这个流程画的比较简单,不过整个相关搜索也不复杂啦,大概的数据处理流程也就是这样子,只不过算法模块有些不一样而已。

在离线算法设计这个环节中,若是你有资源,而且数据量比较大的话,固然能够直接用hadoop进行验证,也推荐这么作,毕竟这样和最后的工程化的差别比较小,若是你的资源有限,呵呵,那就本机验证吧,用相似python mapper.py | sort | python reducer.py > res.txt这样的脚原本验证算法吧,哈哈。。。

离线算法设计的最后产出就是最后的数据集合了,这也是最后在线部分的基础数据了。

4. 在线服务设计

离线部分设计完了,也验证了算法了,那么就得开始在线服务部分的设计了,离线部分获得的数据是一个相似KV形式的数据集合,那么很明显,最简单的在线服务就是把这一堆数据存到redis中,而后在线服务根据搜索的query在redis中查询数据返回结果就好了。

做为一个高端的设计人员,这么干显然不符合个人一向做风啊。

  • 首先,即使是离线计算出来的,也是有不少搜索词覆盖不到的,因此对这部分要在线处理一下。
  • 第二,使用一个redis集群多耗资源啊,直接在本机用一个本地的kv存储就能解决,不必上redis啊。

对于第一种状况,能够先分词,而后找到中心词(这部分能够在搜索的query分析统一来作),用中心词就行推荐,好比搜索女士黄色碎花连衣裙加大码这种搜索词,极可能由于太长尾了,没有数据支持,因此得不到相关搜索,咱们能够在在线服务的时候把这个搜索词改为女士连衣裙,这样就有相关搜索的推荐了,虽然相关性没那么高,可是聊胜于无吧,这种就属于在线算法部分了。

在线算法还有一个功能就是作A/B测试,看看哪一种算法的效果更好,或者是一共10个结果,前5个是协同过滤的,后5个是word2vec的,把那种算法的结果排在前面效果更好,这种的话,经过一个流量的切分来能够看到两种算法的效果。

关于A/B测试,能够专门写一篇文章,这里简单的说一下,流量切分通常有两种,一种是和用户相关的,就是对于某一个用户,你就想让他看到A版本或者B版本;还有一种是用户无关的,只是把全部的请求流量切到A版本或者B版本。使用哪个须要根据业务场景来决定。通常状况下,为了用户体验,都会使用用户切分的方式,由于你让一个用户先看到一种版本的结果,刷新一下页面就看到另一个版本,总感受怪怪的。A/B测试最基本的办法就是经过用户id取模,而后分发到不一样的版本上去。

对于算法类的系统,由于是机器算出来的效果,还有一个很重要的功能就是人工干预了,当看到badcase之后能够迅速先解决掉,记录下badcase,积攒到必定程度,找到规律,而后再去修改算法,既然要先解决掉,那么就直接人工干预就好了,对于相关搜索,人工干预也很容易,把某个搜索词的相关搜索推荐结果直接人填写就好了,把在线服务加一个post的请求接口就能够搞定了。

综合上面的全部因素,咱们能够将在线服务设计成下面这个样子,具体就不描述了,你们看看图吧,有问题能够留言。

5. 总体设计

离线和在线部分都已经设计好了,那么把他们串起来就是总体设计了,可是总体设计的时候更多的须要考虑外围的因素了。

外围的因素在这里就是原始日志的收集,这一部分在离线和在线部分都没涉及到,可是真正工程化的时候是须要考虑的,好比多久整合一第二天志啊,日志从什么渠道推送到离线平台啊,这些都是总体设计的时候考虑的,由于咱们的系统并不须要实时计算,因此对于日志的处理,能够天天从各个服务器直接拉取了,也不须要什么Kafka了,直接wget过来就好了,固然,通常须要作相关搜索的公司,都是搜索有必定的规模了,对于日志早都有统一的处理的平台了,日志早就按时同步到HDFS上了,你只须要直接处理就好了。

总体设计中还有一个环节就是怎么把离线数据推送到在线服务中,这也是两个模块的链接点,凡是这种分为在线和离线两部分的系统都有这么一个过程,最简单的就是写个脚本rsync啦,别以为low啊,rsync仍是简单有效的,至少传输的时候不会出错,或者说出错的几率比你本身经过tcp传输要低得多。还有就是启一个http的服务,在线模块wget这份离线数据啊。再高端点,本身实现一个同步数据的协议来进行同步啊。

在数据传输中,也会遇到一个小坑,就是推模型拉模型的选择,我的以为拉模型比较合适,由于在线服务通常是一个集群,要是用推模型挨个去推,一个失败了还要不停的尝试重新推,推到一半失败了下次是断点续传仍是重新来过也是个问题,这样会对离线端产生不少复杂逻辑,还有若是在线集群增长或者减小了机器,还须要通知到离线端,若是是拉模型就好多了,离线端产生了数据之后就不用管了,前面的集群爱何时拉取数据就何时拉取,离线端彻底不用操心。

因此,把两个线上和线下系统串起来之后,就是下面这个样子了,能够说是一个搜索词的轮回,从搜索引擎产生搜索词的日志,到最后又变成了一个个的推荐搜索词,而后这些个搜索词又能够进入到搜索日志中,继续优化这个系统。

6. 后记

一个小小的相关搜索,虽然简单,可是基本上涵盖了一个算法类系统的全部部分,从算法选型,算法验证,而后是工程化过程当中的离线算法部分和在线服务设计,还要包括A/B测试,在线部分和离线部分结合架构设计。

大部分的算法类系统,都有离线部分,有在线部分,两个部分各自分担一部分算法逻辑,最后把两部分结合起来就是总体的系统了,离线部分负责复杂的算法,在这一块中,你可使用各类高端算法,各类机器学习算法,关键是要尽量的给在线服务分担计算压力,最后要生成一个够简单的数据给在线服务,在线服务负责性能,如何能更快的响应客户的请求是这部分须要重点考虑的问题。

哦了,相关搜索部分就写完了,从头至尾应该没有什么难点,要是你,看了这个设计,能撸出代码来么?


若是你以为不错,欢迎转发给更多人看到,也欢迎关注个人公众号,主要聊聊搜索,推荐,广告技术,还有瞎扯。。文章会在这里首先发出来:)扫描或者搜索微信号XJJ267或者搜索西加加语言就行

相关文章
相关标签/搜索