应用商店推荐系统探索与实践
Huang Xiaoqun vivo互联网技术
介绍 vivo 应用商店推荐系统如何高效支撑个性化的推荐需求。
一、前言
商店的应用数据主要来源于运营排期、CPD、游戏、算法等渠道,成立推荐项目之后也没有变化,发生变化的是由推荐系统负责和数据源进行对接,商店服务端只需要和应用推荐系统进行对接即可。
如果读者以为我们单纯是把商店服务端代码给照搬到推荐系统这边来了那就真的是too young too simple 了,不做优化或者升级直接copy一个系统是不可能的,这辈子都不可能。以下我将介绍我们如何去设计和规划应用推荐系统的。
二、面临的挑战
在笔者眼中,商店应用推荐系统除了要具备高性能、高可用性及核心指标的监控能力之外,还有一个核心的能力就是高效支撑商店流量场景接入个性化推荐。
如何定义高效支撑?
- 最起码能支撑三四个并行的需求同时进行吧。
- 一个需求开发周期最起码不能超过2天吧。
- bug少一点吧,平均下来每个场景不应该超过2个吧。
- 产品同学的常态性的需求基本都能快速支持吧。
分享我们一个应用推荐的策划case看看:
在xx场景下,
如果主应用A属于应用类,
- 则首先从从x1数据源去取Q1队列。
- 然后从x2数据源去取Q2队列。
- 然后用Q2队列去截断Q1队列,
- 交集之后进行同开发者过滤和一级分类过滤。
- 如果交集为空则用Q2去兜底。
- 然后取交集队列的n1和n2 位置上的元素作为返回队列。
- 如果前面都没有取到数据的话从大数据xxx表中按照主应用下应用点击的概率取点击率最高的分类下的n个,同时需要对这些数据进行队列内的同开发者过滤。
如果主应用A属于游戏类,
- 则xxxx
- 进行二级分类过滤
- 如果量不足的话,则从x(n)取数据然后进行处理,
- 如果数据不足3个的话,需要从周榜单中取同一级分类下的应用按照下载排行进行兜底。
没错,读者朋友不要怀疑自己,为了不把各位读者大大绕晕,我们这里只是挑选了一个简单的需求。实现这么一个功能也没有什么大不了的,但是当这种个性化推荐需求有几十个,后面还可能一致扩展下去的时候会不会心里发慌?来,简单看下我们现在个性化推荐的一部分需求,如图(一)所示:
图(一)
使用商店服务端之前的case by case的开发方案,无论如何都无法实现上文中描述的要支撑商店高效接入推荐场景了,接着就是我们如何去实现优化的过程了。
三、如何解决
为了更好的说明解决思路,我们从实际思考过程出发,一步步讲解问题的解决过程。
3.1 业务流程抽象
单纯从策划上面来说,我们每个场景都需要至少做如图(二)中的几件事情:
图(二)
- 获取推荐列表: 调用各个数据源获取的推荐队列(需要注意的是不同场景下调用的接口并不一致,此外接口返回的字段和结构可能也不一样)。
- 队列融合: 将1中提到的进行交集或者并集并等操作。
- 数据过滤(队列内/队列间): 在队列中进行各项过滤,过滤操作主要是为了提升相关性。
- 数据兜底: 指在队列数据不够的时候,用榜单兜底,可能取周榜单数据的同一级分类数据,同二级分类数据。
笔者从开发便捷性出发,对模型进行了进一步的调整,调整后为图(三)
图(三)
获取队列后对队列进行安装过滤和队列内过滤(如主应用同开发者过滤等)可以进行流程合并,主要有如下的原因
- 方便定义每一个数据源的过滤策略,实际需求中不同的队列也会使用不同的过滤策略。
- 这种方式非常匹配模板设计模式,能确保我们获取推荐列表过程是一致和稳定的。
3.2 抽象流程延伸
到图(三)这里,读者会发现我们依然没有能够解决我们前面提到的各种推荐场景里面的差异化过程。
其实在接触几个需求以后,我们会发现,想要在一套代码里面去解决这么大的差异性,几乎不可能,或者即使实现了,那么也会让代码变得无比复杂。与其这样子,我们还不如正视这种差异性,让差异在场景插件里面去实现,我们花更多的精力去打理主干。
那么为了支持让场景能够具备灵活的扩展能力,笔者在基于图(三)的基础上增加了四个环节:
- 队列结果线程内共享: 使用ThreadLocal来实现。存储各推荐队列的结果主要是为了便于后续使用某推荐队列做填充的需求,另外就是避免需要再重复请求三方数据接口,减少接口重复调用。
- 插件队列兜底: 主要目的是在过滤后在数量不足需求的情况下,使用指定的队列完成填充,场景插件亦可按需填写实现填充逻辑,实现队列内容的补充。
- 插件接口回调: 该环节主要是对前面的队列做个性化的处理,如对队列进行干预等,没有将插件接口回调和插件队列兜底融合在一起主要原因是插件队列融合可以实现可配置化的设置。
- 周榜单兜底: 提供通用的周榜单数据查询能力,支持按照各种维度进行查询,此部分数据作为队列的最后兜底。
拓展后的流程图如图(四)所示
图(四)
3.3 整体逻辑框图
经过上述的分析可知,我们可以尽可能的把个性化的场景内容放在插件层实现,框架层负责加载按场景加载场景插件的具体个性化推荐逻辑。
系统从分层思路上讲从上至下共分为:插件层,框架层,协议适配层,数据源服务层,原子服务层,基础服务层,上层通过 SDK 依赖下层的服务(接口),各层次职责为:
- 插件层: 各个场景对应的插件,框架层对插件回调或者扩展接口提供默认实现,插件层按需实现具体的逻辑。
- 框架层: 定义推荐数据的核心流程和执行逻辑,回调插件层的实现的扩展和回调接口。
- 协议适配层: 负责按照场景找到场景对应的数据源服务,并封装转换协议和进行数据转换。
- 数据源服务层: 与各个队列提供方提供的RPC服务封装层。
- 原子服务层: 过滤类型的相关服务,主要是依赖于商店的 RPC 服务,使用组合的设计模式,服务可以进行组合。
- 基础服务层: 支持从开发者、一级分类、二级分类、应用类型等纬度进行相关性的判断或者过滤,同原子服务层一样,此层服务也是原子粒度,支持进行组合控制。
图(五)
至此,相信大家都知晓了,针对于个性化的推荐,我们的开发工作最终将聚焦于开发场景插件,不需要再额外开发每一个业务流程了。
应用推荐系统架构
3.4 关键实现
在完成第三步整体逻辑框图设计之后,我们从场景参数定义,服务设计原则,设计模式使用,场景热插拔等方面进行了相关的方案研究并最终实现了方案的落地。
3.4.1 场景服务参数定义
为实现推荐场景足够通用,我们将数据源层,原子服务层,基础服务层的内容进行了服务配置的映射,通过在配置中定义对应的配置项来实现服务的映射和组合,针对�
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek/post/%E4%BA%92%E8%81%94%E7%BD%91/%E5%BA%94%E7%94%A8%E5%95%86%E5%BA%97%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E6%8E%A2%E7%B4%A2%E4%B8%8E%E5%AE%9E%E8%B7%B5/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com