摘要:Appboy 正在过手机等新兴渠道尝试一种新的方法,让机构能够与顾客创建更好的关系,能够说是市场自动化产业的一个前沿探索者。在移动端探索上,该公司已经取得了必定的成功,知名产品有 iHeartMedia、PicsArt、Etsy 等。html
【编者按】本文摘录自 Appboy 联合创始人兼 CIO Jon Hyman 在 MongoDB World 2015 上的演讲。Appboy 正在过手机等新兴渠道尝试一种新的方法,让机构能够与顾客创建更好的关系,能够说是市场自动化产业的一个前沿探索者。在移动端探索上,该公司已经取得了必定的成功,知名产品有 iHeartMedia、PicsArt、Etsy、Samsung、Urban Outfitters 等。本文主要包括 Statistical Analysis、Multivariate Testing and Rate Limiting、Flexible Schemas: Extensible User Profiles 和 Data Intensive Algorithms 四方面内容,本文系 OneAPM 工程师编译整理。web
如下演讲摘录:算法
为了支撑其营销自动化平台,Appboy 为其分析和定位引擎使用了 MongoDB 做为其主要数据存储层。时下,Appboy 天天须要处理上万用户的数十亿数据点。本文将分享 Appboy 关于 MongoDB 的最佳实践,看看该公司如何在规模迅速扩大后仍然保持敏捷。本文将谈及诸多话题,如文档随机抽样、多变量测试及其 Multi-arm bandit optimization、Field tokenization,以及 Appboy 如何在一个个体用户基础上存储多维数据从而优化以最佳的时间给终端用户提供信息。mongodb
Appboy 适用于各类大小的客户群体,其中包括了只有数万用户的初级客户,也有客户已经拥有了数千万用户。可是毫无疑问的是,经过 Appboy 营销自动化技术,即便拥有上亿用户规模的客户仍然能够便捷地收集和储存用户数据。数据库
Appboy 平台的核心是 customer segmentation(客户细分)。segmentation 容许机构根据行为数据、消费史、技术特性、社交概要等来定位。创新和智能的使用 Segmentation 和信息自动化使机构能够无缝地、轻松地将安装用户转化为活跃的用户,从而斩获 kpi,Segments 能够按需定制。数组
当客户使用 Appboy 仪表板定义 segment 时,Appboy 能够在一些特征上作实时计算,好比群体大小、开通消息推送的用户规模、用户平均消费能力。这些计算须要实时和交互式的,而在不具有谷歌规模的基础设施上,在这种规模上作交互式分析是极具挑战的。这里存在的挑战是如何更有效率的支撑如此规模,以及如何服务于各类体积的用户。基于这些缘由,随机抽样是个不错的选择。缓存
在现实世界中,随机的统计抽样时刻发生着,好比针对美国总统的舆情调查不可能去单独的问每一个人,全国收视率统计也并非靠评级机构查看每一个用户的电视机。相反,这些数来源于统计抽样,统计抽样经过抽样小部分群体来得到更大群体的特征。经过统计数据,1个小样本就能够对大规模群体作出准确的评估。许多政治民意调查只调查几千成年人就能够估计数以百万计的公民的政治倾向。但调查机构的报告与统计也常常带有所谓的置信区间,也称为误差。网络
相同的原则能够运用到这里。与传统分析数据库相比,抽样用户有一个明显的优点,由于这里能够从用户的总体行为上进行抽样,而不是从原始事件流中取样。须要注意的是,Appboy 只针对 segment 交互式反馈作抽样,从而在网络仪表板反馈。当作营销活动或对 Segment 进行分析做为 Facebook Custom Audience 时,准确用户会被计算,而这些原则并不适用。并发
在开始时,会在已知范围 document 内添加一个随机数字,称之为「bucket」。选择一个合理的小用户群,从而有可能聚焦每一个用户,须要注意的是,这个抽样规模乘以 bucket 的数量必须覆盖该范围。举个例子,只选择了1到10的抽样显然不能够支撑上亿规模,1到100万显然是个不错的选择。在 Appboy 共拥有1万个「bucket」,因此应该是0到9999。app
假设这里有1000万个 documents(表明用户),首先将给这些文档加个数字并对其索引。
{ random: 4583, favorite_color: “blue”, age: 29, gender: “M”, favorite_food: “pizza”, city: “NYC”, shoe_size: 11 } db.users.ensureIndex({random:1})
第一步是得到1个随机样本。1000万个 document ,10000随机的 buckets,每一个 buckets 应该有1000个用户:
db.users.find({random: 123}).count() == ~1000 db.users.find({random: 9043}).count() == ~1000 db.users.find({random: 4982}).count() == ~1000
若是抽取整个用户基础的1%,那就是10万的用户。为了实现这一点,必须选择一个随机范围来「托管」这些用户。举个例子,这些都是能够的:
db.users.find({random: {$gt: 0, $lt: 101}) db.users.find({random: {$gt: 503, $lt: 604}) db.users.find({random: {$gt: 8938, $lt: 9039}) db.users.find({$or: [ {random: {$gt: 9955}}, {random: {$lt: 56}} ])
在有了随机样本后,下一步就是对其分析。要衡量其真正的大小,首先须要进行一个计数,由于鉴于随机性这里不可能精确到100000。
在并行的方式,这里能够在样本上添加任意查询,这里拿找出最喜欢蓝色的男性用户比例。
sample_size = db.users.find({random: {$gt: 503, $lt: 604}).count() observed = db.users.find({random: {$gt: 503, $lt: 604}, gender: “M”, favorite_color: “blue”).count()
假如,样本大小设定是100000,观察数是11302。从这里能够推断出,在1000万用户中有11.3%的用户符合标准。要称为优秀的统计学家,还应该提供一个置信区间来估计偏离值。置信区间背后的数学有点复杂,可是,若是想本身尝试的话,有无数样本 sizecalculators 可供参考。本文使用的案例中,置信区间为+ / - 0.2%。
在实践中,当执行统计抽样时,Appboy 基于这些高等级概念概念作了大量优化。首先,Appboy 使用 MongoDB 聚合框架,而且大量使用缓存。由于这里使用的是内存映射存储引擎,对于这种抽样,使用 MongoDB 的好处是一旦将随机样本加载到内存就能够运行任意查询。这么作为 web 仪表盘上提供了卓越的体验,用户能够经过添加和删除选择标准并当即看到统计数据更新,从而用户能够进行交互式探索。
在当今竞争激烈的市场中,用户细分是必不可少的。随着经验与品牌继续快速转向移动等新兴渠道,对营销来讲,信息定制化和关联性性比以往更加剧要,这就是用户分类为何会成为与客户交互的先决条件。
所以一旦定义了一个划分,下一个目标是优化消息推送使其转换最大化,多变量测试则是实现这一目标的一种途径。多变量测试是一个实验,用来比较用户对相同营销活动多个不一样推广手段的反应。这些版本拥有相同的营销目标,但在措辞和风格上有所不一样,而多变量测试的目标就是为了肯定哪一个版本能达到最好的转换。
例如,假设您有3个不一样的推送通知消息:
Message 1:This deal expires tomorrow!
Message 2:This deal expires in 24 hours!
Message 3:Fourth of July is almost over! All deals end tomorrow!
此外,除下消息,一般还会测试大量的图片搭配合文本。
使用多变量测试,机构能够发现哪一种措辞产生更高的转化率。在下次发送推送式通知谈生意时,就能够知道哪一种语气和措辞更有效。更好的是,能够经过限制测试的大小,好比在一小部分听众内,找出哪些消息更有效,而后发送这些有效的消息给其余人。
在进行一个多变量测试时,消息推送的目标是测试全体,可是同一细分中的其余用户不会收到该条消息。从而,机构能够经过对比两种反应来进行评估。
从技术的角度来看,接收消息的人应该是随机的。也就是说,若是你有100万用户且想要发送一个测试给50000人,这50000人应该是随机分布在你的用户群里(你还想要另外一组5000用户为对照组)。一样的,若是你想测试10到50000用户,随机性有助于确保每一个测试组的用户都不一样。
思考这个问题,它与1个消息中的比率限制问题是一行。许多客户想要给一小群用户发送一条消息。好比,一个电子商务公司想随机的在用户群中发放50000个优惠码。这在概念上,是一样的问题。
为了实现这一点,这里能够经过每一个文档上的随机值来扫描用户:
Appboy 会在不一样的随机范围内经过随机值用并行处理的方式来管理用户。并追踪全局状态,所以能够知道什么时候达到比率的极限。对于多变量测试而言,随后还会经过发送比率或者是随机地选择一个消息版本。
那些有数学思惟的人可能已经注意到,若是在随机字段中使用统计分析,并基于相同的随机字段选择个体接收消息,那么在某些状况下,将会产生误差。为了阐释这一说法,假定使用随机 bucket 值为10来选择全部用户,给他们随机发送消息。这意味着,在这个用户 bucket 中收到消息的用户将再也不是随机分布。做为一个简单的解决方案,Appboy 对用户使用多个随机值,注意不要为了多个目的使用相同的随机值。
在每一个用户打开 Appboy 的任意一个应用,一个丰富的用户概要文件都会被建立。用户的基本字段看起来是这样:
{ first_name: “Jane”, email: “jane@example.com”, dob: “1994-10-24”, gender: “F”, country: “DE”, ... }
Appboy 客户端还能够存储每一个用户的「自定义属性」。做为一个例子,一个体育应用程序可能想存储用户「最喜欢的球员」,而电子商务应用程序可能会存储客户最近购买的品牌等。
{ first_name: “Jane”, email: “jane@example.com”, dob: 1994-10-24, gender: “F”, custom: { brands_purchased: “Puma and Asics”, credit_card_holder: true, shoe_size: 37, ... }, ... }
这么作一个巨大的好处是,这些自定义属性能够在其余属性更新时直接插入。由于 MongoDB 提供灵活的模式,添加任意数量的自定义字段都很容易而,且不用担忧它的类型(boolean、string、intege、float 又或是什么)。MongoDB 会处理这一切,而查询自定义属性也很容易理解。针对一个 value 列,这里不提供复杂的链接,而在传统关系型数据库中你每每须要提早定义。
db.users.find(…).update({$set: {“custom.loyalty_program”:true}}) db.users.find({“custom.shoe_size” : {$gt: 35}})
这么作的缺点是,若是用户不当心在客户端中使用很是长的名称来定义(「this_is_my_really_long_custom_attribute_name_it_represents_shoe_size」)
或者是被 MongoDB,在 MongoDB 的早期版本中它会占用大量的空间。另外,由于类型不是强制的,这里也可能出现跨 documents 值类型不匹配问题。1个document 可能列出某人{ visited_website: true}
,可是若是不当心,另外一个就多是{ visited_website: “yes”}
。
为了解决第一个问题,一般会使用1个 map 来切分用户属性名称。一般状况下,这能够是 MongoDB 中的一个 documents,好比将「shoe_size」值映射成一个独特的、可预测的短字符串。只要使用 MongoDB 的自动操做,就能够生成这种映射。
在映射中,一般会使用数组进行存储,数组索引是「token」。每一个客户至少有一个 document 会包含 list 的数组字段。当首次添加一个新的自定义属性时,能够自动把它放到列表最后,生成索引(「token」),并在第一次检索后缓存:
db.custom_attribute_map.update({_id: X, list: {$ne: "Favorite Color"}}, {$push: {list: "Favorite Color"}})
可能会有这样一个列表:
[“Loyalty Program”, “Shoe Size”, “Favorite Color”] 0 1 2
MongoDB 最佳实践须要警示 documents 的不断增加,而自 Appboy 定义起,documents 就存在无限增加的状况。实际上,这个潜在的问题已经被考虑,而这里则是经过限制数组大小来让用户使用多个 documents。当给列表添加新的项时,若是数组长度小于必定规模,更新操做只能局限于 $push
。若是更新操做没有生成1个新 $push
,一个自动的 $findAndModify
能够用来建立一个新文档并添加元素。
Tokenization 确实增长了一些间接和复杂性,但它能够自定义映射属性,从而在整个代码库传递。这个解决方案一样能够应用到其余问题上,能够是数据类型文档中不匹配。在这里一样可使用映射来追踪数据类型。例如,记录「visited_website」是一个 boolean,只接受 true 或者 false。
多变量测试目标是,在最短的时间内寻找最高的转化率,当下已经能够在大量平台上发现,客户会按期进行测试,并发现最好的那个。
Appboy 一种叫作 Intelligent Selection(智能选择)的特性,该特性能够分析多变量测试的性能,并依据统计算法自动调整接收到不一样版本消息的用户比例。这里的统计算法能够确保得到最真实的性能,而不是随机的可能性,该算法被称为themulti-arm bandit。
multi-arm bandit 背后的数学算法很是复杂,本文不会阐述,这里不妨着眼剑桥大学数理统计学教授 Peter Whittle 在1979年的发言:
「The bandit problem」 是二战期间被正式提出的,为了解决它,盟军分析师绞尽脑汁,备受折磨,以致于建议把这个问题抛给德国,做为知识战的终极手段。
但提出这个算法的理由代表,为了有效地运行,the multi-arm bandit 算法须要输入大量的数据。对于每一个消息版本,该算法会计算接受者以及转换率。这就是 MongoDB 发光的地方,由于可使用 pre-aggregated analytics 实时地自动积累数据:
{ company_id: BSON::ObjectId, campaign_id: BSON::ObjectId, date: 2015-05-31, message_variation_1: { unique_recipient_count: 100000, total_conversion_count: 5000, total_open_rate: 8000, hourly_breakdown: { 0: { unique_recipient_count: 1000, total_conversion_count: 40, total_open_rate: 125, ... }, ... }, ... }, message_variation_2: { ... } }
经过这样1个模式,能够快速查看天天和每小时的转换变化,打开并发送。Appboy 模式稍微复杂一点,由于这里还存在其余须要考虑的因素,这里须要注意。
预聚合 documents 容许快速终止实验。鉴于为每一个公司对 collection 进行分片,这里能够以扩展的方式同时优化某个公司的所有活动。
Appboy 提供给客户的另外一个专有算法称为智能交付。当规划消息活动部署时,Appboy 分析出给每一个用户发送消息的最优时间,并在正确的时刻提供可顾客。好比 Alice 更可能在晚上获取应用程序推送信息,而 Bob 则喜欢把这个事情放在早上上班前,那么 Appboy 将会在他们最乐意的时间推送消息。这是个能创造奇迹的特性,正如 Urban Outfitters CRM 和 Interactive Marketing 负责人 Jim Davis 所称赞的:
对比使用先后的打开比率,能够看到表现提高了1倍。针对男性 Urban On members 一周活动目标提高了138%。此外,细分功能也值得称赞,提高了3个月以上不活跃用户94%。
这种算法无疑是数据密集型,要智能地预测出给每一个客户发送消息的最佳时间,必须清楚的分析出这个用户的行为特征。除此以外,Appboy 天天将发送数千万智能交付消息,因此这里需求一个很是高的预测。
这里的方法是相似于 Intelligent Selection,主要经过实时地在每一个用户的基础上预聚合多个维度完成。有了 MongoDB,每一个用户都有不少 documents,相似下面代码:
{ _id: BSON::ObjectId of user, dimension_1: [DateTime, DateTime, …], dimension_2: [Float, Float, …], dimension_3: […], ... }
当所关心的用户维度数据进入时,应使其正规化,并保存 documents 的副本。经过{_id: “hashed”}
对每一个 documents 进行,从而让读写分布的更优化。当须要用 Intelligent Delivery 发送一条消息,这里能够快速地查询一系列 documents,并送到机器学习算法。在这个方面,MongoDB 带来的帮助很大,其可扩展性当下已支撑系统的数十个维度。而随着新的维度被添加,这个机器学习算法被不停的修改,而这个过程一直受益于 MongoDB 的灵活。
本文讨论了系统的主要设计思想,而这一切都得益于 MongoDB 灵活的模式和强扩展性。而经过 MongoDB,Appboy 在数据密集型工做上取得了一个很大的成功。
原文连接:Remaining Agile with Billions of Documents: Appboy’s Creative MongoDB Schemas
本文系 | 6803da6e1241c3b46359f28d015fd7e314 | 工程师编译整理。想阅读更多技术文章,请访问 OneAPM 官方博客。