H5计算器实现
php/mysql/jquery实现各系统流行的瀑布流显示方式,实现很简单的!!!!
大家在用这个东西的时候一定要计得有这么几个文件,一个是jquery.js 还有就是你自己数据库的密码。和相对应的图片才可以正常看到效果。下面就是这里所有的代码!!!
HTML文件:waterfall.html
1. [代码][PHP]代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
View Code <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > <html xmlns= "http://www.w3.org/1999/xhtml" > <head> <meta http-equiv= "Content-Type" content= "text/html; charset=utf-8" /> <title>瀑布流-Derek</title> <script type= "text/javascript" language= "javascript" src= "jquery.js" ></script> <link type= "text/css" rel= "stylesheet" href= "waterfall.css" /> <script type= "text/javascript" language= "javascript" src= "waterfall.js" ></script> </head> <body> <ul id= "stage" > <li></li> <li></li> <li></li> <li></li> </ul> </body> </html> /* * Javascript文件:waterfall.js */ $( function (){ jsonajax(); }); //这里就要进行计算滚动条当前所在的位置了。如果滚动条离最底部还有100px的时候就要进行调用ajax加载数据 $(window).scroll( function (){ //此方法是在滚动条滚动时发生的函数 // 当滚动到最底部以上100像素时,加载新内容 var $doc_height , $s_top , $now_height ; $doc_height = $(document).height(); //这里是document的整个高度 $s_top = $(this).scrollTop(); //当前滚动条离最顶上多少高度 $now_height = $(this).height(); //这里的this 也是就是window对象 if (( $doc_height - $s_top - $now_height ) < 100) jsonajax(); }); //做一个ajax方法来请求data.php不断的获取数据 var $num = 0; function jsonajax(){ $.ajax({ url: 'data.php' , type: 'POST' , data: "num=" + $num ++, dataType: 'json' , success: function (json){ if (typeof json == 'object' ){ var neirou, $row ,iheight,temp_h; for ( var i=0,l=json.length;i<l;i++){ neirou = json[i]; //当前层数据 //找了高度最少的列做添加新内容 iheight = -1; $( "#stage li" ).each( function (){ //得到当前li的高度 temp_h = Number($(this).height()); if (iheight == -1 || iheight >temp_h){ iheight = temp_h; $row = $(this); //此时$row是li对象了 } }); $item = $( '<div><img src="' +neirou.img+ '" border="0" ><br/>' +neirou.title+ '</div>' ).hide(); $row .append( $item ); $item .fadeIn(); } } } }); } /* * CSS文件:waterfall.css */ body{text-align:center;} /*Download by http://www.codefans.net*/ #stage{ margin:0 auto; padding:0; width:880px; } #stage li{ margin:0; padding:0; list-style:none;float:left; width:220px;} #stage li div{ font-size:12px; padding:10px; color:#999999; text-align:left; } /* * php文件:data.php */ <?php $link = mysql_connect( "localhost" , "root" , "" ); $sql = "use waterfall" ; mysql_query( $sql , $link ); $sql = "set names utf8" ; mysql_query( $sql , $link ); $num = $_POST [ 'num' ] *10; if ( $_POST [ 'num' ] != 0) $num +1; $sql = "select img,title from content limit " . $num . ",10" ; $result = mysql_query( $sql , $link ); $temp_arr = array (); while ( $row = mysql_fetch_assoc( $result )){ $temp_arr [] = $row ; } $json_arr = array (); foreach ( $temp_arr as $k => $v ){ $json_arr [] = (object) $v ; } //print_r($json_arr); echo json_encode( $json_arr ); |
2. [文件] waterfall.zip ~ 8KB 下载(850)
A/B测试:实现方法
上文介绍了 A/B 测试的基本概念 ,接下来我们继续探讨如何实现 A/B 测试。
我们先来看一个图:
(注:感谢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 下,页面横向的元素要精确一致,纵向上很难做到完全一致,但也要尽可能保持统一。另外,这样的测试也不太适合自适应宽度的页面,比较适合定宽 的页面,为了避免不同分辨率下页面左右空白不同导致鼠标点击位置的不同,点击位置取的应该是相对于测试区域 左上角的位置。除此之外,最好再记录一下测试区域相对于页面内容左上角的位置,在后面还原点击分布图以及绘制热区图时会用到这个数据。
这一阶段的流程大致如下图所示:
数据打点该如何发送以及如何存储呢?这要取决于你的打点服务器如何存储信息。
四、数据存储
我们使用了一台专用的服务器收集打点信息,为了能支持尽可多尽可能密集的打点请求,这台服务器的 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 日志中读取打点信息并加以分析,这已经和前端无关了,并且是一个比较复杂的问题,将在后续日志中介绍。
通过对web日志的挖掘来实现内容推荐系统
先说一说问题,不知道大家有没有这样的经验,反正我是经常碰到。
举例1,某些网站每隔几天就发邮件给我,每次发的邮件内容都是一些我根本不感兴趣的东西,我不甚其扰,对其深恶痛绝。
举例2,添加具有某功能的一个msn机器人,每天都有几次突然蹦出一个窗口,推荐一堆我根本不想知道的内容,烦不烦啊, 我只好将你阻止掉。
每一个观众只想看他感兴趣的东西,而不是一下与之无关的事物,那么如何才能知道观众的兴趣所在呢,还是数据挖掘,经过一番思考,终于有点思路,即根据用户 以往的浏览历史来预测用户将来的行为,也就是基于内容的推荐。
基于内容的推荐(Content-based Recommendation)是信息过滤技术的延续与发展,它是建立在项目的内容信息上作出推荐的,而不需要依据用户对项目的评价意见,更多地需要用机 器学习的方法从关于内容的特征描述的事例中得到用户的兴趣资料。在基于内容的推荐系统中,项目或对象是通过相关的特征的属性来定义,系统基于用户评价对象 的特征,学习用户的兴趣,考察用户资料与待预测项目的相匹配程度。用户的资料模型取决于所用学习方法,常用的有决策树、神经网络和基于向量的表示方法等。 基于内容的用户资料是需要有用户的历史数据,用户资料模型可能随着用户的偏好改变而发生变化。
基于内容推荐 方法的优点是:
1)不需要其它用户的数据,没有冷开始问题和稀疏问题。
2)能为具有特殊兴趣爱好的用户进行推荐。
3)能推荐新的或不是很流行的项目,没有新项目问题。
4)通过列出推荐项目的内容特征,可以解释为什么推荐那些项目。
5)已有比较好的技术,如关于分类学习方面的技术已相当成熟。
缺点是要求内容能容易抽取成有意义的特征,要求特征内容有良好的结构性,并且用户的口味必须能够用内容特征形式来表达,不能显式地得到其它用户的判断情 况。
要实现内容推荐系统总体来说要经过4个大的步骤:
1 搜集数据,即搜集用户的行为资料,其中也包括很多方法,根据我找到的资料与以往的经验来看,web日志可以作为我们的切入点,即我们的数据来源。
2 过滤数据,web日志中有很多无用的信息,我们要把这些无用的信息排除掉,而且要区分出用户和日志数据之间的联系。
3 分析数据,利用分类聚类技术分析出这些日志数据之间的关联性,以及这些日志数据和用户之间的关联性,这也是最重要的一步。
4 输出结果。
有了这个思路之后,我们可以着手做第一步,即日志数据的收集
我们知道,大多数的web服务器都是有自己的日志记录的,比如说apache安装之后有一个logs目录,其中就有它的日志文件,一般说来它有自 己的一个格式,比如说:
1浏览器所在主机的 IP 地址(ip);
2访问日期和时间(date-time);
3客户机与服务器通信所用的方法(methed,get or post);
4客户机请求访问页面的 URL;
5服务器返回的状态(status);
6客户端浏览器的类型;
但是这个日志文件有一些不能克服的问题,或者我不知道如何克服,那么我先说说我的疑问,首先,这个日志文件中记录的是ip地址,据了解,网络中有很多计算 机的ip地址是相同的,因为他们在一个统一的路由后面,这个比例可能达到25%。那么我们就无法根据ip地址来唯一确定一个用户。其次,一般的web服务 器中都会用多个应用,那么其他应用的访问信息对我们来说有可能是多余的。再者,web服务器的日志形式比较单一,灵活性不大,可定制的余地很小,在日志数 据中有效数据所占的比例较小。还有,一些静态文件的请求也会被web服务器记录下来,比如说js文件,css文件,还有图片文件,等等这些东西对内容推荐 来说都是无用的资源。
基于上面3点原因,我认为可以自定义日志数据。为了解决用户唯一性,我们让应用为每一个浏览器生成一个clientId保存在对应的浏览器上,这样该浏览 器只要访问网站,我们就可以确定这个浏览器的唯一性,当然我们仍然不能确定浏览器使用者的唯一性,但是我们可以更进一步,如果浏览器的使用者登陆网站的 话,我们就可以使用用户id来确定用户的唯一性,不过大多数网站用户可能在使用网站的时候并不会登陆,我也是这样,没有关系,即使使用clientId问 题也不会太大,随着社会的发展,计算机的拥有量逐渐增加,一般来说一个人只会使用一台固定的电脑,在公司里尤其是这样。所以我认为clientId的方案 是可行的,也许有人要问,别人的浏览器禁止了cookie怎么办,那么我只能说没有办法,不过还好事实是绝大多数人都没有这样做。
接下来我们可以定义一下我们所需要的日志数据的格式,比如这样,
ip,clientId,userId,url,datetime,get or post等等。
这样数据有效性会大大提高。
在得到较为有效的数据之后,我们还需要对这些数据进行再次过滤:
1 去掉一些非内容的url,这些数据也是无效数据,这些非内容的url需要我们自己手工的统计出来,然后和日志数据中的数据进行比对,将这些非内容数据从日 志数据中清除出去。
2 同时我们也需要把post请求从日志数据中清除出去,或者我们在记录日志的时候根本不应该把post请求记录下来。
经过以上步骤之后我们就可以开始第3个阶段了,统计每个用户的访问的url,对这些url进行访问,得到对应的html中所包含的数据,这些数据都是文 本,将有用的文本提取出来,然后对这些有用的文本进行聚类。这样就可以得到每个用户喜欢的几个类别。
聚类完成之后我们就可以开始分类了,即把最新的文章或者内容和对应的类别进行匹配,匹配成功之后,我们可以认为这个新文章或者内容可以推荐给对应的用户。
问题:以上的流程只适用于没有使用缓存的系统,但是一般大型的网站都会使用varnish,squid等等,使用它们之后我们就无法得到用户访问的日志数 据了,所以如果使用了varnish或者squid,我们不得不再次面对web服务器的日志数据。
在不考虑varnish或者squid的情况下,使用lucene+jamon+htmlparse基本就可以实现以上推荐系统。