# 3.2 HyperLogLog相关命令

HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的.

***

注:

基数统计是指确定某个数据集中不同(唯一)元素的数量.简而言之,它是评估数据集的"独特性"或"多样性"的方法.例如,考虑以下数字序列:

`1, 3, 4, 5, 5, 6, 6, 7, 7, 7`

虽然这个序列有10个数字,但它只有6个不同的数字.因此,这个数据集的基数是6.

在大数据环境下,直接计算基数可能非常消耗资源和时间,尤其是当数据集很大而内存有限的时候.为了解决这个问题,我们需要一些可以提供近似结果的算法,而这些算法通常在时间和空间效率上都要比完全准确的方法好得多.

HyperLogLog就是这样的一个算法,它提供了一种近似的方法来估计基数,使用的内存非常少,但准确率相对较高.

基数统计在很多领域都有应用,比如统计网站的独立访客数量、统计某个数据库中独特的搜索查询数量或者分析大型数据集中的独特值数量等.

***

在Redis里面,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2^64个不同元素的基数.这和计算基数时,元素越多耗费内存就越多的set形成鲜明对比.

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

HyperLogLog(HLL)是一种在Redis中提供的数据结构,它的主要作用是为了提供一种内存效率很高的方法来估计大数据集的唯一元素数量.简单来说,**当你想知道某个数据集中有多少唯一值且不需要知道具体的唯一值时**,你可以使用HyperLogLog.

HyperLogLog的优势在于其极低的内存消耗.无论数据集大小,一个HyperLogLog只需要约12KB的内存.

举个例子:假设你想统计过去一个月你的网站有多少唯一访客.如果使用传统的set结构,每个唯一的用户ID都会被存储一次,这可能会消耗大量内存.但如果使用HyperLogLog,即使是数百万或数十亿的唯一用户ID,所需要的内存也仍然只有12KB.

需要注意的是,HyperLogLog是一个近似算法,这意味着**它提供的计数不是精确的**.但误差范围是可控的,并且对于许多应用来说,这个误差是可以接受的,特别是考虑到它所提供的巨大的内存节省.

在Redis中,你可以使用一系列的`PF*`命令来操作 HyperLogLog.例如`PFADD`来添加元素,`PFCOUNT`来获取近似的唯一元素数量等.

## 3.2.1 用`PFADD`添加键值对

* `PFADD`
  * 语法:`PFADD key element [element ...]`
  * 功能:添加指定元素到HyperLogLog中.如果至少有个1元素被添加返回1,否则返回0

例:

在1个键上同时添加多个值:

```
127.0.0.1:6379> PFADD Peter Math Computer Piano
(integer) 1
```

再向HyperLogLog中添加一个已存在的值:

```
127.0.0.1:6379> PFADD Peter Math
(integer) 0
```

可以看到,由于Math已存在,故返回0

再创建一个HyperLogLog:

```
127.0.0.1:6379> PFADD Mary Math Piano Math
(integer) 1
```

注意:此时键名为Mary的HyperLogLog中有重复的元素Math

## 3.2.2 用`PFCOUNT`统计基数值

* `PFCOUNT`
  * 语法:`PFCOUNT key [key ...]`
  * 功能:返回给定HyperLogLog的基数估算值.如果多个键,则返回多个键对应的值中不重复数据的数量;若HyperLogLog不存在则返回0

例:

查看Peter上的课外班数量:

```
127.0.0.1:6379> PFCOUNT Peter
(integer) 3
```

查看Mary上的课外班数量:

```
127.0.0.1:6379> PFCOUNT Mary
(integer) 2
```

可以看到,添加元素到HyperLogLog时,由于Math是重复的,因此统计出的基数值为2

查看Peter和Mary上的课外班数量:

```
127.0.0.1:6379> PFCOUNT Peter Mary
(integer) 3
```

虽然Peter的基数为3,Mary的基数为2.但是由于2个HyperLogLog中的元素值是重复的,因此它们的基数和仍然为3

查看一个不存在的HyperLogLog的基数值:

```
127.0.0.1:6379> PFCOUNT notExist
(integer) 0
```

注意:`PFCOUNT`命令返回的是对应基数的近似值,而非精确值.因此当基数量很大时统计结果不一定准确

## 3.2.3 用`PFMERGE`进行合并操作

* `PFMERGE`
  * 语法:`PFMERGE destkey sourcekey [sourcekey ...]`
  * 功能:把多个HyperLogLog合并成一个.无论sourcekey是否存在,都将返回OK.如果合并前destkey不存在,则会新建一个

例:

创建2个HyperLogLog:

```
127.0.0.1:6379> PFADD hll1 1 2 3
(integer) 1
```

```
127.0.0.1:6379> PFADD hll2 2 4 5
(integer) 1
```

合并2个HyperLogLog:

```
127.0.0.1:6379> PFMERGE hll hll1 hll2
OK
```

查看合并后的基数:

```
127.0.0.1:6379> PFCOUNT hll
(integer) 5
```

合并2个不存在的HyperLogLog:

```
127.0.0.1:6379> EXISTS a
(integer) 0
127.0.0.1:6379> EXISTS b
(integer) 0
127.0.0.1:6379> EXISTS c
(integer) 0
127.0.0.1:6379> PFMERGE a b c
OK
```

可以看到,合并2个不存在的HyperLogLog,同样返回OK

## 3.2.4 统计网站访问总人数

在网站分析方面有两个统计指标:第一个是统计总访问量,第二个是统计访问人数.统计总访问量比较好办,每来一次访问加1即可,而在统计访问人数时需要去除重复,比如某人在某天内访问了100次,但在统计访问人数时只能算作一次

例:

此处我们以webSite1和webSite2表示2个网站的key;以u1-u5表示5个不同的用户:

```
127.0.0.1:6379> PFADD webSite1 u1 u1 u2 u3 u1 u4 u2
(integer) 1
```

```
127.0.0.1:6379> PFADD webSite2 u1 u2 u3 u4 u5 u4 u3 u2
(integer) 1
```

统计2个网站的访问人数:

```
127.0.0.1:6379> PFCOUNT webSite1
(integer) 4
```

```
127.0.0.1:6379> PFCOUNT webSite2
(integer) 5
```
