【Redis笔记】一起了解 Redis 中的 HyperLogLog 算法?

HyperLogLog是一种用于近似基数统计的算法,旨在使用有限空间处理大量唯一值。在Redis中,HyperLogLog数据结构实现了这一算法,用于高效估算UV等大数据集合的基数。其核心原理基于伯努利试验,通过记录每个桶内伯努利过程的最大k值,然后取所有桶的k值平均,用估算公式计算基数。Redis的每个HyperLogLog占用12kb空间,理论上可支持2^64量级的数据量。

一起了解 Redis 中的 HyperLogLog 算法?


如果觉得对你有帮助,能否点个赞或关个注,以示鼓励笔者呢?!博客目录 | 先点这里

  • 前提概念

    • 需求
    • 什么是 HyperLogLog ?
    • 什么是基数?
    • 基数统计
  • 应用

    • 需求
    • 应用
  • 原理

    • 伯努利试验
    • 原理
  • Redis 实践

    • Redis HyperLogLog 与伯努利试验的联系?
    • Redis HyperLogLog 的实现?

前提概念


什么是 HyperLogLog?

HyperLogLog
HyperLogLog 是一种算法,其来源于论文 《HyperLogLog the analysis of a near-optimal cardinality estimation algorithm》,是 LogLog 算法的升级版本,主要的目的就是利用统计学原理做近似基数统计。优势就是利用一个较小的固定大小空间计算任意大小的 Distinct Value
在这里插入图片描述

Redis 的实践
HyperLogLog 并非 Redis 一家独有,Redis 只是基于 HyperLogLog 算法实现可一个 HyperLogLog 数据结构,并用该数据结构提供基数统计的功能。其优势就是可以做到只需要 12 kb 的空间大小,就可以实现接近 2^64 量级的基数统计。

HyperLogLog 数据结构并不会保存真实的元数据,所以其核心就是基数估算算法
在工程实践中,通常会用于 App 或页面的 UV 统计


什么是基数?
什么是集合?

在了解数学概念上的基数之前,我们先来了解下在数学上,是怎么描述 “集合” 的。

集合Set), 也成集,是集合论的主要研究对象。集合是指具有某种特定性质的具体或抽象的对象汇总而成的集体。其中构成集合的这些对象则称之为该集合的元素

集合特性

  • 确定性
    给定一个集合,任给一个元素,该元素只可能属于或不属于该集合。不存在模棱两可的情况
  • 互异性
    一个集合中,任何两个元素都可以被认为是不相同的,即每一个元素只会在集合中出现一次,具有去重性质
  • 无序性
    一个集合中,所有元素的地位都是相同的,元素之间是无序的

在本文中重点记住,集合中的元素是具互异性的

什么是基数?

基数 (cardinal number) 在数学上,是集合论中刻画任意集合大小的一个概念。通俗点讲,基数就是对集合元素的计数

  • 结合对集合的理解,大白话就是,基数就是指一个集合中不同元素的个数

  • 元素集合可以是有限集合或无限集合,如果是有限集合,那么集合的基数就是一个特定的自然数;如果是无限集合,那么其基数就不是一个自然数了

  • 基数(数学)-@wiki

基数?集合大小

我们知道基数就是对集合元素的计数,那说白了不就是集合元素的个数吗?为什么要引申出基数的概念,不直接使用集合大小?

这里直接贴上知乎 @lvony 的回答

  • 基数就是严格意义上的集合元素多寡,为什么不直接用集合大小或者元素个数来描述,我觉得主要是所有集合的基数集合不是自然数集合的子集。换言之所有的自然数都是基数,但不是所有的基数都是自然数
  • 如无穷集合的基数都不是自然数

基数统计

我们可以知道,基数可以简单理解成集合中不同元素的个数。那么什么是基数统计呢?在工程实践大数据领域,要精确的计算基数是十分困难的。为什么这么说呢?假设你要实现大数据集合的精确基数统计,通常我们会有两种思路

Set
我们可以采用集合的方式去统计元素基数,需要存储数据的元数据。假设有 10 亿个用户,每个用户占用 64 位的空间,那么总共就需要 1000000000 * 64 / 8 / 1024 / 1024 /1024 = 7.45 GB。似乎咋一看还能接受,但是这只是单场景的基数统计,如果存在多个场景?时间范围再放大,那么空间就会跟随基数的增长而线性增长,这肯定是不能接受的

BitMap
那么既然 Set 占用空间过大,那么 BitMap 如何?位图倒是一个可以考虑的选项,将数据经过 hash 得到位图上的索引,并将该索引标记为 1,最后经过统计位图中 1 的个数,就可以做到基数统计。但是呢,也是有缺点的,因为采用的是哈希算法,那么必然存在哈希冲突,所以位图统计也并非是一个严谨的准确基数统计。为了降低冲突,必然会将位图的大小大于集合基数的一定倍数。

假设仍然是 10 亿用户数,假设位图的大小是基数的 2 倍,那么需要的空间就是 1000000000 * 2 / 8 /1024/1024 = 238 MB, 这相比 Set 的空间占用,似乎已经可以接受了

概率算法
综上,位图的确是一个不错的选择,只需要 MB 级的空间就可以做 10 亿级别的基数统计。
但是如果有人跟你说它只需要 KB 级别的空间就可以做跟你同等量级甚至更大的基数统计呢?那位图还香吗? 在不追求绝对准确的情况下,倒是有很多基于概率算法的基数统计解决方案,比如

  • Linear Counting
  • LogLog Counting
  • HyerLogLog Counting
  • HyperLogLog++

而 Redis 则是采用 HyperLogLog 这种算法去实现的


应用


需求
  • 统计页面 UV
    • 统计 APP 或页面,每天被点击/浏览/观看的用户数量
    • 注意是 UV, 非 PV
  • 不能占用大量空间,即非 O(n) 的空间复杂度

应用

Redis 原生提供了 HyperLogLog ,它是 LogLog 算法的升级版本,可以为我们提供 “非精准的去重计数估算”,常用于 APP 或页面的 UV 统计

  • Redis Command
    在这里插入图片描述
    Redis 只为 HyperLogLog 提供了三个命令,所以还是相当简单的,我们一起来看一下
  • pfadd key element [element...]
    O(1) 的插入时间复杂度, 向指定 key 的 HyperLogLog 数据结构插入一或多个元素
  • pfcount key [key...]
    查询某 key 在 HyperLogLog 数据结构中的近似基数,如果该 key 不存在,则为 0
  • pfmerge destkey sourcekey [sourcekey...]
    将多个 HyperLogLog 合并到一个 HyperLogLog

原理


伯努利试验
什么是伯努利试验?

伯努利试验 (Bernoulli trial)
伯努利试验 (Bernoulli Trial) 是在相同的条件下,重复地,互相独立地进行的一种随机试验

  • 该随机试验只有两种互斥结果:成功失败
  • 设试验只有 2 个可能结果: A A A A ‾ \overline{A} A ,则称实验为 E E E 伯努利试验;设
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值