学习视频:【狂神说Java】Redis最新超详细版教程通俗易懂
Redis入门
概述
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
Redis的优势
- 性能极高 -- redis读的速度能达到110000次/秒,写的速度达到81000次/秒
- 原子 -- redis的所有操作都是原子性的,要不完全成功,要么完全失败。单个操作时原子性的。多个操作也支持事务,既原子性,通过MULTI和EXEC指令包起来
- 丰富的数据类型 -- 支持strings, hashes, lists, sets, sorted sets, bitmaps, hyperloglogs, geospatial 等数据类型的操作
- 丰富的特性 -- 支持publish/subscribe,通知,key,过期等特性
Redis安装
参考菜鸟教程:https://www.runoob.com/redis/redis-install.html
性能测试
redis 性能测试的基本命令如下:
redis-benchmark [option] [option value]
注意:该命令是在 redis 的目录下执行的,而不是 redis 客户端的内部指令。
可选参数(图片来自菜鸟教程):
windows实测:
# 测试 100 并发 10000 请求
redis-benchmark.exe -c 100 -n 10000
测试结果:
基础知识
基本命令
127.0.0.1:6379> select 2 # 选择数据库
OK
127.0.0.1:6379[2]> dbsize # 查看数据库大小
(integer) 0
127.0.0.1:6379[2]> set name zhangsan
OK
127.0.0.1:6379[2]> dbsize
(integer) 1
127.0.0.1:6379[2]> get name
"zhangsan"
127.0.0.1:6379[2]> flushdb # 清空本数据库
OK
127.0.0.1:6379[2]> flushall # 清空所有数据库
OK
127.0.0.1:6379[2]> keys * # 查看数据库所有key
(empty list or set)
Redis是单线程的
Redis是基于内存操作,CPU不是Redis新能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!所有就用了单线程了!
Redis为什么单线程还这么快?
误区:
- 高性能的服务器一定是多线程的?
- 多线程(CPU上下文会切换!)一定比单线程效率高?
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程CPU上下文切换,耗时,对于内存系统来说,如果没有上下文切换效率就是做高的!多次读写都是在一个CPU上的,在内存情况下这个就是最佳方案!
五大基本数据类型
Redis-Key(基本命令)
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> exists age # 判断key是否存在
(integer) 1
127.0.0.1:6379> exists age1
(integer) 0
127.0.0.1:6379> move name 1 # 移动至指定数据库
(integer) 1
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "name"
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> type age # 查看key的类型
string
127.0.0.1:6379> expire age 10 # 设置过期时间,单位秒
(integer) 1
127.0.0.1:6379> ttl age # 查看剩余过期时间
(integer) 5
127.0.0.1:6379> ttl age
(integer) 4
127.0.0.1:6379> ttl age
(integer) 3
127.0.0.1:6379> ttl age
(integer) 2
127.0.0.1:6379> ttl age
(integer) 1
127.0.0.1:6379> ttl age
(integer) -2
127.0.0.1:6379> ttl age
(integer) -2
127.0.0.1:6379> ttl age
(integer) -2
String
127.0.0.1:6379> set name zhangsan # 设置key
OK
127.0.0.1:6379> keys * # 查看所有key
1) "name"
127.0.0.1:6379> keys name # 获取指定key
1) "name"
127.0.0.1:6379> get name # 获取指定key
"zhangsan"
127.0.0.1:6379> exists name # 判断key是否存在
(integer) 1
127.0.0.1:6379> append name hello # 追加字符串
(integer) 13
127.0.0.1:6379> get name
"zhangsanhello"
127.0.0.1:6379> append name2 hello # 如果当前key不存在,相当于set key
(integer) 5
127.0.0.1:6379> get name2
"hello"
127.0.0.1:6379> strlen name # 获取字符串的长度
(integer) 13
127.0.0.1:6379>
#########################################################################
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> type views
string
127.0.0.1:6379> incr views # 自增1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> decr views # 自减1
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> incrby views 3 # 自增指定步长
(integer) 2
127.0.0.1:6379> incrby views 3
(integer) 5
127.0.0.1:6379> incrby views 3
(integer) 8
127.0.0.1:6379> decrby views 5 # 自减指定步长
(integer) 3
127.0.0.1:6379> decrby views 5
(integer) -2
127.0.0.1:6379>
########################################################################
# setrange getrange
127.0.0.1:6379>
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> getrange name 0 4 # 获取指定范围字符串,闭区间
"zhang"
127.0.0.1:6379> getrange name 0 -1
"zhangsan"
127.0.0.1:6379> getrange name 0 -2
"zhangsa"
127.0.0.1:6379> setrange name 5 si # 替换指定位置开始字符串
(integer) 8
127.0.0.1:6379> get name
"zhangsin"
127.0.0.1:6379>
#########################################################################
# setex (set with expire) 设置key的同时,设置过期时间
# setnx (set if not exists) 如果key不存在,则创建
127.0.0.1:6379>
127.0.0.1:6379> setex name 10 wangwu # 设置name为wangwu,过期时间10秒
OK
127.0.0.1:6379> ttl name
(integer) 7
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> setnx name3 zhaoliu # 如果name3不存在,设置值为zhaoliu
(integer) 1
127.0.0.1:6379> get name3
"zhaoliu"
127.0.0.1:6379> setnx name3 zhaoliu333 # 如果name3存在,设置失败
(integer) 0
127.0.0.1:6379> get name3
"zhaoliu"
127.0.0.1:6379>
################################################################
# mset mget 批量设置
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 批量设置键值对
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 # 批量获取
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v11 k4 v4 # 原子性操作,要么全成功,要么全失败
(integer) 0
# 对象
# set user:1:{name:zhangsan, age:18} # 设置一个user:1对象,值为json字符串
# 这里的key是一个巧妙的设计: user:{id}:{key:value}, 如此设计在Redis中是完全OK的
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "18"
127.0.0.1:6379>
#######################################################################
# getset # 先get,再set
127.0.0.1:6379> getset db redis # 如果不存在值,则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb # 如果存在值,获取原来的值,并设置新的值
"redis"
127.0.0.1:6379> get db
"mongodb"
127.0.0.1:6379>
String类似的使用场景:value除了是字符串,还可以是数字
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
List
基本的数据类型,列表
在Redis里面,可以把list当成 栈,队列,阻塞队列使用
所有的list命令都是L开头的
127.0.0.1:6379> lpush list one # 将一个值或多个值插入列表的头部
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 获取list中的值,闭区间
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1
1) "three"
2) "two"
127.0.0.1:6379> rpush list four # 将一个或多个值插入列表的尾部
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
#########################################################################
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
127.0.0.1:6379> lpop list # 移除列表的头部元素
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "four"
127.0.0.1:6379> rpop list
"four"
127.0.0.1:6379> lrange list 0 -1 # 移除列表的尾部元素
1) "two"
2) "one"
#########################################################################
127.0.0.1:6379> lindex list 0 # 通过下标获取list中的某一个元素
"two"
127.0.0.1:6379> lindex list 2
(nil)
#########################################################################
127.0.0.1:6379> llen list # 获取列表的长度
(integer) 2
127.0.0.1:6379>
#########################################################################
# 移除指定值
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 one # 移除list中指定个数的元素值
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
127.0.0.1:6379> lrem list 2 three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
#########################################################################
# trim 截断
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> ltrim list 1 2 # 通过下标截取指定的长度,这个list已经改变了,只剩下截取的元素
OK
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
#########################################################################
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> rpoplpush list mylist # 移除列表最后一个元素,并将其添加到另一个列表
"one"
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
#########################################################################
127.0.0.1:6379> exists list
(integer) 0
127.0.0.1:6379> lset list 0 one # 将列表中指定下标的值进行修改,如果不存在列表,就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list two
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "two"
127.0.0.1:6379> lset list 0 one
OK
127.0.0.1:6379> lrange list 0 -1
1) "one"
127.0.0.1:6379> lset list 1 one
(error) ERR index out of range
#########################################################################
# linsert 将某个值插入列表中指定值的前面或者后面
127.0.0.1:6379> lrange list 0 -1
1) "one"
127.0.0.1:6379> linsert list before one two
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> linsert list after one three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "three"
127.0.0.1:6379> linsert list after one four
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "four"
4) "three"
127.0.0.1:6379> linsert list after one four
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "four"
4) "four"
5) "three"
127.0.0.1:6379> linsert list after four five
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "four"
4) "five"
5) "four"
6) "three"
小结
- list实际上是一个链表, before node, after, left, right 都可以插入值
- 如果key不存在,创建新的链表
- 如果key存在,新增内容
- 在两边插入或改动值,效率最高!
Hash(哈希)
Map集合, key-map 这个值是一个map集合!
本质和String类型没有太大区别,还是key-value,命令和String基本相同
127.0.0.1:6379> hset myhash name zhangsan # 设置一个key-value
(integer) 1
127.0.0.1:6379> hget myhash name # 获取一个字段值
"zhangsan"
127.0.0.1:6379> hmset myhash name lisi age 18 # 设置多个key-value
OK
127.0.0.1:6379> hmget myhash name age # 获取多个key-value
1) "lisi"
2) "18"
127.0.0.1:6379> hgetall myhash # 获取全部数据
1) "name"
2) "lisi"
3) "age"
4) "18"
127.0.0.1:6379> hdel myhash age # 删除myhash指定key
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "name"
2) "lisi"
127.0.0.1:6379> hlen myhash # 获取hash表的字段数量
(integer) 1
127.0.0.1:6379> hexists myhash name # 判断myhash中是否存在指定key
(integer) 1
127.0.0.1:6379> hkeys myhash # 获取所有key
1) "name"
2) "age"
127.0.0.1:6379> hvals myhash # 获取所有value
1) "lisi"
2) "18"
hash更适合对象的存储,String适合字符串
Set(集合)
set中的值不能重复,是无序的!
127.0.0.1:6379> sadd set one # set中添加元素
(integer) 1
127.0.0.1:6379> sadd set two
(integer) 1
127.0.0.1:6379> sadd set three
(integer) 1
127.0.0.1:6379> smembers set # 查看指定set的所有值
1) "three"
2) "one"
3) "two"
127.0.0.1:6379> sismember set one # 判断set中是否存在one
(integer) 1
127.0.0.1:6379> sismember set four # 不存在返回0
(integer) 0
127.0.0.1:6379> scard set # 获取set中元素个数
(integer) 3
###################################################################################
127.0.0.1:6379> srem set one # 移除指定元素
(integer) 1
127.0.0.1:6379> smembers set
1) "three"
2) "two"
###################################################################################
127.0.0.1:6379> smembers set
1) "three"
2) "four"
3) "one"
4) "two"
127.0.0.1:6379> srandmember set # 随机抽取一个元素
"three"
127.0.0.1:6379> srandmember set 2 # 随机抽取指定个数元素
1) "one"
2) "four"
###################################################################################
# spop 随机删除key
127.0.0.1:6379> smembers set
1) "three"
2) "four"
3) "one"
4) "two"
127.0.0.1:6379> spop set
"four"
127.0.0.1:6379> smembers set
1) "three"
2) "one"
3) "two"
###################################################################################
# smove 将一个指定的值移动到另个一set集合中
127.0.0.1:6379> smembers set
1) "three"
2) "four"
3) "one"
4) "two"
127.0.0.1:6379> smove set myset one
(integer) 1
127.0.0.1:6379> smembers set
1) "three"
2) "four"
3) "two"
127.0.0.1:6379> smembers myset
1) "one"
###################################################################################
# 微博,B站,共同关注(并集)
# 数字集合类
# - 差集
# - 交集
# - 并集
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> smembers set2
1) "3"
2) "4"
3) "5"
127.0.0.1:6379> sdiff set1 set2 # 差集 在set1中,且不在set2中
1) "1"
2) "2"
127.0.0.1:6379> sinter set1 set2 # 交集
1) "3"
127.0.0.1:6379> sunion set1 set2 # 并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
Zset
在set的基础上,增加了一个值,set k1 v1 | zset k1 score1 v2
127.0.0.1:6379> zadd myset 1 one # 添加一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three # 添加多个值
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
##########################################################################
# ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
127.0.0.1:6379> zadd salary 2000 xiaohong # 添加三个用户
(integer) 1
127.0.0.1:6379> zadd salary 1200 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 899 wangwu
(integer) 1
127.0.0.1:6379> zrange salary 0 -1 # 按score升序排序
1) "wangwu"
2) "zhangsan"
3) "xiaohong"
127.0.0.1:6379> zrevrange salary 0 -1 # 按score降序排序
1) "xiaohong"
2) "zhangsan"
3) "wangwu"
127.0.0.1:6379> zrangebyscore salary -inf +inf # 按score排序,显示全部用户
1) "wangwu"
2) "zhangsan"
3) "xiaohong"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 按score排序,显示全部用户,且显示成绩
1) "wangwu"
2) "899"
3) "zhangsan"
4) "1200"
5) "xiaohong"
6) "2000"
127.0.0.1:6379> zrangebyscore salary 0 9999 # 设置score范围,进行排序
1) "wangwu"
2) "zhangsan"
3) "xiaohong"
127.0.0.1:6379> zrangebyscore salary 0 1999
1) "wangwu"
2) "zhangsan"
################################################################################
# zrem 移除指定元素
# zcard 获取集合长度
127.0.0.1:6379> zrange salary 0 -1
1) "wangwu"
2) "zhangsan"
3) "xiaohong"
127.0.0.1:6379> zrem salary xiaohong
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "wangwu"
2) "zhangsan"
127.0.0.1:6379> zcard salary
(integer) 2
################################################################################
127.0.0.1:6379> zrevrange salary 0 -1 withscores
1) "zhangsan"
2) "1200"
3) "wangwu"
4) "899"
127.0.0.1:6379> zcount salary 800 900 # 获取指定区间的成员数量
(integer) 1
三种特殊数据类型
geospatial 地理空间
朋友的定位,附近的人,打车距离计算?
Redis的Geo在Redis3.2版本就推出了!这个功能可以推算地理位置信息,两地之间的距离,方圆几里的人!
可以查询一些测试数据:http://www.hao828.com/chaxun/zhongguochengshijingweidu/
Geoadd
geoadd key longitude latitude member [longitude latitude member ...]
时间复杂度:每一个元素添加是O(log(N)) ,N是sorted set的元素数量。
将指定的地理空间位置(纬度、经度、名称)添加到指定的key
中。这些数据将会存储到sorted set
这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。
当坐标位置超出上述指定范围时,该命令将会返回一个错误。
# geoadd key longitude latitude member [longitude latitude member ...]
# 添加城市地理位置
127.0.0.1:6379> geoadd china:city 116.408 39.904 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.445 31.213 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 117.246 39.117 tianjin
(integer) 1
geopos
时间复杂度:O(log(N)) for each member requested, where N is the number of elements in the sorted set.
从key里返回所有给定位置元素的位置(经度和纬度)。
127.0.0.1:6379> geopos china:city beijing
1) 1) "116.40800267457962036"
2) "39.90399988166036138"
127.0.0.1:6379> geopos china:city shanghai
1) 1) "121.44499808549880981"
2) "31.213001199663303"
geodist
时间复杂度:O(log(N))
返回两个给定位置之间的距离。
如果两个位置之间的其中一个不存在, 那么命令返回空值。
指定单位的参数 unit 必须是以下单位的其中一个:
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
127.0.0.1:6379> geodist china:city beijing shanghai # 获取北京到天津的直线距离,单位m
"1068232.0171"
127.0.0.1:6379> geodist china:city beijing shanghai km # 指定单位km
"1068.2320"
127.0.0.1:6379> geodist china:city beijing tianjin
"113283.6949"
127.0.0.1:6379> geodist china:city beijing tianjin km
"113.2837"
georadius
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
时间复杂度:O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.
以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
范围可以使用以下其中一个单位:
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
127.0.0.1:6379> georadius china:city 117 35 1000 km # 显示距离指定经纬度的城市
1) "tianjin"
2) "beijing"
3) "shanghai"
127.0.0.1:6379> georadius china:city 117 35 500 km
1) "tianjin"
127.0.0.1:6379> georadius china:city 117 35 500 km withdist # 显示距离指定经纬度的城市,同时显示距离
1) 1) "tianjin"
2) "458.4383"
127.0.0.1:6379> georadius china:city 117 35 1000 km withdist
1) 1) "tianjin"
2) "458.4383"
2) 1) "beijing"
2) "547.9485"
3) 1) "shanghai"
2) "590.5622"
127.0.0.1:6379> georadius china:city 117 35 1000 km withcoord # 显示距离指定经纬度的城市,同时显示经纬度
1) 1) "tianjin"
2) 1) "117.24599987268447876"
2) "39.11699937833952134"
2) 1) "beijing"
2) 1) "116.40800267457962036"
2) "39.90399988166036138"
3) 1) "shanghai"
2) 1) "121.44499808549880981"
2) "31.213001199663303"
127.0.0.1:6379> georadius china:city 117 35 1000 km withcoord count 2 # 按距离排序显示前两个
1) 1) "tianjin"
2) 1) "117.24599987268447876"
2) "39.11699937833952134"
2) 1) "beijing"
2) 1) "116.40800267457962036"
2) "39.90399988166036138"
georadiusbymember
georadiusbymember key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
指定成员的位置被用作查询的中心。
127.0.0.1:6379> georadiusbymember china:city beijing 500 km
1) "tianjin"
2) "beijing"
geohash
geohash key member [member ...]
该命令将返回11个字符的Geohash字符串!
# 将二维的经纬度转换为一维的字符串,如果两个字符串越相近,距离越近
127.0.0.1:6379> geohash china:city beijing shanghai
1) "wx4g0bm9xh0"
2) "wtw3ed1sct0"
Geo底层的原理就是zset,可以用zset命令操作geo,例如使用zrem命令删除元素
127.0.0.1:6379> zrange china:city 0 -1
1) "shanghai"
2) "tianjin"
3) "beijing"
127.0.0.1:6379> zrem china:city tianjin
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "shanghai"
2) "beijing"
127.0.0.1:6379>
hyperloglog
介绍
Redis2.8.9版本更新了Hyperloglog数据结构
Redis Hyperloglog 基数统计的算法,不会存储元素本身!
什么是基数?一组不重复的数,基数估计有一定误差!
优点:占用的内存是固定的,2^64不同元素的技术,只需要12KB内存!如果从内存角度来比较的话,Hyperloglog首选。
统计存在0.81%的错误率!
应用:网页的UV(一个人访问一个网站多次,但还是算作一个人!)
传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!
这个方式如果保存大量用户的ID,就会比较麻烦!我们的目的是为了计数,而不是保存用户ID!
常用命令
127.0.0.1:6379> pfadd mykey1 a b c d e f # 创建第一组元素
(integer) 1
127.0.0.1:6379> pfadd mykey2 e f g h i j k # 创建第一组元素
(integer) 1
127.0.0.1:6379> pfcount mykey1 # 统计组内元素个数
(integer) 6
127.0.0.1:6379> pfcount mykey2
(integer) 7
127.0.0.1:6379> pfmerge mykey3 mykey1 mykey2 # 将 mykey1 mykey2 合并为 mykey3
OK
127.0.0.1:6379> pfcount mykey3
(integer) 11
如果允许容错,那么一定可以使用Hyperloglog!
bitmaps
位运算
统计用户信息,活跃,不活跃!登录,未登录!打卡,未打卡!
两个状态的表示,都可以使用Bitmaps!
Bitmaps 位图,数据结构!都是操作二进制为来进行记录,就只有 0 和 1 两个状态!
如: 365天 = 365bit 1字节 = 8bit 46个字节左右!
使用bitmap来记录 周一到周六的打卡!
127.0.0.1:6379> setbit sign 0 0 # 设置值
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
查看某一天是否打卡!
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 4
(integer) 0
统计一周打卡天数!
127.0.0.1:6379> bitcount sign
(integer) 3