摘要: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 官方博客。