六Redis HyperLogLog

使用常量空间估算大量元素的基数
使用集合来存储每个访客的IP,通过集合性质(集合中的每个元素都各不相同)来得到多个独立 IP,然后通过调用SCARD命令得出独立IP的数量
ip = get_vistor_ip()
SADD '2014.8.15::unique::ip' ip
然后使用以下代码来获得当天的唯一 IP 数量
SCARD '2014.8.15::unique::ip'

集合实现的问题
使用字符串来储存每个 IPv4 地址最多需要耗费 15 字节(格式为 'XXX.XXX.XXX.XXX' ,比如'202.189.128.186')

随着集合记录的IP 越来越多,消耗的内存也会越来越多
另外如果要储存IPv6地址的话,需要的内存还会更多一些

为了更好地解决像独立IP地址计算这种问题,Redis 在2.8.9版本添加了 HyperLogLog结构。

HyperLogLog 介绍
HyperLogLog可以接受多个元素作为输入,并给出输入元素地基数估算值。
    。基数:集合中不同元素地数量。比如{'apple', 'banana', 'cherry', 'banana', 'apple'} 的基数就是 3
    。估算值:算法给出地基数并不是精确地,可能会比实际稍微多一些或者稍微少一些,但会控制在合理的范围之内。
HyperLogLog的优点是,即使输入元素的数量或者体积非常非常大,计算基数所需的空间总是固定的,并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成 鲜明对比

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素


将元素添加至 HyperLogLog
PFADD key element [element ...]
将任意数量的元素添加到指定的 HyperLogLog 里面。
这个命令可能会对 HyperLogLog 进行修改,以便反映新的基数估算 值,如果 HyperLogLog 的基数估算
值在命令执行之后出现了变化,那么命令返回 1, 否则返回 0 。
命令的复杂度为O(N) ,N为被添加元素的数量。


返回给定 HyperLogLog 的基数估算值
PFCOUNT key [key ...]
当只给定一个 HyperLogLog 时,命令返回给定 HyperLogLog 的基数估算值
当给定多个 HyperLogLog 时,命令会先对给定的 HyperLogLog 进行并集计算,得出一个合并后的 HyperLogLog ,然后返回这个合并 HyperLogLog 的基数估算值作为命令的结果(合并得出的 HyperLogLog 不会被储存,使用之后就会被 删掉)。
当命令作用于 单个 HyperLogLog 时, 复杂度为 O(1) , 并且具有非常低的平均常数 时间。
当命令作用于多个 HyperLogLog 时, 复杂度为 O(N) ,并且常数时间也比处理单个 HyperLogLog 时要大得多。



PFADD 和 PFCOUNT 的使用示例
dis> PFADD unique::ip::counter '192.168.0.1'
(integer) 1
redis> PFADD unique::ip::counter '127.0.0.1'
(integer) 1
redis> PFADD unique::ip::counter '255.255.255.255'
(integer) 1
redis> PFCOUNT unique::ip::counter
(integer) 3

合并多个 HyperLogLog
PFMERGE destkey sourcekey [sourcekey ...]
将多个 HyperLogLog 合并为一个 HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。
命令的复杂度为 O(N) , 其中 N 为被合并的 HyperLogLog 数量,不过这个命令得常数复杂度比较高。

PFMERGE 的使用示例
redis> PFADD str1 "apple" "banana" "cherry"
(integer) 1
redis> PFCOUNT str1
(integer) 3
redis> PFADD str2 "apple" "cherry" "durian" "mongo"
(integer) 1
redis> PFCOUNT str2
(integer) 4
redis> PFMERGE str1&2 str1 str2
OK
redis> PFCOUNT str1&2
(integer) 5



唯一计数器得使用示例
# 创建一个 IP 地址唯一计数器
>>> ip_counter = UniqueCounter(client, 'unique::ip::counter')
# 添加一些 IP
>>> ip_counter.include('192.168.0.1')
>>> ip_counter.include('8.8.8.8')
>>> ip_counter.include('255.255.255.255')
# 查看计数器当前的值
>>> ip_counter.result() 3




HyperLogLog 接受多个元素作为输入,估算出输入元素的基数。
因为 HyperLogLog 只需要使用少量内存就可以 对非常多的元素 进行计数,对于那些只想知道 输入元 素的基数,但是并不需要知道具体 输入的是哪些元素的程序来 说,使用 HyperLogLog 而不是集合来 计 算基数,可以 节约大量内存。
三个命令:PFADD、PFCOUNT、PFMERGE 。






猜你喜欢

转载自blog.csdn.net/xsjzdrxsjzdr/article/details/85242354