问题背景:如果你负责开发维护一个大型网站,有一天老板找产品经理要网站每个网页每天的UV数据,然后让你来维护这个统计模块,你应该如何实现?

  注明一下几个词的意思

    UV(unique visitor):指通过互联网访问、浏览这个网页的自然人。访问您网站的一台电脑客户端为一个访客。一天内同一个访客的多次访问仅计算一个UV。

    PV(page view):页面浏览量,用户对同一页面的多次访问,其访问量都累计下来。


  直观的一个可行方案,UV可以用一个集合,PV直接为每个页面设置一个计数器,每次访问加一。

  这个做法的问题也很直观,当用户量非常大的时候,UV需要的这个集合就会非常非常大,即便可以采用为用户分配uuid之类的方式,但是这还是非常庞大的一个数据量。这个时候就能用上redis的HyperLogLog结构。

  HyperLogLog就是redis用来解决这种问题的方案,值得注意的是,HyperLogLog提供的是不精确的统计方案,标准误差为0.81%,但是对于UV来说,这种误差已经可以满足需求了。

  文中作者介绍了HyperLogLog的三个指令

    pfadd key value1 value2... 向其中添加元素

    pfcount key 查询其中的元素数量

    pfmerge key1 key2... 将多个HyperLogLog合并为一个,保存至key1中 (2.8.9后可用)

  关于指令中的pf(本来我以为会是hll之类的!),pf是这个数据结构的发明者Philippe Flajolet名字的简写,上一张老教授的照片!

 

  注意,HyperLogLog在计数比较小的时候会采用稀疏矩阵的形式,占用空间比较小,在计数变大时,超过一定阈值会转变为稠密矩阵,占据12K的空间。因此,该结构不适用于保存单个用户的相关信息,毕竟如果一个用户12K,在用户量巨大的时候占据的空间就太大了。

HyperLogLog的内部实现原理。。。好后悔我没好好学概率论,我浏览一遍之后,大概意思说的就是这种结构应该说的是基于统计数据的结果。。。再多的我就看不懂了,文中作者提到想要详细了解的可以阅读Count-Distinct Problem,我找了以下,同名的不少,不知道具体指的是哪一篇,也没有在附录中找到相关链接,比较遗憾(找到了我也看懂。。)