1. 程式人生 > >A/B 測試的基本概念舉例理解以及具體實現方法【傳統A/B測試基於後端的 A/B 測試(Back-end AB test),現在基本上基於前端js在客戶端進行分流,有更多優點,請看裡面】

A/B 測試的基本概念舉例理解以及具體實現方法【傳統A/B測試基於後端的 A/B 測試(Back-end AB test),現在基本上基於前端js在客戶端進行分流,有更多優點,請看裡面】

文章來源:http://www.aliued.cn/2010/09/27/ab-testing-realization-method.html

什麼是A/B測試?以及如何進行?

很多朋友都問我怎麼進行A/B測試,我一般都不直接回答他們的問題,而是首先問一句:“你的日IP是多少?”。當對方的回答是不到一百的時候,我一般都說這個沒必要了解。

    或許你會納悶,為什麼日IP少的站沒必要了解A/B測試,原因很簡單,A/B測試需要大量的IP,如果你的IP只有十幾個,那麼測試出來的資料很可能不是很準確,換句話說A/B測試的站日流量越大測試的結果越準確。

    好了,說了這麼多,還是把A/B測試跟大家談談吧。

    舉個簡單的例子,當你有一個日IP過千的網站,而你的
網站首頁
幾百年沒有更改了,這個時候你想啟用新的網頁,而你有害怕新的頁面使用者不一定就非常喜歡,那麼這個時候你就需要進行A/B測試了。測試的方法是將老頁面定義為A頁面,新頁面定義為B頁面。到谷歌網站優化工具申請進行A/B測試(免費的),這是時候谷歌會給你一串程式碼,我們只需要將程式碼新增到谷歌要求的頁面即可。 程式碼新增完畢,如果有一千個使用者訪問你的網站,那麼會有500個使用者看到A頁面,500個使用者看到B頁面,這個時候再統計下通過A頁面到達網站內頁的使用者佔的百分比是多少,通過B頁面到達內頁的使用者佔的百分比是多少。假設A的是6%,B的是20%那麼恭喜你,這說明你新設計的頁面是博得了使用者的歡心。如果你對20%的結果還不滿意,那麼繼續修改你的頁面,直到這個轉化率不能夠再提高為止。 A/B測試是一個科學的統計方法,這一統計的誕生,再也不用為了爭吵是使用A圖片好,還是使用B圖片好,好不好,按照效果說算。還是鄧爺爺說的好,
實踐是檢驗真理的唯一標準
。停止爭吵,來做個A/B測試吧。 前提是你要有上千的IP,而且還是每日。資料太小的話,往往不準確。

上文介紹了 A/B 測試的基本概念,接下來我們繼續探討如何實現 A/B 測試。

我們先來看一個圖:

A/B testing 部署概念圖

(注:感謝Algo提供本圖。)

上圖展示了 A/B 測試的實現原理。從左到右,四條較粗的豎線代表了 A/B 測試中的四個關鍵角色:客戶端(Client)、伺服器(Server)、資料層(Data)、資料倉庫(Data Warehouse)。從上到下代表了三種訪問形式:無 A/B 測試的普通訪問流程(Non AB test)、基於後端的 A/B 測試訪問流程(Back-end AB test)、基於前端的 A/B 測試訪問流程(Front-end AB test)。

一般情況下,使用者在一次瀏覽中,會從客戶端(Client)發起一個請求,這個請求被傳到了伺服器(Server),伺服器的後臺程式根據計算,得出要給使用者返回什麼內容(Data),同時向資料倉庫(Data Warehouse)新增一條打點資訊,記錄本次訪問的相關資訊。這個過程也就是圖上橫向的流程。資料倉庫收集到足夠的資料之後,就可以開始進行分析(Analytics)了,這也即是圖中右上角的部分。

A/B 測試需要將多個不同的版本展現給不同的使用者,即需要一個“分流”的環節。從上圖中我們可以看到,分流可以在客戶端做,也可以在伺服器端做。傳統的 A/B 測試一般是在服務端分流的,即基於後端的 A/B 測試(Back-end AB test),當用戶的請求到達伺服器時,伺服器根據一定的規則,給不同的使用者返回不同的版本,同時記錄資料的工作也在服務端完成。

基於後端的 A/B 測試技術實現上稍微簡單一些,不過缺點是需要技術部工程資源介入,另外收集到的資料通常是比較巨集觀的PV(Page View)資訊,雖然可以進行比較複雜的巨集觀行為分析,但要想知道使用者在某個版本的頁面上的具體行為往往就無能為力了。

基於前端的 A/B 測試則可以解決上面的問題。它的特點是,利用前端 JavaScript 方法,在客戶端進行分流,同時,可以用 JavaScript 記錄下使用者的滑鼠行為(甚至鍵盤行為,如果需要的話),直接傳送到對應的打點伺服器記錄。這樣的好處是不需要技術部(如果你們和我們一樣,前端工程師與後端工程師分屬不同部門的話)參與,並且可以比較精確地記錄下使用者在頁面上的每一個行為,甚至包括後端方法難以記錄到的無效點選!

下面,我將重點介紹一下我們在基於前端的 A/B 測試上的一些實踐。


一、分流

首先遇到的問題是如何分流的問題。對於大部分需求來說,我們希望各個版本的訪問人數平均分配。解決辦法有很多種,比較簡單的一種即是前面提到過的,根據某一個 Cookie ID 來劃分使用者,前提是你的網站上每一位訪客在第一次訪問時就要有一個不重複的 Cookie ID,比如“123.180.140.*.1267882109577.3”。然後,可以根據這個 Cookie ID 的最後一位(在本例中是“3”)來劃分人群,比如單數的顯示 A 版本,偶數的顯示 B 版本。

因為 Cookie ID 一般設定後不會輕易改變,基於 Cookie ID 的好處是我們能很好地對訪客保持一致性,某個使用者如果第一次看到的是 A 版本,那他重新整理後看到的還是 A 版本,不會一會兒看到 A 版本一會兒看到 B 版本。但不足之處就是如果使用者瀏覽器不支援 Cookie 的話,分流就不能正常進行了。不過,現代瀏覽器預設情況下都是支援 Cookie 的,如果真有使用者的瀏覽器不支援 Cookie ,那也應該是極少數特殊情況,對結果的影響非常微小,對於這些特殊情況,我們一般可以安全地忽略掉。

還有一點需要注意的是,A/B 測試的頁面必須有較高的 UV (Unique Visitor,獨立訪客數),因為分流帶有一定的隨機性,如果頁面 UV 太小,分到每一個版本的人數就更少,結果很有可能被一些偶然因素影響。而 UV 較大時,根據大數定理,我們得到的結果會接近於真實資料。就像想知道一個地方的成年人的平均身高,當然是取的樣本越大結論越可信。

二、展示

決定向當前訪問者顯示哪個版本後,怎麼用前端的方法載入對應的版本呢?這需要分情況處理。

一般情況下,如果兩個版本只有一個較小的區域不一樣,我們可以同時將兩個區域的 HTML 都載入到當前頁面中,先用 CSS 把它們隱藏起來(也可以預設顯示一個版本),等 JS 判斷出該顯示哪個版本後,再控制對應版本的 CSS 顯示。

有時候,測試區域比較大,程式碼比較多,或者需要後臺較多的計算資源,如果一開始就把兩個版本的 HTML 全載入到當前頁面中,就會需要比較大的開銷(比如頻寬、後臺計算量)。這種情況下,我們可以先把測試區留空,之後再用 Ajax 的方式延遲載入。

還有的時候,測試區域非常大,幾乎佔了整個頁面,或者完全就是不同的頁面,這時,用 Ajax 方式載入也不適合了,可以將不同的版本做成不同的頁面,然後再用 JS 跳轉。不過這樣的方式並不是很好,因為前端 JS 跳轉需要一定的時間,這個過程很有可能被使用者感受到,並且留下不好的體驗。對這個問題,似乎沒有很好的解決辦法,至少在前端層面很難完美解決,所以並不是非常推薦這種跳轉方式,如果真的需要跳轉,最好是在伺服器端由後端程式碼來操作。

三、資料採集

正確展示對應的版本後,就要開始採集需要的資料了。有一個可選的資料,是當前版本有多少 PV (Page Views,訪問量),如果需要記錄這個資料的話,在正確版本載入完成之時就要傳送一個打點資訊。不過很多需求中,具體版本的 PV 的精確數值可能不是很重要,而且要收集這個資訊需要多一次打點操作,所以一般情況下這個資料是可選的。

必須的資料是測試區域內使用者的點選資訊。當用戶在測試區域點選了滑鼠左鍵(無論這個點選是點選在連結、文字、圖片還是空白處),我們就需要傳送一條對應的打點資訊到打點伺服器。一般來說,這個打點資訊至少需要包含以下資料:

當前 A/B 測試以及版本標識

點選事件的位置

點選時間戳(客戶端時間)

當前點中的URL(如果點在非超連結區域,此項為空)

使用者標識(比如 Cookie ID)

使用者瀏覽器資訊

為了儘可能精確地還原使用者的點選位置,我們的頁面對前端有比較高的要求,要求頁面在不同的瀏覽器下有基本一致的表現,至少在IE6、7、8以及 Fiefox 下,頁面橫向的元素要精確一致,縱向上很難做到完全一致,但也要儘可能保持統一。另外,這樣的測試也不太適合自適應寬度的頁面,比較適合定寬的頁面,為了避免不同解析度下頁面左右空白不同導致滑鼠點選位置的不同,點選位置取的應該是相對於測試區域左上角的位置。除此之外,最好再記錄一下測試區域相對於頁面內容左上角的位置,在後面還原點選分佈圖以及繪製熱區圖時會用到這個資料。

這一階段的流程大致如下圖所示:

A/B 測試打點生命週期

資料打點該如何傳送以及如何儲存呢?這要取決於你的打點伺服器如何儲存資訊。

四、資料儲存

我們使用了一臺專用的伺服器收集打點資訊,為了能支援儘可多儘可能密集的打點請求,這臺伺服器的 apache 服務網站目錄下只有兩個靜態檔案,分別是 abtest.html 和 abtest.gif ,兩者都是非常小的空白檔案(空白圖片)。訪客端進行打點時,只需要以 GET 的方式帶上相關的引數請求兩個檔案中的任意一個即可。比如:

http://abtest.xxx.com/abtest.gif?abid=1-a&clickBlockX=244&clickBlockY=372&clickBlockW=392&clickBlockH=76&clickTime=1263264082137&clickRX=233&clickRY=47&clickURL=&clickBeaconID=123.180.140.*.1267882109577.3&browserType=FireFox

這個請求可以通過 Ajax 的方式傳送,也可以通過 JS 在頁面上建立 new Image() 物件的方式完成。

對打點伺服器來說,這只是一條普通的 HTTP 請求,它會在日誌裡留下一條普通的日誌記錄,形如:

123.180.140.* – – [13/Jan/2010:15:21:15 +0800] “GET /abtest.gif?a=123&b=456&c=789 HTTP/1.1″ 304 – “-” “Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.6 (KHTML, like Gecko) Chrome/4.0.266.0 Safari/532.6″

可以看到了,除了 JS 傳送給我們的資訊外,Apache 還幫我們記錄了一些資訊,比如訪客 IP 、伺服器時間、使用者瀏覽器資訊。

對於資料記錄和儲存來說,到這一步就足夠了。Apache 靜態檔案 + 日誌的方式足夠高效,基本不用擔心效能的問題。剩下的,就是另外一個問題,如何從 Apache 日誌中讀取打點資訊並加以分析,這已經和前端無關了,並且是一個比較複雜的問題,將在後續日誌中介紹。