[原]使用算法放大用户点击坐标数据的粒度

    最近在公司昨做了一个关于用户点击行为的各种统计,其中包括最直观的 点击热点图。   样貌如下: 

    

    我是做后端的,前端肯定直接用写好的库,其中用到的生成热点图的类库是 heatmap,详情参看 github。在此感谢作者。

    关于这个heatmap 还是有一些坑的,之后我在写一个关于heatmap的文章。下面介绍另外的一个问题,就是数据量的问题。一个网站的页面用户的点击量是很大的,即使只有一天。因为用户的每一次点击都会被记录下来。这些数据不论存储在关系数据库里面 还是 nosql里面 都是不小的。效率问题很严重。

    如果这个页面被点击了100W次,再除去坐标重复,因为存储的时候会有一个坐标计数,也就是同一个坐标被点击多次,只有一个记录,但是即使这样,数据量依旧很大,将近100W条记录。这在程序里面直接读出来然后交给JS再画到canvas画布上,服务器内存再大也是吃不消的,

    举个栗子:如果PHP被开的memory limit 内存限制是8G的话,也就能取出10-20W条记录,就爆掉了。而且没有大数据字段,字段数据量都不大。

    比如我们当时的记录是 url:xxxx , x_y:100,200 , count 10 , time:xxxxxx 。就是这样一些简单的字段。

    所以解决方案有两种:

    1. 分批次取出数据,不要一次都取出来,可以用异步获取数据的方式,一边画坐标,一边取数据。这个具体实现就不多说了,就是简单的ajax。

    但是这种方式的弊端是,太消耗前端性能!如果每次ajax取出1W条记录,就需要100次ajax请求,然后分别画到canvas上。

    实验的结果是:90%的浏览器在这一过程中都无响应了,因为大多数开发是ubuntu和mac,ubuntu和低配mac直接挂掉了,高配mac坚持了下来,但是等待过程也比较漫长,而且画的过程中,浏览器那个标签也是卡住的。

    2.减少数据条数。这就是我们今天的重点了。

    减少数据条数一定会影响精度,但是热点图的目的是看用户的点击趋势,只要精度在一定范围内能接受,不影响用户趋势即可。

    所以我们的做法就是: 合并坐标。

    结果是,简单粗暴,行之有效滴~

    我们会把所有的位于同一个边长为10的正方形内的点,都移动到这个正方形的中心点上。

    例如: 0,10  -> 10,10 这个坐标系最左上角的正方形,会把所有的点都集中在 5,5 这个坐标点上,也就是说,在坐标全覆盖的情况下,会将100个点合并成一个点,该点的点击次数100次。那也就是说理论上,记录数会缩小100倍,经过这样的处理 100W条记录就只剩下 1W条了哦(这是理想情况,实际情况下,会根据点的分布,不一定,但是一般会缩小到1-10W之间),而且精度上上下只会相差5个像素,在页面上画出的点 还是完全能够接受的。效果非常不错。

    具体的逻辑转化,其实非常非常简单,也就是上面说的 简单粗暴。既不用假设页面上已经画好了田字格,也不用坐标点之间的比较。一个简单的数学计算即可解决。

    ((a/10)舍去取整)*10 + 5     

    是不是很简单,只要将坐标的 x,y 的数值分别带入这个公式,替换a,既可以计算出这个坐标的最后所属啦。当然,除10和乘10的这个倍数是可以根据实际情况替换的,如果你换成20 那就意味着,缩小了400倍,一次类推。

    PHP的实现是:

floor(x/10)*10+5

 最后根据计算的结果重新计算count。再存入数据库。

 

 小结:

    鉴于最后100W记录最后会变成7W左右的记录数(这个每个网站的情况不同),所以我们最后是方案1 和 方案2 同时使用了,既缩小了记录数,也分段异步获取了数据,最后的效果还不错,精度上的影响是非常小的,而且其他的人也都可以正常查看这个直观的 用户点击热点图 了呢。