转:A/B测试:实现方法

概念:http://www.aliued.cn/2010/09/13/ab-testing-basic-concept.html

我们先来看一个图:

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 日志中读取打点信息并加以分析,这已经和前端无关了,并且是一个比较复杂的问题,将在后续日志中介绍。

转载于:https://www.cnblogs.com/wujin/p/6773370.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/269532.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

同学录

在中学同学的提醒下,去5460和ChinaRen的同学录更新了我的联系方式等等,了解到中学同学过年时在家乡搞了一个聚会。很久没有见过他们了,最近的一次是去年在zte南研所见到张辉,他从zte深圳来南京出差,此后不久我就离开了…

linux命令编写四位数密码本,grub-crypt命令 – 对口令进行加密

grub-crypt命令的作用是对口令进行加密。grub-crypt命令支持对口令进行MD5和SHA加密,默认情况下是对口令进行SHA-512加密。SHA是Secure Hash Algorithm的简写,中文为安全散列算法,是美国国家安全局 设计,美国国家标准与技术研究院…

mac修改host

1.打开终端 2.输入sudo vi /etc/hosts 3.输入密码 4.进入文件hosts,然后按“i”,进入编辑模式 5.把你的host添加到最后 6.esc推出编辑模式 7.输入:wq,保存退出

宝洁广告的智慧

有趣的是,一大批写文章针砭宝洁拿稿费的营销高手,同时也在满心期待某天能加入宝洁一了夙愿。而宝洁的形象之所以如此深入人心,除了家家户户都在用宝洁公司的产品之外,更离不开十余年宝洁公司通过“宁拙勿巧、气势绵长”的广告运作…

语法之知识点的改进(Func/Action)

上一章我们讲到关于面向对象思想上C#和JAVA之差别。笔者分别从面向对象的三大特性入手。而本章主要讲一些C#改进的知识点。在.NET Framework 2.0之后出现很多新的知识点。这些知识点更是让C#在写法上更加的多样性。有些写法还真的让笔者觉得很有不错。由于这一部分的知识更多是…

linux取字符串的前面,Linux Shell 截取字符串

shell中截取字符串的方法很多${var#*/}${var##*/}${var%/*}${var%%/*}${var:start:len}${var:start}${var:0-start:len}${var:0-start}下面用几个例子展示一下:1) 获得字符串的长度语法:${#var}示例代码:str"http://www.fengbohello.xin…

vs.net 2005 beta 2安装问题

我之前已经卸载了BETA 1了,但可惜安装后,在新建工程后,还是出现 "package load failur"等错误信息。比较郁闷。于是搜索了下,发现有位外国牛人的blog,提供了很好的解决方法 http://blogs.msdn.com/astebner/default.asp…

idea修改新的git提交地址

更换git地址步骤 1、点击VCS 2、点击Git 3、点击Remotes 点击框中链接即可在右边看到一个铅笔字样的按钮,即可看到如图所示弹窗 点击铅笔(编辑),看到新的弹窗,链接已经被默认选中这时候粘贴新的git地址,点…

[HNOI2008]玩具装箱toy(dp+斜率优化)

斜率优化问题一般都是决策单调问题。对于这题能够证明单调决策。 令sum[i]sigma(c [k] ) 1<k<i , f[i]sum[i]i , cL1; 首先我们能够写出转移方程 dp[i] min( dp[j] (f[i]-f[j]-c)^2 ) 。令决策j1<j2。若决策j2更优有 dp[j2](f[i]-f[j2]-c)^2<dp[j1](f[i]-f[…

全球500强企业人力资源管理之道

美国杜邦的组织机构改革 美国杜邦公司(DuPont)是世界上最大的化学公司&#xff0c;建立至今&#xff0c;已近200年。杜邦公司所创设的组织机构&#xff0c;曾成为美国各公司包括著名大公司的模式&#xff0c;并反映了企业组织机构发展演变的一般特点。 拜耳公司人力资源管理…

mac idea实现全局替换

点击Edit ----- Find ----- Replace in Path 例如要把项目中的cc替换为aa 点击Replace All

linux下防火墙脚本,Linux系统如何修改防火墙配置

这篇文章主要介绍了Linux系统如何修改防火墙配置,文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下改Linux系统防火墙配置需要修改 /etc/sysconfig/iptables 这个文件vim /etc/sysconfig/iptables在vim编辑器&…

现代希腊语字母表

转载于:https://www.cnblogs.com/zhangzujin/p/6782532.html

在俱乐部首页看不到的团队成员(更新中...)

截至到目前&#xff0c;可能因为暂时在博客园没有用户ID&#xff0c;在深圳.NET俱乐部首页看不到的几位成员是&#xff1a;1.小郑&#xff1a;没有留下任何信息&#xff0c;如果看到的话请补充。2.周文军&#xff1a;zhouwjsytech.com.cn &#xff1b;深圳时代高科&#xff1b;…

SHA-1算法c语言实现

安全哈希算法&#xff08;Secure Hash Algorithm&#xff09;主要适用于数字签名标准 &#xff08;Digital Signature Standard DSS&#xff09;里面定义的数字签名算法&#xff08;Digital Signature Algorithm DSA&#xff09;。对于长度小于2^64位的消息。SHA1会产生一个160…

Mac安装RocketMQ和可视化控制台教程

1:下载: http://rocketmq.apache.org/docs/quick-start/, 直接下载源代码版本 2:使用maven进行源码编译: mvn -Prelease-all -DskipTests clean install -U 3:环境配置 找到已经安装好的 jdk 位置&#xff0c;通过命令&#xff1a;/usr/libexec/java_home 在.zshrc中加入JAVA…

防止多重启动之调用Api [收集2005090201]

防止多重启动之调用Api (效果:第二次启动程序则前一进程的窗口跳到最前) using System.Threading;private const int SW_NORMAL 1; // see WinUser.h for definitions private const int SW_RESTORE 9; [DllImport("User32",EntryPoint"FindWindow")] …

交叉编译 linux库,linux交叉编译和动态库/链接

我正在努力为BeagleBoard开发。因此我安装了CodeSourcery SourceryG Lite Toolchain。我想使用opencv库。所以我将源码下载到我的Ubuntu devolepment系统中&#xff0c;并使用gcc编译为共享库并安装了该库。当我为x86架构构建helloworld应用程序时&#xff0c;一切都很好。现在…

poj 2109 Power of Cryptography

Power of CryptographyTime Limit: 1000MS Memory Limit: 30000KTotal Submissions: 18408 Accepted: 9292题目大意 给出两个数n&#xff0c;k要你求个数ans ans^nk关于题目中的数据范围全然能够用double完爆 不是必需用到二分高精度可是double类型尽管能表示10^(-307) ~ …