A/B 测试的实现方法

标签: 数据分析 | 发表时间:2012-04-20 17:38 | 作者:黄言之
出处:http://blog.sina.com.cn/netreview

  我们先来看一个图:  



  上图展示了 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 下,页面横向的元素要精确一致,纵向上很难做到完全一致,但也要尽可能保持统一。另外,这样的测试也不太适合自适应宽度的页面,比较适合 定宽的页面,为了避免不同分辨率下页面左右空白不同导致鼠标点击位置的不同,点击位置取的应该是相对于 测试区域左上角的位置。除此之外,最好再记录一下测试区域相对于页面内容左上角的位置,在后面还原点击分布图以及绘制热区图时会用到这个数据。

  这一阶段的流程大致如下图所示:  



  数据打点该如何发送以及如何存储呢?这要取决于你的打点服务器如何存储信息。

  四、数据存储

  我们使用了一台专用的服务器收集打点信息,为了能支持尽可多尽可能密集的打点请求,这台服务器的 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 日志中读取打点信息并加以分析,这已经和前端无关了,并且是一个比较复杂的问题,将在后续日志中介绍。

 

全文转载自: http://oldj.net/article/AB-Testing-method/

 

相关 [测试 方法] 推荐:

敏捷测试的方法和实践

- tossking - 《程序员》杂志官网
有一次,当开发人员完成当前Sprint 任务的代码之后,测试人员、开发人员和产品经理一起来浏览产品、从头到尾走一遍,产品经理发现了问题,认为需要对功能进行比较大的修改. 这时开发人员估计需要两天时间才能完成代码,但测试人员反对这样做,我们本来只有5天测试时间,加上这次新做的功能比较多、开发代码质量不高,验收测试已经很紧张.

集成测试-意义和方法

- - 人月神话的BLOG
集成测试是将模块按照设计要求组装起来同时进行测试,主要目标是发现与接口有关的问题. 如数据穿过接口时可能丢失;一个模块与另一个模块可能有由于疏忽的问题而造成有害影响;把子功能组合起来可能不产生预期的主功能;个别看起来是可以接受的误差可能积累到不能接受的程度;全程数据结构可能有错误等. 集成测试是单元测试的逻辑扩展.

A/B 测试的实现方法

- - 互联网旁观者
  上图展示了 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).

VM性能的快速测试方法

- - 婉兮清扬
前段时间陆续发布了一些对公有云服务性能评测的数据. 经常有同行问我怎么样去做这些性能评测. 其实这些性能评测都很简单,任何一个具备Linux基础知识的工程师都可以完成. 我们通常使用UnixBench来评估虚拟机整机性能,mbw来评估内存性能,iozone来评估磁盘IO性能,iperf来评估网络性能,pgbench来评估数据库性能.

界面测试的方法要点

- - 博客园_首页
b 、标题栏中(最大化、最小化、关闭)按钮,根据窗口的特性,如没有最大化或者最小化状态的窗口,应该不显示最大化和最小化按钮,或者把按钮 Disable 状态显示. ( 1 )文字描述的准确性:. a 、检查文字的描述和所对应的功能是否一致;. ( 2 )文字用语的一致性:. (菜单、界面按钮或者 Label 等、 ToolTip 、窗口标题).

php类方法在线性能测试

- - CSDN博客编程语言推荐文章
在两个月前一个群里的朋友问了一个问题,他说:“现在他们公司的项目有一个模块的性能在线表现非常差,很长时间没有查出问题所在,老板一怒之下让他把所有类方法的执行时间给记录进行分析,并且不能影响现在的项目性能. ”老板让他记录这些信息是为了分析具体影响性能的地方在哪些地方,待项目运行一段时间就去除. 这个需求导致两个个问题,第一是怎么监听这个模块所有类方法的执行时间,第二是怎么能在不影响现在项目性能的情况下完成(本身性能就很差了),下面我们就这两个问题来分析:.

Linux主机性能测试方法

- - Mythsman
最近打算用躺家吃灰的树莓派4B搭一个NAS,用来快捷方便地访问和备份一些资源. 由于备选的硬件(芯片、硬盘、网线、路由器等)和软件(内网穿透技术)的技术选型比较多,这时候就需要有一个能简单评估服务性能的方法. 因此简单搜寻了一下常见方案,方便在技术选型时有个统一的对比标准,并且对一些常见指标能在数量级上有一些感性的理解.

谈谈网站测试中的AB测试方法

- - 博客园_知识库
  A / B测试,即你设计的页面有两个版本(A和B),A为现行的设计, B是新的设计. 比较这两个版本之间你所关心的数据(转化率,业绩,跳出率等) ,最后选择效果最好的版本.   A / B测试不是一个时髦名词. 现在很多有经验的营销和设计工作者用它来获得访客行为信息来提高转换率. 这是一种很有效的方式,并且由于各种分析工具的发展,测试成本也越来越低,因此很多电商网站都会采用.

可用性测试中的任务设计方法

- 嘉慧 - 网易用户体验设计中心博客
可用性是用来衡量产品质量的重要指标,从用户角度来判断产品的有效性、学习性、记忆性、使用效率、容错程度和令人满意的程度. 可用性测试是在迭代设计中不断获得用户反馈,根据用户反馈不断优化产品设计的一种方法. 其目的是是建立评价标准,尽可能多的发现可用性问题,并指导产品界面的设计和改进,尽可能地提高产品的可用性质量.