Redis数据结构大全

1,506 阅读14分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

Redis数据结构大全

五大基本数据类型

Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。

Redis-key

在redis中无论什么数据类型,在数据库中都是以key-value形式保存,通过进行对Redis-key的操作,来完成对数据库中数据的操作。

下面学习的命令:

  • exists key:判断键是否存在
  • del key:删除键值对
  • move key db:将键值对移动到指定数据库
  • expire key second:设置键值对的过期时间
  • type key:查看value的数据类型
 127.0.0.1:6379> keys * # 查看当前数据库所有key
 (empty list or set)
 127.0.0.1:6379> set name qinjiang # set key
 OK
 127.0.0.1:6379> set age 20
 OK
 127.0.0.1:6379> keys *
 1) "age"
 2) "name"
 127.0.0.1:6379> move age 1 # 将键值对移动到指定数据库
 (integer) 1
 127.0.0.1:6379> EXISTS age # 判断键是否存在
 (integer) 0 # 不存在
 127.0.0.1:6379> EXISTS name
 (integer) 1 # 存在
 127.0.0.1:6379> SELECT 1
 OK
 127.0.0.1:6379[1]> keys *
 1) "age"
 127.0.0.1:6379[1]> del age # 删除键值对
 (integer) 1 # 删除个数
 ​
 ​
 127.0.0.1:6379> set age 20
 OK
 127.0.0.1:6379> EXPIRE age 15 # 设置键值对的过期时间
 ​
 (integer) 1 # 设置成功 开始计数
 127.0.0.1:6379> ttl age # 查看key的过期剩余时间
 (integer) 13
 127.0.0.1:6379> ttl age
 (integer) 11
 127.0.0.1:6379> ttl age
 (integer) 9
 127.0.0.1:6379> ttl age
 (integer) -2 # -2 表示key过期,-1表示key未设置过期时间
 ​
 127.0.0.1:6379> get age # 过期的key 会被自动delete
 (nil)
 127.0.0.1:6379> keys *
 1) "name"
 ​
 127.0.0.1:6379> type name # 查看value的数据类型
 string

关于TTL命令

Redis的key,通过TTL命令返回key的过期时间,一般来说有3种:

  • 当前key没有设置过期时间,所以会返回-1
  • 当前key有设置过期时间,而且key已经过期,所以会返回-2.
  • 当前key有设置过期时间,且key还没有过期,故会返回key的正常剩余时间.

关于重命名RENAME和RENAMENX

  • RENAME key newkey修改 key 的名称
  • RENAMENX key newkey仅当 newkey 不存在时,将 key 改名为 newkey 。

更多命令学习:www.redis.net.cn/order/

String(字符串)

普通的set、get直接略过。

image-20221116194347306

image-20221116194408891

String类似的使用场景:value除了是字符串还可以是数字,用途举例:

  • 计数器
  • 统计多单位的数量:uid:123666:follow 0
  • 粉丝数
  • 对象存储缓存

List(列表)

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。

首先我们列表,可以经过规则定义将其变为队列、栈、双端队列等

image-20221116194508650

正如图Redis中List是可以进行双端操作的,所以命令也就分为了LXXX和RLLL两类,有时候L也表示List例如LLEN

image-20221116194556288

 ---------------------------LPUSH---RPUSH---LRANGE--------------------------------
 ​
 127.0.0.1:6379> LPUSH mylist k1 # LPUSH mylist=>{1}
 (integer) 1
 127.0.0.1:6379> LPUSH mylist k2 # LPUSH mylist=>{2,1}
 (integer) 2
 127.0.0.1:6379> RPUSH mylist k3 # RPUSH mylist=>{2,1,3}
 (integer) 3
 127.0.0.1:6379> get mylist # 普通的get是无法获取list值的
 (error) WRONGTYPE Operation against a key holding the wrong kind of value
 127.0.0.1:6379> LRANGE mylist 0 4 # LRANGE 获取起止位置范围内的元素
 1) "k2"
 2) "k1"
 3) "k3"
 127.0.0.1:6379> LRANGE mylist 0 2
 1) "k2"
 2) "k1"
 3) "k3"
 127.0.0.1:6379> LRANGE mylist 0 1
 1) "k2"
 2) "k1"
 127.0.0.1:6379> LRANGE mylist 0 -1 # 获取全部元素
 1) "k2"
 2) "k1"
 3) "k3"
 ​
 ---------------------------LPUSHX---RPUSHX-----------------------------------
 ​
 127.0.0.1:6379> LPUSHX list v1 # list不存在 LPUSHX失败
 (integer) 0
 127.0.0.1:6379> LPUSHX list v1 v2  
 (integer) 0
 127.0.0.1:6379> LPUSHX mylist k4 k5 # 向mylist中 左边 PUSH k4 k5
 (integer) 5
 127.0.0.1:6379> LRANGE mylist 0 -1
 1) "k5"
 2) "k4"
 3) "k2"
 4) "k1"
 5) "k3"
 ​
 ---------------------------LINSERT--LLEN--LINDEX--LSET----------------------------
 ​
 127.0.0.1:6379> LINSERT mylist after k2 ins_key1 # 在k2元素后 插入ins_key1
 (integer) 6
 127.0.0.1:6379> LRANGE mylist 0 -1
 1) "k5"
 2) "k4"
 3) "k2"
 4) "ins_key1"
 5) "k1"
 6) "k3"
 127.0.0.1:6379> LLEN mylist # 查看mylist的长度
 (integer) 6
 127.0.0.1:6379> LINDEX mylist 3 # 获取下标为3的元素
 "ins_key1"
 127.0.0.1:6379> LINDEX mylist 0
 "k5"
 127.0.0.1:6379> LSET mylist 3 k6 # 将下标3的元素 set值为k6
 OK
 127.0.0.1:6379> LRANGE mylist 0 -1
 1) "k5"
 2) "k4"
 3) "k2"
 4) "k6"
 5) "k1"
 6) "k3"
 ​
 ---------------------------LPOP--RPOP--------------------------
 ​
 127.0.0.1:6379> LPOP mylist # 左侧(头部)弹出
 "k5"
 127.0.0.1:6379> RPOP mylist # 右侧(尾部)弹出
 "k3"
 ​
 ---------------------------RPOPLPUSH--------------------------
 ​
 127.0.0.1:6379> LRANGE mylist 0 -1
 1) "k4"
 2) "k2"
 3) "k6"
 4) "k1"
 127.0.0.1:6379> RPOPLPUSH mylist newlist # 将mylist的最后一个值(k1)弹出,加入到newlist的头部
 "k1"
 127.0.0.1:6379> LRANGE newlist 0 -1
 1) "k1"
 127.0.0.1:6379> LRANGE mylist 0 -1
 1) "k4"
 2) "k2"
 3) "k6"
 ​
 ---------------------------LTRIM--------------------------
 ​
 127.0.0.1:6379> LTRIM mylist 0 1 # 截取mylist中的 0~1部分
 OK
 127.0.0.1:6379> LRANGE mylist 0 -1
 1) "k4"
 2) "k2"
 ​
 # 初始 mylist: k2,k2,k2,k2,k2,k2,k4,k2,k2,k2,k2
 ---------------------------LREM--------------------------
 ​
 127.0.0.1:6379> LREM mylist 3 k2 # 从头部开始搜索 至多删除3个 k2
 (integer) 3
 # 删除后:mylist: k2,k2,k2,k4,k2,k2,k2,k2
 ​
 127.0.0.1:6379> LREM mylist -2 k2 #从尾部开始搜索 至多删除2个 k2
 (integer) 2
 # 删除后:mylist: k2,k2,k2,k4,k2,k2
 ​
 ​
 ---------------------------BLPOP--BRPOP--------------------------
 ​
 mylist: k2,k2,k2,k4,k2,k2
 newlist: k1
 ​
 127.0.0.1:6379> BLPOP newlist mylist 30 # 从newlist中弹出第一个值,mylist作为候选
 1) "newlist" # 弹出
 2) "k1"
 127.0.0.1:6379> BLPOP newlist mylist 30
 1) "mylist" # 由于newlist空了 从mylist中弹出
 2) "k2"
 127.0.0.1:6379> BLPOP newlist 30
 (30.10s) # 超时了
 ​
 127.0.0.1:6379> BLPOP newlist 30 # 我们连接另一个客户端向newlist中push了test, 阻塞被解决。
 1) "newlist"
 2) "test"
 (12.54s)
 ​

小结

  • list实际上是一个链表,before Node after , left, right 都可以插入值
  • 如果key不存在,则创建新的链表
  • 如果key存在,新增内容
  • 如果移除了所有值,空链表,也代表不存在
  • 在两边插入或者改动值,效率最高!修改中间元素,效率相对较低

应用:

消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)

Set(集合)

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)

image-20221117165849403

 ---------------SADD--SCARD--SMEMBERS--SISMEMBER--------------------
 ​
 127.0.0.1:6379> SADD myset m1 m2 m3 m4 # 向myset中增加成员 m1~m4
 (integer) 4
 127.0.0.1:6379> SCARD myset # 获取集合的成员数目
 (integer) 4
 127.0.0.1:6379> smembers myset # 获取集合中所有成员
 1) "m4"
 2) "m3"
 3) "m2"
 4) "m1"
 127.0.0.1:6379> SISMEMBER myset m5 # 查询m5是否是myset的成员
 (integer) 0 # 不是,返回0
 127.0.0.1:6379> SISMEMBER myset m2
 (integer) 1 # 是,返回1
 127.0.0.1:6379> SISMEMBER myset m3
 (integer) 1
 ​
 ---------------------SRANDMEMBER--SPOP----------------------------------
 ​
 127.0.0.1:6379> SRANDMEMBER myset 3 # 随机返回3个成员
 1) "m2"
 2) "m3"
 3) "m4"
 127.0.0.1:6379> SRANDMEMBER myset # 随机返回1个成员
 "m3"
 127.0.0.1:6379> SPOP myset 2 # 随机移除并返回2个成员
 1) "m1"
 2) "m4"
 # 将set还原到{m1,m2,m3,m4}
 ​
 ---------------------SMOVE--SREM----------------------------------------
 ​
 127.0.0.1:6379> SMOVE myset newset m3 # 将myset中m3成员移动到newset集合
 (integer) 1
 127.0.0.1:6379> SMEMBERS myset
 1) "m4"
 2) "m2"
 3) "m1"
 127.0.0.1:6379> SMEMBERS newset
 1) "m3"
 127.0.0.1:6379> SREM newset m3 # 从newset中移除m3元素
 (integer) 1
 127.0.0.1:6379> SMEMBERS newset
 (empty list or set)
 ​
 # 下面开始是多集合操作,多集合操作中若只有一个参数默认和自身进行运算
 # setx=>{m1,m2,m4,m6}, sety=>{m2,m5,m6}, setz=>{m1,m3,m6}
 ​
 -----------------------------SDIFF------------------------------------
 ​
 127.0.0.1:6379> SDIFF setx sety setz # 等价于setx-sety-setz
 1) "m4"
 127.0.0.1:6379> SDIFF setx sety # setx - sety
 1) "m4"
 2) "m1"
 127.0.0.1:6379> SDIFF sety setx # sety - setx
 1) "m5"
 ​
 ​
 -------------------------SINTER---------------------------------------
 # 共同关注(交集)
 ​
 127.0.0.1:6379> SINTER setx sety setz # 求 setx、sety、setx的交集
 1) "m6"
 127.0.0.1:6379> SINTER setx sety # 求setx sety的交集
 1) "m2"
 2) "m6"
 ​
 -------------------------SUNION---------------------------------------
 ​
 127.0.0.1:6379> SUNION setx sety setz # setx sety setz的并集
 1) "m4"
 2) "m6"
 3) "m3"
 4) "m2"
 5) "m1"
 6) "m5"
 127.0.0.1:6379> SUNION setx sety # setx sety 并集
 1) "m4"
 2) "m6"
 3) "m2"
 4) "m1"
 5) "m5"
 ​
 127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijin
 (integer) 1
 127.0.0.1:6379> GEOADD china:city 121.47 31.23 shanghai
 (integer) 1
 127.0.0.1:6379> GEOADD china:city 106.50 29.53 chongqi
 (integer) 1
 127.0.0.1:6379> GEOADD china:city 114.05 22.52 shenzhen
 (integer) 1
 127.0.0.1:6379> GEOADD china:city 120.16 30.24 hangzhou
 (integer) 1
 127.0.0.1:6379> GEOADD china:city 108.96 34.26 xian
 ​
 127.0.0.1:6379> GEOPOS china:city beijin chongqi
 1) 1) "116.39999896287918091"
    2) "39.90000009167092543"
 2) 1) "106.49999767541885376"
    2) "29.52999957900659211"
 127.0.0.1:6379> 
 ​

Hash(哈希)

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。

Set就是一种简化的Hash,只变动key,而value使用默认值填充。可以将一个Hash表作为一个对象进行存储,表中存放对象的信息。

image-20221117165949348

 ------------------------HSET--HMSET--HSETNX----------------
 127.0.0.1:6379> HSET studentx name sakura # 将studentx哈希表作为一个对象,设置name为sakura
 (integer) 1
 127.0.0.1:6379> HSET studentx name gyc # 重复设置field进行覆盖,并返回0
 (integer) 0
 127.0.0.1:6379> HSET studentx age 20 # 设置studentx的age为20
 (integer) 1
 127.0.0.1:6379> HMSET studentx sex 1 tel 15623667886 # 设置sex为1,tel为15623667886
 OK
 127.0.0.1:6379> HSETNX studentx name gyc # HSETNX 设置已存在的field
 (integer) 0 # 失败
 127.0.0.1:6379> HSETNX studentx email 12345@qq.com
 (integer) 1 # 成功
 ​
 ----------------------HEXISTS--------------------------------
 127.0.0.1:6379> HEXISTS studentx name # name字段在studentx中是否存在
 (integer) 1 # 存在
 127.0.0.1:6379> HEXISTS studentx addr
 (integer) 0 # 不存在
 ​
 -------------------HGET--HMGET--HGETALL-----------
 127.0.0.1:6379> HGET studentx name # 获取studentx中name字段的value
 "gyc"
 127.0.0.1:6379> HMGET studentx name age tel # 获取studentx中name、age、tel字段的value
 1) "gyc"
 2) "20"
 3) "15623667886"
 127.0.0.1:6379> HGETALL studentx # 获取studentx中所有的field及其value
  1) "name"
  2) "gyc"
  3) "age"
  4) "20"
  5) "sex"
  6) "1"
  7) "tel"
  8) "15623667886"
  9) "email"
 10) "12345@qq.com"
 ​
 ​
 --------------------HKEYS--HLEN--HVALS--------------
 127.0.0.1:6379> HKEYS studentx # 查看studentx中所有的field
 1) "name"
 2) "age"
 3) "sex"
 4) "tel"
 5) "email"
 127.0.0.1:6379> HLEN studentx # 查看studentx中的字段数量
 (integer) 5
 127.0.0.1:6379> HVALS studentx # 查看studentx中所有的value
 1) "gyc"
 2) "20"
 3) "1"
 4) "15623667886"
 5) "12345@qq.com"
 ​
 -------------------------HDEL--------------------------
 127.0.0.1:6379> HDEL studentx sex tel # 删除studentx 中的sex、tel字段
 (integer) 2
 127.0.0.1:6379> HKEYS studentx
 1) "name"
 2) "age"
 3) "email"
 ​
 -------------HINCRBY--HINCRBYFLOAT------------------------
 127.0.0.1:6379> HINCRBY studentx age 1 # studentx的age字段数值+1
 (integer) 21
 127.0.0.1:6379> HINCRBY studentx name 1 # 非整数字型字段不可用
 (error) ERR hash value is not an integer
 127.0.0.1:6379> HINCRBYFLOAT studentx weight 0.6 # weight字段增加0.6
 "90.8"
 ​

Hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息!

Hash更适合于对象的存储,Sring更加适合字符串存储!

Zset(有序集合)

不同的是每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大的排序。

score相同:按字典顺序排序

有序集合的成员是唯一的,但分数(score)却可以重复

image-20221117170123315

image-20221117170146797

 -------------------ZADD--ZCARD--ZCOUNT--------------
 127.0.0.1:6379> ZADD myzset 1 m1 2 m2 3 m3 # 向有序集合myzset中添加成员m1 score=1 以及成员m2 score=2..
 (integer) 2
 127.0.0.1:6379> ZCARD myzset # 获取有序集合的成员数
 (integer) 2
 127.0.0.1:6379> ZCOUNT myzset 0 1 # 获取score在 [0,1]区间的成员数量
 (integer) 1
 127.0.0.1:6379> ZCOUNT myzset 0 2
 (integer) 2
 ​
 ----------------ZINCRBY--ZSCORE--------------------------
 127.0.0.1:6379> ZINCRBY myzset 5 m2 # 将成员m2的score +5
 "7"
 127.0.0.1:6379> ZSCORE myzset m1 # 获取成员m1的score
 "1"
 127.0.0.1:6379> ZSCORE myzset m2
 "7"
 ​
 --------------ZRANK--ZRANGE-----------------------------------
 127.0.0.1:6379> ZRANK myzset m1 # 获取成员m1的索引,索引按照score排序,score相同索引值按字典顺序顺序增加
 (integer) 0
 127.0.0.1:6379> ZRANK myzset m2
 (integer) 2
 127.0.0.1:6379> ZRANGE myzset 0 1 # 获取索引在 0~1的成员
 1) "m1"
 2) "m3"
 127.0.0.1:6379> ZRANGE myzset 0 -1 # 获取全部成员
 1) "m1"
 2) "m3"
 3) "m2"
 ​
 #testset=>{abc,add,amaze,apple,back,java,redis} score均为0
 ------------------ZRANGEBYLEX---------------------------------
 127.0.0.1:6379> ZRANGEBYLEX testset - + # 返回所有成员
 1) "abc"
 2) "add"
 3) "amaze"
 4) "apple"
 5) "back"
 6) "java"
 7) "redis"
 127.0.0.1:6379> ZRANGEBYLEX testset - + LIMIT 0 3 # 分页 按索引显示查询结果的 0,1,2条记录
 1) "abc"
 2) "add"
 3) "amaze"
 127.0.0.1:6379> ZRANGEBYLEX testset - + LIMIT 3 3 # 显示 3,4,5条记录
 1) "apple"
 2) "back"
 3) "java"
 127.0.0.1:6379> ZRANGEBYLEX testset (- [apple # 显示 (-,apple] 区间内的成员
 1) "abc"
 2) "add"
 3) "amaze"
 4) "apple"
 127.0.0.1:6379> ZRANGEBYLEX testset [apple [java # 显示 [apple,java]字典区间的成员
 1) "apple"
 2) "back"
 3) "java"
 ​
 -----------------------ZRANGEBYSCORE---------------------
 127.0.0.1:6379> ZRANGEBYSCORE myzset 1 10 # 返回score在 [1,10]之间的的成员
 1) "m1"
 2) "m3"
 3) "m2"
 127.0.0.1:6379> ZRANGEBYSCORE myzset 1 5
 1) "m1"
 2) "m3"
 ​
 --------------------ZLEXCOUNT-----------------------------
 127.0.0.1:6379> ZLEXCOUNT testset - +
 (integer) 7
 127.0.0.1:6379> ZLEXCOUNT testset [apple [java
 (integer) 3
 ​
 ------------------ZREM--ZREMRANGEBYLEX--ZREMRANGBYRANK--ZREMRANGEBYSCORE--------------------------------
 127.0.0.1:6379> ZREM testset abc # 移除成员abc
 (integer) 1
 127.0.0.1:6379> ZREMRANGEBYLEX testset [apple [java # 移除字典区间[apple,java]中的所有成员
 (integer) 3
 127.0.0.1:6379> ZREMRANGEBYRANK testset 0 1 # 移除排名0~1的所有成员
 (integer) 2
 127.0.0.1:6379> ZREMRANGEBYSCORE myzset 0 3 # 移除score在 [0,3]的成员
 (integer) 2
 ​
 ​
 # testset=> {abc,add,apple,amaze,back,java,redis} score均为0
 # myzset=> {(m1,1),(m2,2),(m3,3),(m4,4),(m7,7),(m9,9)}
 ----------------ZREVRANGE--ZREVRANGEBYSCORE--ZREVRANGEBYLEX-----------
 127.0.0.1:6379> ZREVRANGE myzset 0 3 # 按score递减排序,然后按索引,返回结果的 0~3
 1) "m9"
 2) "m7"
 3) "m4"
 4) "m3"
 127.0.0.1:6379> ZREVRANGE myzset 2 4 # 返回排序结果的 索引的2~4
 1) "m4"
 2) "m3"
 3) "m2"
 127.0.0.1:6379> ZREVRANGEBYSCORE myzset 6 2 # 按score递减顺序 返回集合中分数在[2,6]之间的成员
 1) "m4"
 2) "m3"
 3) "m2"
 127.0.0.1:6379> ZREVRANGEBYLEX testset [java (add # 按字典倒序 返回集合中(add,java]字典区间的成员
 1) "java"
 2) "back"
 3) "apple"
 4) "amaze"
 ​
 -------------------------ZREVRANK------------------------------
 127.0.0.1:6379> ZREVRANK myzset m7 # 按score递减顺序,返回成员m7索引
 (integer) 1
 127.0.0.1:6379> ZREVRANK myzset m2
 (integer) 4
 ​
 ​
 # mathscore=>{(xm,90),(xh,95),(xg,87)} 小明、小红、小刚的数学成绩
 # enscore=>{(xm,70),(xh,93),(xg,90)} 小明、小红、小刚的英语成绩
 -------------------ZINTERSTORE--ZUNIONSTORE-----------------------------------
 127.0.0.1:6379> ZINTERSTORE sumscore 2 mathscore enscore # 将mathscore enscore进行合并 结果存放到sumscore
 (integer) 3
 127.0.0.1:6379> ZRANGE sumscore 0 -1 withscores # 合并后的score是之前集合中所有score的和
 1) "xm"
 2) "160"
 3) "xg"
 4) "177"
 5) "xh"
 6) "188"
 ​
 127.0.0.1:6379> ZUNIONSTORE lowestscore 2 mathscore enscore AGGREGATE MIN # 取两个集合的成员score最小值作为结果的
 (integer) 3
 127.0.0.1:6379> ZRANGE lowestscore 0 -1 withscores
 1) "xm"
 2) "70"
 3) "xg"
 4) "87"
 5) "xh"
 6) "93"
 ​

应用案例:

  • set排序 存储班级成绩表 工资表排序!
  • 普通消息,1.重要消息 2.带权重进行判断
  • 排行榜应用实现,取Top N测试

三种特殊数据类型

Geospatial(地理位置)

使用经纬度定位地理坐标并用一个有序集合zset保存,所以zset命令也可以使用

image-20221117170238577

有效经纬度

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

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

于GEORADIUS的参数

通过georadius就可以完成 附近的人功能

withcoord:带上坐标

withdist:带上距离,单位与半径单位相同

COUNT n : 只显示前n个(按距离递增排序)

 ----------------georadius---------------------
 127.0.0.1:6379> GEORADIUS china:city 120 30 500 km withcoord withdist # 查询经纬度(120,30)坐标500km半径内的成员
 1) 1) "hangzhou"
    2) "29.4151"
    3) 1) "120.20000249147415"
       2) "30.199999888333501"
 2) 1) "shanghai"
    2) "205.3611"
    3) 1) "121.40000134706497"
       2) "31.400000253193539"
      
 ------------geohash---------------------------
 127.0.0.1:6379> geohash china:city yichang shanghai # 获取成员经纬坐标的geohash表示
 1) "wmrjwbr5250"
 2) "wtw6ds0y300"
 ​

Hyperloglog(基数统计)

什么是基数?

数据集中不重复的元素的个数。

A{1,3,5,7,8,9}

B{1,3,5,7,8}

基数(不重复的元素) = 5 可以接受误差!

简介:

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

花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。

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

其底层使用string数据类型

应用场景:

网页的访问量(UV):一个用户多次访问,也只能算作一个人。

传统实现,存储用户的id,然后每次进行比较。当用户变多之后这种方式及其浪费空间,而我们的目的只是计数,Hyperloglog就能帮助我们利用最小的空间完成。

image-20221117170439480

 ----------PFADD--PFCOUNT---------------------
 127.0.0.1:6379> PFADD myelemx a b c d e f g h i j k # 添加元素
 (integer) 1
 127.0.0.1:6379> type myelemx # hyperloglog底层使用String
 string
 127.0.0.1:6379> PFCOUNT myelemx # 估算myelemx的基数
 (integer) 11
 127.0.0.1:6379> PFADD myelemy i j k z m c b v p q s
 (integer) 1
 127.0.0.1:6379> PFCOUNT myelemy
 (integer) 11
 ​
 ----------------PFMERGE-----------------------
 127.0.0.1:6379> PFMERGE myelemz myelemx myelemy # 合并myelemx和myelemy 成为myelemz
 OK
 127.0.0.1:6379> PFCOUNT myelemz # 估算基数
 (integer) 17
 ​

如果允许容错,那么一定可以使用Hyperloglog !

如果不允许容错,就使用set或者自己的数据类型即可 !

BitMaps(位图)

使用位存储,信息状态只有 0 和 1

Bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND,OR,XOR,NOT以及其它位操作。

应用场景

签到统计、状态统计

image-20221117170647201

 ------------setbit--getbit--------------
 127.0.0.1:6379> setbit sign 0 1 # 设置sign的第0位为 1 
 (integer) 0
 127.0.0.1:6379> setbit sign 2 1 # 设置sign的第2位为 1  不设置默认 是0
 (integer) 0
 127.0.0.1:6379> setbit sign 3 1
 (integer) 0
 127.0.0.1:6379> setbit sign 5 1
 (integer) 0
 127.0.0.1:6379> type sign
 string
 ​
 127.0.0.1:6379> getbit sign 2 # 获取第2位的数值
 (integer) 1
 127.0.0.1:6379> getbit sign 3
 (integer) 1
 127.0.0.1:6379> getbit sign 4 # 未设置默认是0
 (integer) 0
 ​
 -----------bitcount----------------------------
 127.0.0.1:6379> BITCOUNT sign # 统计sign中为1的位数
 (integer) 4
 ​