一、五大基本数据类型

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库缓存消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Key(键):Redis 键命令用于管理 redis 的键

keys *	#查看所有的key

EXISTS key	#判断key是否存在,存在则返回1

MOVE key db	#将key移动到目标数据库

DEL key	#删除key

EXPIRE key seconds	#设置key的过期时间,单位为s

TTL key	#查看key的剩余时间

TYPE key	#查看当前key的类型

1.1、String(字符串)

Redis 字符串数据类型的相关命令用于管理 redis 字符串值

SET key value	#设置指定key的值

GET key	#获取指定key的值
APPEND key value	#如果key已经存在并且是一个字符串,则将指定的value追加到该key的末尾;如果key不存在,则相当于set key 

STRLEN key	#返回key所储存的字符串值的长度
INCR key	#将key中储存的数字值增一

INCRBY key increment	#将key所储存的值加上给定的增量值

DECR key	#将key中储存的数字值减一

DECRBY key decrement	#key所储存的值减去给定的减量值
GETRANGE key start end	#返回key中下标从start到end的子字符串(下标从0开始)
GETRANGE key 0 -1	#返回key全部字符串

SETRANGE key offset value	#用value参数覆写给定key所储存的字符串值,从偏移量offset始。
SETNX key value	#不存在则创建:只有在key不存在时设置key的值;否则创建失败

SETEX key seconds value	#设置过期时间:将值key的值为value,且过期时间为seconds(以秒为单位)

MSET key value [key value ...]	#同时设置一个或多个key-value对

MGET key1 [key2..]	#获取所有(一个或多个)给定key的值。

MSETNX key value [key value ...]	#同时设置一个或多个key-value对,当且仅当所有给定key都不存在(原子性操作,要么一起成功,要么一起失败)

对象:

set user:1{name:zsr,age:20}	#设置一个user:1对象,值为json的字符来保存一个对象

#这里的key是一个巧妙的设计:user:{id}:{filed}
mset user:1:name zsr user:1:age 20
mget user:1:name user:1:age
GETSET key value	#如果不存在值,返回nil;如果存在值,返回原来的值,并设置为新的值 

使用场景:value除了是字符串还可以是数字

  • 计数器
  • 统计多单位的数量
  • 粉丝数
  • 对象缓存存储


1.2、List(列表)

Redis列表是简单的字符串列表,按照插入顺序排序;既可以作为队列,也可以作为栈

  • 你可以添加一个元素到列表的头部(左边)或者尾部(右边)
  • 一个列表最多可以包含 2^32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
LPUSH list value1 [value2]	#将一个或多个值插入到列表头部(左)

RPUSH list value1 [value2]	#将一个或多个值插入到列表尾部(右)

LRANGE list start stop	#获取列表指定范围内的元素
LRANGE list 0 -1	#显示全部列表元素	
image-20200801134318769
LPOP list	#移出并获取列表的头部元素,返回值为移除的元素

RPOP list	#移除列表的尾部元素,返回值为移除的元素。
LINDEX list index	#通过下标获取列表中的值(下标从0开始)

LLEN list	#获取列表长度

LREM list count value	#移除列表count个指定元素
 
LTRIM list start stop	#截取列表指定区间

RPOPLPUSH list1 list2	#移除列表1的尾部元素,并将该元素从头部添加到列表2并返回
exists list	#判断列表是否存在

lset list index value	#更改列表index处的值为value(前提是列表存在,否则会报错)
linsert list before|after pivot element	#向列表pivot元素的前|后插入元素element

使用场景

  • 消息队列


1.3、Set(集合)

String类型的无序不重复集合

  • Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
  • 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)
sadd set member [member ...]	#向集合set中添元素member

smembers set	#显示集合set的全部元素

sismember set member	#判断member是不是集合set中的元素
scard set	#获取集合set中元素的个数
srem set member [member ...]	#删除set集合中的元素member

spop set [count]	#随机删除set集合中的元素,可以指定个数count,默认为一个
srandmember set [count]	#随机抽取set集合中元素,可以指定个数count,默认为一个
smove set1 set2 member	#将set1中的元素member移动到set2中
sdiff set [set...]	#集合差集

sinter set [set...]	#集合交集

sunion set [set...]	#集合并集

使用场景

  • 微博关注的人
  • 共同关注、共同爱好、推荐好友(六度分割理论)


1.4、Hash(哈希)

String 类型的field(字段)和value(值) 的映射表,hash 特别适合用于存储对象。

  • 每个 hash 可以存储 232 - 1 键值对(40多亿)。
hset key field value [field value ...]	#将一个多个field-value对设置到哈希表key中

hmset key field1 value1 [field2 value2 ]	#同时将多个field-value对设置到哈希表key中

hget key field	#获取存储在哈希表中指定字段的值

hmget key field	[field ...]	#获取所有给定字段的值

hgetall key	#获取在哈希表中指定key的所有字段和值

hdel key field [field ...]	#删除一个或多个哈希表字段
hlen key	#获取哈希表中字段的数量
hexists key feild	#判断哈希表key中指定的字段是否存在
hkeys key	#获取所有哈希表中的字段

hvals key	#获取哈希表中所有值
hincrby key field increment	#为哈希表key中的指定字段的整数值加上增量increment
hsetnx key field value	#只有在字段field不存在时,设置哈希表字段的值

使用场景

  • 存储对象


1.5、Zset(有序集合)

有序不重复集合

  • 每个元素关联一个double类型的分数score,通过此分数为集合中的成员进行从小到大的排序。
  • 有序集合的成员是唯一的,但分数(score)却可以重复、
  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
  • 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

zadd key [nx|xx] [ch] [incr] score member [score member ...]

zadd key score member [score member ...]	#向有序集合添加一个或多个成员,或者更新已存在成员的分数

zrange key start stop [withscores]	#通过索引区间返回有序集合指定区间内的成员,可附带分数
zrange key 0 -1 [withscores]	#返回所有的成员[及其分数]

zrevrange key start stop [withscores]	#返回有序集中指定区间内的成员,通过索引,分数从高到低

zrangebyscore key min max [withscores] [limit offset count]	#通过分数返回有序集合指定区间内的成员

zrevrangebyscore key max min [withscores] [limit offset count]	#返回有序集中指定分数区间内的成员,分数从高到低排序
# 示例
127.0.0.1:6379> zadd salary 2000 zsr 3000 gcc 5000 bareth
(integer) 3
127.0.0.1:6379> zrangebyscore salary -inf +inf
1) "zsr"
2) "gcc"
3) "bareth"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "zsr"
2) "2000"
3) "gcc"
4) "3000"
5) "bareth"
6) "5000"
127.0.0.1:6379> zrangebyscore salary -inf 4000 withscores
1) "zsr"
2) "2000"
3) "gcc"
4) "3000"
zrem key member [member ...]	#移除有序集合中的一个或多个成员
zcard key	#获取有序集合的成员数
zcount key min max	#获取有序集合指定区间分数的成员数

使用场景:

  • 排序:存储班级成绩,工资表排序
  • 权重:普通消息(1),重要消息(2)
  • 排行榜实现:top 10设置



二、三种特殊数据类型

2.1、geospatial(地理位置)

官方文档geoadd 命令 – Redis中国用户组(CRUG)
image-20201123224139313

使用场景

  • 朋友的定位
  • 附近的人
  • 打车距离计算

2.1.1、GEOADD

将指定的地理空间位置(经度、纬度、名称)添加到指定的key

GEOADD key longitude latitude member [longitude latitude member ...]
  • 有效的经度从-180度到180度。
  • 有效的纬度从-85.05112878度到85.05112878度。

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

示例:

127.0.0.1:6379> geoadd china:city 116.23128 40.22077 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.02919 30.58203 wuhan
(integer) 1
127.0.0.1:6379> geoadd china:city 120.21201 30.2084 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 113.88308 22.55329 shenzhen
(integer) 1
127.0.0.1:6379> geoadd china:city 117.30794 31.79322 hefei
(integer) 1

2.1.2、GEOPOS

key里返回所有给定位置元素的位置(经度和纬度)

GEOPOS key member [member ...]

示例:

127.0.0.1:6379> geopos china:city beijing wuhan hangzhou shenzhen hefei
1) 1) "116.23128265142440796"
   2) "40.22076905438526495"
2) 1) "114.02918905019760132"
   2) "30.58203052674790712"
3) 1) "120.21200805902481079"
   2) "30.20839995425554747"
4) 1) "113.88307839632034302"
   2) "22.55329111565713873"
5) 1) "117.30793744325637817"
   2) "31.79321915080526395"

2.1.3、GEODIST

返回两个给定位置之间的距离。

GEODIST key member1 member2 [unit]
  • 如果两个位置之间的其中一个不存在, 那么命令返回空值。
  • 指定单位的参数 unit 必须是以下单位的其中一个:
  • m 表示单位为米
  • km 表示单位为千米
  • mi 表示单位为英里d
  • ft 表示单位为英尺
  • 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位

示例:

127.0.0.1:6379> geodist china:city beijing wuhan km
"1090.4028"

2.1.4、GEORADIUS

以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]

范围可以使用以下其中一个单位:

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

在给定以下可选项时, 命令会返回额外的信息:

  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。

命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:

  • ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。
  • DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。

在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 COUNT <count> 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。

示例:

#查询经纬度(110,30)附近1000km的城市	
127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "shenzhen"
2) "wuhan"
3) "hefei"
4) "hangzhou"

#查询经纬度(110,30)附近500km的城市,并返回城市与其的距离
127.0.0.1:6379> georadius china:city 110 30 500 km withdist
1) 1) "wuhan"
   2) "392.3221"
   
#查询经纬度(110,30)附近500km的城市,并返回城市的经纬度
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord
1) 1) "wuhan"
   2) 1) "114.02918905019760132"
      2) "30.58203052674790712"

#查询经纬度(110,30)附近1000km的城市,并返回城市的经纬度和城市与其的距离,限定返回前两个城市
127.0.0.1:6379> georadius china:city 110 30 1000 km withcoord withdist count 2
1) 1) "wuhan"
   2) "392.3221"
   3) 1) "114.02918905019760132"
      2) "30.58203052674790712"
2) 1) "hefei"
   2) "725.2703"
   3) 1) "117.30793744325637817"
      2) "31.79321915080526395"

2.1.5、GEORADIUSBYMEMBER

这个命令和 GEORADIUS命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS那样, 使用输入的经度和纬度来决定中心点

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]

示例:

#查询以北京为中心,方圆1000km内的城市,并附加与城市的距离以及城市的经纬度
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km withcoord withdist
1) 1) "beijing"
   2) "0.0000"
   3) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) "942.3343"
   3) 1) "117.30793744325637817"
      2) "31.79321915080526395"

2.1.6、GEOHASH

该命令将返回11个字符的Geohash字符串

GEOHASH key member [member ...]

示例:

#将二维的经纬度转换为一维的字符串,两个字符串越像,距离越接近
127.0.0.1:6379> geohash china:city beijing wuhan
1) "wx4sucvncn0"
2) "wt3jfz390x0"

2.1.7、总结

GEO底层的原理就是Zset,我们可以使用Zset的命令来操作GEO

127.0.0.1:6379> zrange china:city 0 -1
1) "shenzhen"
2) "wuhan"
3) "hefei"
4) "hangzhou"
5) "beijing"
127.0.0.1:6379> zrem china:city beijing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "shenzhen"
2) "wuhan"
3) "hefei"
4) "hangzhou"


2.2、hyperloglog

2.2.1、简介

什么是基数

数据集 {1, 3, 5, 7, 5, 7, 8},该数据集的基数集为 {1, 3, 5 ,7, 8},基数(不重复元素) = 5

hyperloglog简介

Redis 在 2.8.9 版本添加了 HyperLogLog 结构。

  • Redis HyperLogLog 是用来做基数统计的算法

  • 基数估计就是在误差可接受的范围内,快速计算基数。

  • 优点:在输入元素的数量或者体积非常大时,计算基数所需的空间总是固定且很小的。每个 HyperLogLog 键只需要花费12 KB内存,就可以计算接近 2^64个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

  • 缺点:有%0.81的错误率(统计UV数据时可忽略不计)

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

2.2.2、应用场景

比如统计网页的UV(一个人访问多次但只算做一次)时
- 传统的方式:set保存用户的id,利用其不重复特性,统计set集合中的用户数即可
  缺点:我们的目的时计数,而不是保存用户的id,此方法会保存大量用户的id,占内存

2.2.3、命令

PFADD key element [element ...]	#添加指定元素到HyperLogLog中

PFCOUNT key [key ...]	#返回给定HyperLogLog的基数估算值

PFMERGE destkey sourcekey [sourcekey ...]	#将多个HyperLogLog合并为一个

2.2.4、示例

127.0.0.1:6379> pfadd c1 1 2 3 4 5 6 7	#创建c1集合{1,2,3,4,5,6,7}
(integer) 1
127.0.0.1:6379> pfadd c2 6 7 8 9 10 11	#创建c2集合{6,7,8,9,10,11}
(integer) 1
127.0.0.1:6379> pfcount c1	#统计c1集合的基数数量
(integer) 7
127.0.0.1:6379> pfcount c2	#统计c2集合的基数数量
(integer) 6
127.0.0.1:6379> pfmerge c3 c1 c2	#合并c1集合和c2集合成c3
OK
127.0.0.1:6379> pfcount c3	#统计合并后c3集合的基数
(integer) 11

2.2.5、总结

  • 如果允许容错,则一定使用Hyperloglog
  • 如果不允许容错,则使用set或者自己的数据类型


2.3、bitmaps

2.3.1、简介

位存储

常用场景:两个状态的,都可以使用 Bitmaps

  • 统计用户信息:活跃,不活跃!
  • 登录、未登录!
  • 打卡,未打卡!

Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态

2.3.2、示例

使用bitmaps来记录周一到周日的打卡信息

127.0.0.1:6379> setbit week 1 1	#设置week的位置1的值为1:代表周一打卡
(integer) 0
127.0.0.1:6379> setbit week 2 0	#设置week的位置2的值为0:代表周二未打卡
(integer) 0
127.0.0.1:6379> setbit week 3 1	#设置week的位置3的值为1:代表周三打卡
(integer) 0
127.0.0.1:6379> setbit week 4 1	#设置week的位置4的值为1:代表周四打卡
(integer) 0
127.0.0.1:6379> setbit week 5 0	#设置week的位置5的值为0:代表周五未打卡
(integer) 0
127.0.0.1:6379> setbit week 6 1	#设置week的位置6的值为1:代表周六打卡
(integer) 0
127.0.0.1:6379> setbit week 7 0	#设置week的位置7的值为0:代表周日未打卡
(integer) 0

查看某天是否打卡

127.0.0.1:6379> getbit week 3	#查看周三是否打卡
(integer) 1
127.0.0.1:6379> getbit week 7	#查看周日是否打卡
(integer) 0

统计打卡的天数(就是统计1的个数)

127.0.0.1:6379> bitcount week	#统计一周的打卡天数
(integer) 4
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐