Redis 有这些数据类型,基本数据类型:String、List、Hash、Set、Zset,特殊的数据类型:Geospatial、Hyperloglog、Bitmap。

命令并未包含全部的,可供参考,要查询更多命令,请点此

String

String,也叫字符串,是基本的数据类型之一。

基本操作

set

设置值

127.0.0.1:6379> set name xiaohehe
OK

get

获得值

127.0.0.1:6379> get name
"xiaohehe"

append

追加字符串,如果当前 key 不存在,它的用法和 set 命令一样。

127.0.0.1:6379> append name 2021
(integer) 12
127.0.0.1:6379> get name
"xiaohehe2021"

strlen

得到字符串的长度

127.0.0.1:6379> strlen name
(integer) 12

mset

设置多组 key : value

127.0.0.1:6379> mset age 23 sex 0 address bestguo.top
OK

mget

输入多个 key,获取对应的 value

127.0.0.1:6379> mget age sex address
1) "23"
2) "0"
3) "bestguo.top"

getset

获取 key 中的值并替换 key 中的值,如果 key 在数据库不存在,则返回 null,并且给 key 设置值。

127.0.0.1:6379> getset name2 1111
(nil)
127.0.0.1:6379> get name2
"1111"
127.0.0.1:6379> getset age 18
"23"
127.0.0.1:6379> get age
"18"

截取与替换

getrange

提取字符串中介于两个指定下标之间的字符,类比 substring

127.0.0.1:6379> getrange name 0 3
"xiao"

setrange

替换指定位置开始的字符串位置,并且之后的字符会被替换掉

127.0.0.1:6379> get name
"xiaxiaoe2021"

同时设置

setex

设置值的时候,同时设置过期时间

127.0.0.1:6379> setex tel 10 123456789
OK
127.0.0.1:6379> get tel
"123456789"
127.0.0.1:6379> ttl tel
(integer) 3
127.0.0.1:6379> ttl tel
(integer) 2
127.0.0.1:6379> ttl tel
(integer) 0
127.0.0.1:6379> ttl tel
(integer) -2
127.0.0.1:6379> get tel
(nil)

setnx

key 不存在时,则设置值,反之则不设置值。

127.0.0.1:6379> setex tel 10 123456789
OK
127.0.0.1:6379> setnx tel 111
(integer) 0
127.0.0.1:6379> setnx tel 111
(integer) 0
127.0.0.1:6379> setnx tel 111
(integer) 1
127.0.0.1:6379> get tel
"111"

msetnx

设置多个值的时候,同时设置过期时间。他是一个原子性的操作,要么一起成功,要么一起失败。

# 由于house不存在,肯定设置失败
127.0.0.1:6379> msetnx name xiaohehe2020 house 111
(integer) 0
127.0.0.1:6379> get house
(nil)
# 之前我把 tel 的值给删除了,然后再重新设置值,此时都设置成功了
127.0.0.1:6379> msetnx tel 1234 house 111
(integer) 1
127.0.0.1:6379> mget tel house
1) "1234"
2) "111"

增加与减少

incr

自增命令,每次增加1

127.0.0.1:6379> get age
"18"
127.0.0.1:6379> incr age
(integer) 19
# 不能是英文
127.0.0.1:6379> getset age a
"19"
127.0.0.1:6379> incr age
(error) ERR value is not an integer or out of range

decr

自减命令,每次减少1

127.0.0.1:6379> decr age
(integer) 18

incrby

增加命令,指定设置自增量

127.0.0.1:6379> incrby age 10
(integer) 28

decrby

减少命令,指定设置自减量

127.0.0.1:6379> decrby age 8
(integer) 20

简单示例

设置 user1 对象,值为 json 字符串来保存

set user:1 {name: zhangsan, age: 3}
set user:1:name zhangsan user:1:age 3

使用场景

  • 计数器
  • 对象缓存存储

对象缓存存储

将结构体 json 序列化成字符串,然后将字符串保存在 redis 的 value 中,将结构体的业务唯一标示作为 key;这种保存 json 的用法用的最多的场景就是缓存用户信息,将用户 bean 信息转成 json 再序列化为字符串作为 value保存在 redis 中,将用户 id 作为 key。从代码中获取用户缓存信息就是一个逆过程,根据 userid 作为 key 获取到结构体 json,然后将 json 转成 java bean。

比如:

127.0.0.1:6379> set user.10001 {“id”:”10001”,”name”:”monkey”}
(integer) 1

计数功能

redis 是单线程模式,并且 redis 将很多常用的事务操作进行了封装,这里我们最常用的就是数值自增或自减,redis 的作者封装了 incr 可以进行自增,没调用一次自增1,因为 redis 是单线程运行,所以就算 client 是多线程调用那么也是正确自增,因为 incr 命令中将 read 和 write 做了事务封装。同样可以设置 incr 的 step,每次根据 step 进行自增,当然如果要达到自减的效果,那么只要将 step 设置为负数就可以了。

计数功能使用的场景很多,我们之前经常用在实时计数统计场景,也用在过库存场景、限流计数场景等等,而且redis 的性能也是非常高的,对于一般的并发量没那么高的系统都是适用的。

127.0.0.1:6379> set num 1
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incrby num 2
(integer) 4

List

List,也叫列表,是基本的数据类型之一,Redis 的列表可以当成栈、队列。因为有这些操作命令。在 Redis 中,它的实现方式是双向链表。因此,它有双向链表的特点。

提示:绝大部分的 List 命令都是由 L 开头的。

添加

lpush

从第一个位置插入元素

127.0.0.1:6379> lpush words one two three four
(integer) 4

lrange

通过区间取得元素

127.0.0.1:6379> lrange words 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrange words 0 2
1) "four"
2) "three"
3) "two"

rpush

从最后一个位置插入元素

127.0.0.1:6379> lrange words 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
5) "five"

移除

lpop

从第一个位置移除元素

127.0.0.1:6379> lpop words
"four"
127.0.0.1:6379> lrange words 0 -1
1) "three"
2) "two"
3) "one"
4) "five"
# 从第一个位置开始,移除2个元素
127.0.0.1:6379> lpop words 2
1) "three"
2) "two"
127.0.0.1:6379> lrange words 0 -1
1) "five"
2) "one"

rpop

从最后一个位置移除元素

127.0.0.1:6379> rpop words
"one"

两者结合

rpoplpush

从最后一个位置移除元素,将该元素放到另一个列表中的第一个位置

127.0.0.1:6379> rpoplpush words words2
"five"
127.0.0.1:6379> lrange words 0 -1
(empty array)
127.0.0.1:6379> lrange words2 0 -1
1) "five"

其它命令

现在,words 中有以下内容:five,four,three,two,one

lindex

指定下标获取元素

127.0.0.1:6379> lindex words 1
"four"
127.0.0.1:6379> lindex words 0
"five"
127.0.0.1:6379> lindex words -2
"two"

llen

获取列表的长度

127.0.0.1:6379> llen words
(integer) 5

lrem

移除列表中指定的元素,需要指定个数。

127.0.0.1:6379> rpush words two
(integer) 5
127.0.0.1:6379> lrem words 2 two
(integer) 2

ltrim

通过下标截取指定的长度,这个 list 已经被改变了、截断了只剩下截取的元素!

127.0.0.1:6379> ltrim words 0 2
OK
127.0.0.1:6379> lrange words 0 -1
1) "five"
2) "four"
3) "three"

exists

判断列表是否存在

127.0.0.1:6379> exists words
(integer) 1

lset

指定列表中的下标设置元素,如果列表是空的,则会插入失败

127.0.0.1:6379> lset words 0 five
OK
127.0.0.1:6379> lrange words 0 -1
1) "five"
2) "three"
3) "two"
4) "one"
5) "two"

linsert

在指定的位置插入一个元素,可以在目标位置之前,也可以在目标位置之后

# 在 three 之前添加 six
127.0.0.1:6379> linsert words before three six
(integer) 6
127.0.0.1:6379> lrange words 0 -1
1) "five"
2) "six"
3) "three"
4) "two"
5) "one"
6) "two"
127.0.0.1:6379> linsert words after one seven
(integer) 7
# 在 one 之后添加 seven
127.0.0.1:6379> lrange words 0 -1
1) "five"
2) "six"
3) "three"
4) "two"
5) "one"
6) "seven"
7) "two"

lmove

将列表中的指定的元素移动到另外一个列表中。需要指定从列表的哪一边,移动到另一个列表的哪一边。

# 从列表的左边取出一个元素,再移入到另一个列表的左边。
127.0.0.1:6379> lmove words words2 left left
"five"
127.0.0.1:6379> lrange words2 0 -1
1) "five"
127.0.0.1:6379> lmove words words2 left left
"six"
127.0.0.1:6379> lrange words2 0 -1
1) "six"
2) "five"
# 从列表的左边取出一个元素,再移入到另一个列表的左边。
127.0.0.1:6379> lmove words words2 left right
"three"
127.0.0.1:6379> lrange words2 0 -1
1) "six"
2) "five"
3) "three"
# 从列表的右边取出一个元素,再移入到另一个列表的左边。
127.0.0.1:6379> lmove words words2 right left
"two"
127.0.0.1:6379> lrange words2 0 -1
1) "two"
2) "six"
3) "five"
4) "three"
# 从列表的右边取出一个元素,再移入到另一个列表的右边。
127.0.0.1:6379> lmove words words2 right right
"seven"
127.0.0.1:6379> lrange words2 0 -1
1) "two"
2) "six"
3) "five"
4) "three"
5) "seven"

使用场景

  • 队列
  • 秒杀

队列

将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理。

秒杀

在商品秒杀场景最怕的就是商品超卖,为了解决超卖问题,我们经常会将库存商品缓存到类似 MQ 的队列中,多线程的购买请求都是从队列中取,取完了就卖完了,但是用 MQ 处理的化有点重,这里就可以使用 redis 的 list 数据类型来实现,在秒杀前将本场秒杀的商品放到list中,因为 list 的 pop 操作是原子性的,所以即使有多个用户同时请求,也是依次 pop,list 空了 pop 抛出异常就代表商品卖完了。

比如:

> rpush goods:cola cola cola cola
(integer) 3
> lpop goods:cola
"cola"
> lpop goods:cola
"cola"

Set

Set,也叫集合,是基本的数据类型之一,集合中的元素不重复且无序。

提示:所有的 Set 命令都是由 s 开头的。

基本操作

sadd

添加一组元素

127.0.0.1:6379> sadd s1 b g a o f c
(integer) 6

scard

获取 set 集合中的内容元素个数

127.0.0.1:6379> scard s1
(integer) 6

smembers

查看指定 set 集合中的所有元素

127.0.0.1:6379> smembers s1
1) "o"
2) "a"
3) "b"
4) "c"
5) "g"
6) "f"

sismember

判断某一个值是不是在 set 集合中

127.0.0.1:6379> smembers s1
1) "o"
2) "a"
3) "b"
4) "c"
5) "g"
6) "f"
127.0.0.1:6379> sismember s1 s
(integer) 0
127.0.0.1:6379> sismember s1 a
(integer) 1

srandmember

随机抽取元素,默认取出一个。可以指定取出多个元素。

# 取出一个元素
127.0.0.1:6379> srandmember s1
"f"
127.0.0.1:6379> srandmember s1
"g"
127.0.0.1:6379> srandmember s1
"o"
# 取出多个元素
127.0.0.1:6379> srandmember s1 3
1) "g"
2) "c"
3) "a"
127.0.0.1:6379> srandmember s1 3
1) "g"
2) "c"
3) "f"

spop

随机弹出一个元素

127.0.0.1:6379> spop s1
"g"
127.0.0.1:6379> spop s1
"b"
127.0.0.1:6379> smembers s1
1) "o"
2) "c"
3) "a"
4) "f"
127.0.0.1:6379>

smove

将集合中的指定的元素移动到另外一个集合中。

127.0.0.1:6379> smembers s1
1) "o"
2) "c"
3) "a"
4) "f"
127.0.0.1:6379> smove s1 s2 c
(integer) 1
127.0.0.1:6379> smembers s2
1) "c"
127.0.0.1:6379> smembers s1
1) "o"
2) "a"
3) "f"

相关运算

假设 s1 中有 “o”、”b”、”c”、”a”、”f” 5 个元素,s2 中有 “c”、”e”、”d”、”f” 4 个元素。

集合中的运算分别有三种,分别是交集,并集和差集。

sdiff

计算两个元素的差集

127.0.0.1:6379> sdiff s1 s2
1) "a"
2) "o"
3) "b"

sinter

计算两个元素的交集

127.0.0.1:6379> sinter s1 s2
1) "c"
2) "f"

sunion

计算两个元素的并集

127.0.0.1:6379> sunion s1 s2
1) "d"
2) "e"
3) "o"
4) "b"
5) "c"
6) "a"
7) "f"

使用场景 - 去重

redis 的 set 相当于 java 中的 HashSet,内部的健值是无序唯一的,相当于一个 HashMap,但是 value 都是null。set 数据类型其实没什么好讲的,使用场景也是比较单一的,就是用在一些去重的场景里,例如每个用户只能参与一次活动、一个用户只能中奖一次等等去重场景。

Hash

Hash 是什么呢?就类似于 Java 中的 Map 集合。Map 集合中都是以键值对的形式。在本质上和 String 类型没有太大的区别,还是一个简单的键值对形式。

提示:所有的 Hash 命令都是由 h 开头的。

基本操作

hset

设置一个哈希表,并且保存一对键值对。不过 hset 也可以多对键值对

hset 命令:hset key field value [field value ...]

hmset 命令:hmset key field value [field value ...]

127.0.0.1:6379> hset user name xiaohehe age 18 sex 0 house 122 
(integer) 4

hget

从哈希表中的键中拿出一个值。

127.0.0.1:6379> hget user age
"18"

hmset

设置一个哈希表,并且保存多对键值对,用法和 hset 一样

127.0.0.1:6379> hset user name xiaohehe age 18 sex 0 house 122 
(integer) 4

hmget

从哈希表中使用多个键中拿出多个值。

127.0.0.1:6379> hmget user name age asd
1) "xiaohehe"
2) "18"
3) (nil)

hgetall

获取全部的数据,包括键和值。

127.0.0.1:6379> hgetall user
1) "name"
2) "xiaohehe"
3) "age"
4) "18"
5) "sex"
6) "0"
7) "house"
8) "122"

hdel

删除哈希表中指定的 key 字段

127.0.0.1:6379> hdel user sex
(integer) 1
127.0.0.1:6379> hgetall user
1) "name"
2) "xiaohehe"
3) "age"
4) "18"
5) "house"
6) "122"

hlen

获取哈希表的长度

127.0.0.1:6379> hlen user
(integer) 3

hexists

判断哈希表中指定的 key 是否存在

127.0.0.1:6379> hexists user sex
(integer) 0
127.0.0.1:6379> hexists user name
(integer) 1

hkeys

获取哈希表中所有的 key

127.0.0.1:6379> hkeys user
1) "name"
2) "age"
3) "house"

hvals

获取哈希表中所有的 value

127.0.0.1:6379> hvals user
1) "xiaohehe"
2) "18"
3) "122"

增加和减少

这和 String 数据类型中的增加和减少是一样的,但是它并没有 decrby 的命令。如果要减少的话,可以设置增加负数的目的来达到减少

hincrby

127.0.0.1:6379> hincrby user age 2
(integer) 20
127.0.0.1:6379> hincrby user age -1
(integer) 19

同时设置

hsetnx

哈希表中的 key 不存在时,则设置值,反之则不设置值。

127.0.0.1:6379> hsetnx user age 100
(integer) 0
127.0.0.1:6379> hsetnx user asd "this is a redis"
(integer) 1
127.0.0.1:6379> hget user asd
"this is a redis"

使用场景 - 保存结构体信息

hash 字典类型也是比较适合保存结构体信息的,不同于字符串一次序列化整个对象,hash 可以对用户结构中的每个字段单独存储。这样当我们需要获取结构体信息时可以进行部分获取,而不用序列化所有字段,而将整个字符串保存的结构体信息只能一次性全部读取。

Zset

在 set 的基础上,增加了一个值。

提示:所有的 Zset 命令都是由 z 开头的。

基本操作

开始有如下数据:

85 xiaoqiang
90 zhangsan
91 lisi
95 wanwu
76 zhaoliu

zadd

向有序集中添加一个值,可以添加多个值

127.0.0.1:6379> zadd grade a xiaoqiang
(error) ERR value is not a valid float
127.0.0.1:6379> zadd grade 85 xiaoqiang
(integer) 1
127.0.0.1:6379> zadd grade 90 zhangsan
(integer) 1
127.0.0.1:6379> zadd grade 90 zhangsan 91 lisi 95 wanwu 76 zhaoliu
(integer) 3

zrange

向有序集合中通过下标区间取得元素

127.0.0.1:6379> zrange grade 0 -1
1) "zhaoliu"
2) "xiaoqiang"
3) "zhangsan"
4) "lisi"
5) "wanwu"
# 逆序
127.0.0.1:6379> zrange grade 0 -1 rev
1) "wanwu"
2) "lisi"
3) "zhangsan"
4) "xiaoqiang"
5) "zhaoliu"
# 按照 score 截取,可以替换成 zrangebyscore
127.0.0.1:6379> zrange grade 95 100 byscore
1) "wanwu"

zrevrange

向有序集合中通过下标区间取得元素,并且是逆序的

127.0.0.1:6379> zrevrange grade 0 -1
1) "wanwu"
2) "lisi"
3) "zhangsan"
4) "xiaoqiang"
5) "zhaoliu"

zrem

移除有序集合中指定的元素

127.0.0.1:6379> zrem grade zhaoliu xiaoqiang
(integer) 2
127.0.0.1:6379> zrange grade 0 -1
1) "zhangsan"
2) "lisi"
3) "wanwu"

zcard

获取有序集合中的个数

127.0.0.1:6379> zcard grade
(integer) 3

zcount

获取指定 score 区间的成员的数量

127.0.0.1:6379> zcount grade 85 1000
(integer) 3

排序

zrangebyscore

给集合中的数据指定 score 的区间范围并从小到大排序

127.0.0.1:6379> zrangebyscore grade 85 100
1) "zhangsan"
2) "lisi"
3) "wanwu"

zrevrangebyscore

给集合中的数据指定 score 的区间范围并从大到小排序

127.0.0.1:6379> zrevrangebyscore grade 100 85
1) "wanwu"
2) "lisi"
3) "zhangsan"

使用场景 - 各类热门排序场景

例如热门歌曲榜单列表,value值是歌曲ID,score是播放次数,这样就可以对歌曲列表按播放次数进行排序。

当然还有类似微博粉丝列表、评论列表等等,可以将value定义为用户ID、评论ID,score定义为关注时间、评论点赞次数等等。

Geospatial

Redis的 Geospatial 在 Redis 3.2 就已经有了,它可以推算出地理位置的信息,两地之间的距离,方圆之内的人。关于地理位置的可以参考它:Redis 地理位置(geo)

注意:

该命令以采用标准格式的参数 x(纬度),y(经度),所以经度必须在纬度之前。这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。具体的限制,由 EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:

  • 有效的经度从 -180 度到 180 度。
  • 有效的纬度从 -85.05112878 度到 85.05112878 度。

当坐标位置超出上述指定范围时,该命令将会返回一个错误。

基本操作

geoadd

添加元素的位置,包含(经度、纬度、名称)样板:geoadd key [NX|XX] [CH] longitude(经度) latitude(纬度) member [longitude latitude member ...]

# 厦门理工学院和集美大学
127.0.0.1:6379> geoadd xiamen 118.08745238 24.62416819 xmut 118.09534880 24.57996881 jmu
(integer) 2
127.0.0.1:6379> geoadd xiamen 118.08518860 24.60387997 huaqiao # 华侨大学
(integer) 1
127.0.0.1:6379> geoadd xiamen 118.06637022 24.61626788 xit # 厦门工学院
(integer) 1
127.0.0.1:6379> geoadd xiamen 118.08278534 24.63070263 huaxia # 厦门华夏学院
(integer) 1
127.0.0.1:6379> geoadd xiamen 118.10268733 24.43600074 xmu # 厦门大学
(integer) 1
127.0.0.1:6379> geoadd xiamen 118.16647331 24.46291879 xmcu # 厦门城市职业学院
(integer) 1

getpos

获取元素的位置,获取到的是坐标值。

127.0.0.1:6379> geopos xiamen xmut jmu huaqiao xit huaxia xmu xmcu
1) 1) "118.0874517560005188"
   2) "24.62416844172170016"
2) 1) "118.09534817934036255"
   2) "24.57996797414514134"
3) 1) "118.08518797159194946"
   2) "24.60388053356235361"
4) 1) "118.06636959314346313"
   2) "24.61626771586804097"
5) 1) "118.08278471231460571"
   2) "24.63070295287047173"
6) 1) "118.10268670320510864"
   2) "24.43600088173700868"
7) 1) "118.16647499799728394"
   2) "24.46291962044919188"

geodist

比较两个点之间的直线距离。可以指定距离单位,Redis 提供了 4 个单位。

  • m表示单位为米。
  • km表示单位为千米。
  • mi表示单位为英里。
  • ft表示单位为英尺。
# 厦门理工学院与厦门大学的直线距离(千米)
127.0.0.1:6379> geodist xiamen xmut xmu km
"20.9859"
# 厦门理工学院与厦门城市职业学院的直线距离(千米)
127.0.0.1:6379> geodist xiamen xmut xmcu km
"19.6365"

georadius

以给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素。这就像是寻找附近的人。比如,在 20 km 范围内有哪些人。

经度:118.08835144,纬度:24.63347195 所在的位置是厦门理工学院集美苑宿舍。

# 在厦门理工学院集美苑宿舍,方圆5公里内有哪些学校。
127.0.0.1:6379> georadius xiamen 118.08835144 24.63347195 5 km
1) "xit"
2) "huaqiao"
3) "xmut"
4) "huaxia"
# 在厦门理工学院集美苑宿舍,方圆2公里内有哪些学校。
127.0.0.1:6379> GEORADIUS xiamen 118.08835144 24.63347195 2000 m
1) "huaxia"
2) "xmut"
# 同时显示距离集美苑多少公里和他们的经纬度
127.0.0.1:6379> GEORADIUS xiamen 118.08835144 24.63347195 2 km withcoord withdist
1) 1) "huaxia"
   2) "0.6416"
   3) 1) "118.08278471231460571"
      2) "24.63070295287047173"
2) 1) "xmut"
   2) "1.0388"
   3) 1) "118.0874517560005188"
      2) "24.62416844172170016"

georadiusbymember

找出位于指定元素周围的其他元素。

# 寻找厦门大学方圆10公里内有哪些学校
127.0.0.1:6379> GEORADIUSBYMEMBER xiamen xmu 10 km withcoord withdist
1) 1) "xmu"
   2) "0.0000"
   3) 1) "118.10268670320510864"
      2) "24.43600088173700868"
2) 1) "xmcu"
   2) "7.1189"
   3) 1) "118.16647499799728394"
      2) "24.46291962044919188"

geohash

返回一个或多个位置元素的 geohash 表示,将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近。

127.0.0.1:6379> geohash xiamen xmu xmut
1) "ws7gp2ry000"
2) "ws7up4swjj0"
127.0.0.1:6379> geohash xiamen xmu huaxia
1) "ws7gp2ry000"
2) "ws7up5ck0r0"
# 厦门理工学院和厦门华夏学院很近
127.0.0.1:6379> geohash xiamen xmut huaxia
1) "ws7up4swjj0"
2) "ws7up5ck0r0"

其它操作

geo 底层的实现原理其实就是 Zset,我们可以使用 Zset 命令来操作 geo!可以参照 Zset 的操作来。

集合中有几所大学

127.0.0.1:6379> ZCARD xiamen
(integer) 7

列出这些大学的名字

127.0.0.1:6379> zrange xiamen 0 -1
1) "xmu"
2) "jmu"
3) "xit"
4) "huaqiao"
5) "xmut"
6) "huaxia"
7) "xmcu"

删除

127.0.0.1:6379> ZREM xiamen xit
(integer) 1
127.0.0.1:6379> zrange xiamen 0 -1
1) "xmu"
2) "jmu"
3) "huaqiao"
4) "xmut"
5) "huaxia"
6) "xmcu"

Hyperloglog

Redis 2.8.9版本就更新了 Hyperloglog 数据结构!

Redis Hyperloglog 基数统计的算法!

优点∶占用的内存是固定,2^64不同的元素的技术,只需要 12KB 内存!如果要从内存角度来比较的话 Hyperloglog 是首选,虽然 set 集合也能做到,可是它的内存并非是固定的!

网页的 UV(一个人访问一个网站多次,但是还是算作一个人!)

传统的方式,set 保存用户的 id,然后就可以统计 set 中的元素数量作为标准判断!

这个方式如果保存大量的用户 id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;

0.81% 错误率!统计 UV 任务,可以忽略不计!

如果允许容错,那么一定可以使用 Hyperloglog,如果不允许容错,就使用 set 或者自己的数据类型。

基本操作

pfadd

创建一组元素,可以重复。

127.0.0.1:6379> PFADD online_users a s d f g h j q s
(integer) 1

pfcount

统计 key 中元素的基数数量。

127.0.0.1:6379> PFCOUNT online_users
(integer) 8

pfmerge

将两组元素进行合并

127.0.0.1:6379> PFMERGE best_users online_users hot_users
OK
127.0.0.1:6379> PFCOUNT best_users
(integer) 15

Bitmap

位存储。统计用户信息,活跃,不活跃;登录、未登录;打卡,365 打卡。只要是涉及两个状态的,都可以使用 Bitmap。

基本使用

setbit

设置或者清空 key 的 value(字符串)在 offset 处的 bit 值。

127.0.0.1:6379> setbit daka 0 0
(integer) 0
127.0.0.1:6379> setbit daka 1 1
(integer) 0
127.0.0.1:6379> setbit daka 2 1
(integer) 0
127.0.0.1:6379> setbit daka 3 0
(integer) 0
127.0.0.1:6379> setbit daka 4 1
(integer) 0

getbit

返回 key 对应的 string 在 offset 处的 bit 值。

127.0.0.1:6379> getbit daka 1
(integer) 1
127.0.0.1:6379> getbit daka 3
(integer) 0
127.0.0.1:6379> getbit daka 4
(integer) 1

bitcount

统计字符串被设置为 1 的 bit 数。

127.0.0.1:6379> bitcount daka 0 10
(integer) 3