现在网上到处都有推荐。亚马逊等主流电子商务网站根据它们的页面属性以各种形式向用户推荐产品。Mint.com之类的财务规划网站为用户提供很多建议,比如向用户推荐他们可能想要办理的信用卡,可以提供更好利率的银行。谷歌根据用户搜索历史记录的信息优化搜索结果,找到相关性更高的结果。
这些知名公司使用推荐提供情境化的、有相关性的用户体验,以提高转化率和用户满意度。这些建议原来一般由每天晚上、每周或每月生成新推荐的批处理作业计算提供。
然而对于某些类型的推荐,响应时间有必要比批量处理作业所需的时间更短,比如为消费者提供基于地理位置的推荐。比如电影推荐系统,若用户先前看过动作片,但现在要找一部喜剧片,批量推荐很可能会给出更多动作片,而不是最相关的喜剧片。本文将会介绍如何使用Kiji框架,它是一个用来构建大数据应用和实时推荐系统的开源框架。
Kiji,以实体为中心数据和360度视角
要构建实时推荐系统,首先需要一个能存储360视角客户的系统。此外,我们需要具备迅速获取与指定用户相关数据的能力,以便在用户与网站和移动应用交互时做出推荐。 Kiji是一个构建实时应用的模块化开源框架,它收集,存储和分析这类数据。
一般情况下,一个360度视图所需的数据可以被称为以实体为中心的数据。一个实体可以是任意数量的东西,比如客户、用户、帐户,或者POS系统或移动设备之类更抽象的东西。
一个以实体为中心的存储系统要能在一行数据中存储与某个特定实体有关的一切信息。这对传统的关系型数据库来说是个挑战,因为这些信息可能既有状态型数据(如姓名,电子邮件地址等)又有事件流(如点击)。传统的系统需要把这些数据存放在多张表中,处理时再把这些表联接起来,这使得它很难做到实时处理。为了解决这个问题,Kiji用了Apache HBase,它在四个维度 - 行、列族、列标识和时间戳-存储数据。借助时间戳维度和HBase存储多个版本Cell的能力,Kiji能够存储有更多状态的缓慢变化的事件流数据。
HBase是Apache Hadoop使用的一个键-值存储系统,它构建在HDFS之上,为大数据解决方案提供了必需的可扩展性。在HBase上开发应用程序面临的巨大挑战是,它要求所有进出系统的数据都是字节数组。为了解决这个问题,Kiji的最终核心组件是Apache Avro,被Kiji用来存储易于处理的数据类型,如标准字符串和整数,以及由用户定义的更复杂的数据类型。 读写数据时,Kiji为应用程序做必要的序列化和解序列化处理。
开发用在实时中的模型
Kiji为开发模型提供了两套API,Java和Scala,两套API都支持批量和实时组件。如此划分的目的是将模型执行划分为不同阶段。批量阶段是训练阶段,是一个典型的学习过程,在该过程中,将使用完整的数据集来训练模型。该阶段的输出可能是线性分类器的参数,或者聚类算法的群集位置,或在协同过滤系统中相互关联条目的相似性矩阵。实时阶段被称为评分阶段,取得经过训练的模型,并将它与实体数据相结合产生衍生信息。关键是这些衍生数据被当作一等公民,也就是说它可以存回到实体所在的行中,用于推荐,或作为后续计算的输入。
Java API被称为KijiMR, 而Scala API构成了KijiExpress工具的核心。 KijiExpress利用Scalding库提供API来构建复杂的MapReduce工作流,同时避免了大量Java冗余代码,以及串联MapReduce作业所必需的任务调度和协作。
个体与总体
之所以要划分出批量训练和实时评分两个阶段,是因为Kiji观察到总体趋势变化缓慢,而个体趋势的变化迅速。
比如一个包含上千万次购买记录的用户总体数据集。多一次购买不太可能对总体趋势的好恶造成重大影响。但对于一个只有10次购买记录的特定用户而言,第11次购买将对系统判断用户兴趣产生巨大影响。鉴于这种主张,应用程序只需在收集到足以影响总体趋势的数据时再重新训练它的模型。但对于特定用户而言,我们可以通过实时响应用户的行为来改善推荐的相关性。
实时给模型评分
为了做到实时评分,KijiScoring模块提供了一个惰性计算系统,应用程序可以只为经常与其交互的活跃用户生成最新推荐。通过惰性计算,Kiji应用程序不必为那些不经常光顾或再没回来过的用户生成推荐。这还有些额外的好处,Kiji可以在推荐时考虑像移动设备的位置之类的情境信息。
KijiScoring的主要组件叫Freshener。Freshener实际上是另外两个Kiji组件的组合:ScoringFunctions和FreshnessPolicies。正如前面提到的,一个模型包括训练和评分两个阶段。ScoringFunction是一段代码,描述了如何把经过训练的模型和单一实体的数据组合起来产生一个分数或建议。FreshnessPolicy定义数据变得陈旧或过时的时间。比如说,普通的FreshnessPolicy会指出超过一个小时后数据就过期了。更复杂的策略可能会在实体经历过一定次数的事件后将其标记为过期,比如点击或产品访问等事件。最后,ScoringFunction和FreshnessPolicy被附着在Kiji表中特定的列上,在必要时被触发来刷新数据。
进行实时评分的应用程序中包含一个服务器层,被称为KijiScoring服务器,它是负责刷新陈旧数据的执行层。当用户与应用程序交互时,请求将被传递到KijiScoring服务器层,它直接与HBase集群通信。KijiScoring服务器将会请求数据,并且在获取到数据后根据FreshnessPolicy检查数据是否是最新的。如果是最新的数据,它将其直接返回给客户端。如果是过时的数据, KijiScoring服务器将为发出请求的用户运行指定的ScoringFunction。你需要掌握的要点是它只为发出请求的用户刷新数据或推荐;而不是执行批处理操作,刷新所有用户的数据。这样Kiji就可以只是做那些有必要做的工作。数据刷新完成后会被返回给用户,同时写回HBase以备后用。
一个典型的Kiji应用程序将包括一定数量的KijiScoring服务器,它们是可以向外扩展的无状态Java进程,并能够运行使用单一实体的数据作为输入的ScoringFunction。Kiji应用程序通过KijiScoring服务器过滤客户端请求,由它决定数据是否是最新的。若有必要,它会在把所有推荐传回客户端之前运行ScoringFunction进行刷新,并将重算后的数据写到HBase中,以备后用。