Redis 4.x系列(七):Redis 数据特性之位图、过期、排序

  Bitmap:Redis 中的位图并不是一种新的数据类型,它的底层数据类型是字符串。字符串的本质是二进制大对象(BLOB:Binary Large Object),所以可以视作位图。

  Expire:可以通过设置的过期时间,让 Redis 自动地删除键。

  Sort:可以对列表以某种非权重顺序对有序集合的元素进行排序。

Bitmap(位图)

位图:也称为位数组或位向量,是在 String 类型上定义的一组面向位(bit)的操作,是由比特位(bit)组成的数组。Redis 中的位图并不是一种新的数据类型。

Redis 中的字符串本质是二进制大对象 BLOB(Binary Large Object),是二进制安全的,最大长度为 512 MB,因此可以设置 2 的 32 次方个不同的位,所以可以将期视作位图。

因为位图存储的是布尔信息,在存储数据时通常可以节省大量的内存空间,这是其最大的优势之一。位的操作有两种,一定时间内的单个位操作,如将位设置为 1 或 0,或获取位的值;以及对某一组位进行操作,如计算给定位范围内的设位数(例:人口统计)

  1. 常用命令
    • setbit:设置位图指定偏移处比特位的值。
    • getbit:从位图中获取位于指定偏移处比特位的值。
    • bitcount:获取位图中设置为 1 的比特数。
    • bitop:用于进行位操作,该命令支持四种位操作:and, or, xor 和 not,位运算的结果会被存储在一个目标键中。
  2. 位图在节省存储空间方面具有优势,特别是统计大量数据时体现特别明显。

setbit

设置位图指定偏移处比特位的值

语法:setbit key offset value
示例:记录水果被那些用户买过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 买过 apple 的用户
127.0.0.1:6379> setbit "fruit:apple" 10001 1
(integer) 0
127.0.0.1:6379> setbit "fruit:apple" 10002 1
(integer) 0
127.0.0.1:6379> setbit "fruit:apple" 10003 1
(integer) 0
127.0.0.1:6379> setbit "fruit:apple" 10004 1
(integer) 0

# 买过 banana 的用户
127.0.0.1:6379> setbit "fruit:banana" 10003 1
(integer) 0
127.0.0.1:6379> setbit "fruit:banana" 10004 1
(integer) 0
127.0.0.1:6379> setbit "fruit:banana" 10005 1
(integer) 0
127.0.0.1:6379> setbit "fruit:banana" 10006 1
(integer) 0
127.0.0.1:6379> setbit "fruit:banana" 10007 1
(integer) 0

getbit

从位图中获取位于指定偏移处比特位的值

语法:getbit key offset
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 该用户是否买过 apple
127.0.0.1:6379> getbit "fruit:apple" 10003
(integer) 1
127.0.0.1:6379> getbit "fruit:apple" 10005
(integer) 0
127.0.0.1:6379> getbit "fruit:banana" 10003
(integer) 1

# 该用户是否买过 banana
127.0.0.1:6379> getbit "fruit:banana" 10006
(integer) 1
127.0.0.1:6379> getbit "fruit:banana" 10007
(integer) 1
127.0.0.1:6379> getbit "fruit:banana" 10008
(integer) 0

bitop

用于进行位操作,该命令支持四种位操作:and, or, xor 和 not,位运算的结果会被存储在一个目标键中

语法:bitop operation destkey key [key ...]
示例:

1
2
3
4
5
6
7
# 位操作, 合并都购买过两种水果的用户
127.0.0.1:6379> bitop and "fruit_all" "fruit:apple" "fruit:banana"
(integer) 1251

# 统计都购买过两种水的用户
127.0.0.1:6379> bitcount "fruit_all"
(integer) 2

bitcount

获取位图中设置为 1 的比特数

语法:bitcount key [start end]
示例:

1
2
3
4
5
6
7
8
# 统计都购买过两种水的用户
127.0.0.1:6379> bitcount "fruit_all"
(integer) 2
# 统计分别购买两种水果的用户
127.0.0.1:6379> bitcount "fruit:apple"
(integer) 4
127.0.0.1:6379> bitcount "fruit:banana"
(integer) 5

Expire(过期)

Redis 中删除键可以使用DELUNLINK命令来主动删除,还可以通过设置键的过期时间让 Redis 自动删除键。

  1. 常用命令
    • EXPIRE:设置过期时间,单位秒。
    • TTL:查看剩余时间。
    • EXISTS:判断键是否存在。
  2. 键的过期时间会被存储为一个绝对的 UNIX 时间戳,即使服务器宕机一段时间,时间戳也会被持久化到 RDB 文件中。当 Redis 再次启动时会,这个用于判断键是否过期的时间戳并不会发生变化,一旦当前时间超过了这个时间戳时,键就过期了。
    当客户端访问已过期键时,Redis 会立即从内存中删除该键。对于那些已经过期且永久不会再被访问的键,Redis 会定期地运行一个基于概率的算法来进行主动删除。更具体地说,Redis 会随机选择设置了过期时间的 20 个键。在这 20 个被选中的键中,已过期的键会被立即删除;如果选中的键中有超过 25% 的键已经过期且被删除,那么 Redis 会再次随机选择 20 个键并重复这个过程。默认情况下,上述过程每秒运行10次(可通过配置文件中 hz 的值进行设置)。
  3. 清除键的过期时间
    • 使用PERSIST命令使期成为持久键。
    • 被另一个没有过期时间的键重命名。如果键存在但未设置过期时间,则TTL命令返回-1,如果键不存在,则返回-2
    • 键的值被替换或删除。包括SET, GETSET*STORE在内的命令会清除过期时间。修改列表、集合或哈希的元素则不会清除过期时间,因为修改元素的操作不会替换键所关联的对象。
  4. EXPIREAT命令与EXPIRE命令相似,但它可以指定一个绝对UNIX时间戳为参数做为指定键的过期时间。
  5. 可以使用PEXIREPEXIREAT命令以毫秒级的精度指定键的过期时间。
  6. Redis 对已过期的键的主动删除除不过预测,可能存在已过期的键永远不会被删除的情况。当发现太多已过期的键未被删除时,可以通过执行SCAN命令来更加主动地触发被动过期。

EXPIRE

设置过期时间,单位秒

语法:expire key seconds
示例:

1
2
3
4
5
6
7
8
127.0.0.1:6379> lpush session_list userid_10001 userid_10002 userid_10003
(integer) 3
127.0.0.1:6379> ttl session_list
(integer) -1
127.0.0.1:6379> exists session_list
(integer) 1
127.0.0.1:6379> expire session_list 20
(integer) 1

TTL

查看剩余时间

语法:ttl key
示例:

1
2
3
4
5
6
7
8
127.0.0.1:6379> ttl session_list
(integer) 17
127.0.0.1:6379> ttl session_list
(integer) 14
127.0.0.1:6379> exists session_list
(integer) 1
127.0.0.1:6379> exists session_list
(integer) 0

Sort(排序)

Redis 的有序集合是根据元素的权重进行排序,实际使用中有时需要获取一个 列表或集合的已排序副本,或者以某种非权重顺序对有序集合中的元素进行排序。Redis 为这些需求提供了一个方便的命令 SORT

  1. 常用命令
    • SORT:直接使用可对元素都是数值排序,默认是升序(ASC)排序, 若要按降序排序可添加修改饰符DESC
    • SORT…ALPHA:对非数值的元素且想按字典排序的,需增加修饰符ALPHA
    • SORT…LIMIT:默认情况下,SORT 排序默认返回所有元素,可使用LIMIT修饰符来限制返回元素的数量。
    • SORT…GET:Get 选项可被多次使用, Get # 表示获取元素本身。
    • SORT…STORE:把排序结果当做列表保存到指定的键中。

数值排序

默认升级,降序添加修饰符DESC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> lpush fruit 200 365 104 455 333
(integer) 5
127.0.0.1:6379> sort fruit
1) "104"
2) "200"
3) "333"
4) "365"
5) "455"

127.0.0.1:6379> sort fruit desc
1) "455"
2) "365"
3) "333"
4) "200"
5) "104"

非数值排序

非数值元素需要按字典排序,添加修饰符ALPHA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> lpush restaurants "KFC" "Wendy's" "MacDoload" "Dunkin" "Subway"
(integer) 5
127.0.0.1:6379> sort restaurants alpha
1) "Dunkin"
2) "KFC"
3) "MacDoload"
4) "Subway"
5) "Wendy's"
127.0.0.1:6379> sort restaurants alpha desc
1) "Wendy's"
2) "Subway"
3) "MacDoload"
4) "KFC"
5) "Dunkin"

LIMIT限制返回元素

默认情况下,SORT 排序默认返回所有元素,可使用LIMIT修饰符来限制返回元素的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> lrange fruit 0 -1
1) "333"
2) "455"
3) "104"
4) "365"
5) "200"
127.0.0.1:6379> sort fruit limit 0 3
1) "104"
2) "200"
3) "333"
127.0.0.1:6379> sort fruit limit 0 3 desc
1) "455"
2) "365"
3) "333"

按其它键的权重排序

Redis 还支持按在某些其他键中定义的权重来对元素进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
-- 用户喜爱的餐厅列表
127.0.0.1:6379> lpush "user:123:favorite_restaurant_ids" 200 365 104 455 333
(integer) 5

-- 餐厅的评分
127.0.0.1:6379> set "restaurant_rating_200" 4.3
127.0.0.1:6379> set "restaurant_rating_365" 4.0
127.0.0.1:6379> set "restaurant_rating_104" 4.8
127.0.0.1:6379> set "restaurant_rating_455" 4.7
127.0.0.1:6379> set "restaurant_rating_333" 4.6

-- 对用户喜爱的餐厅根据评分排序
127.0.0.1:6379> sort "user:123:favorite_restaurant_ids" by restaurant_rating_* desc
1) "104"
2) "455"
3) "333"
4) "200"
5) "365"
127.0.0.1:6379> sort "user:123:favorite_restaurant_ids" by restaurant_rating_*
1) "365"
2) "200"
3) "333"
4) "455"
5) "104"

-- 餐厅名称
127.0.0.1:6379> set "restaurant_name_200" "Ruby Tuesday"
127.0.0.1:6379> set "restaurant_name_365" "TGI Friday"
127.0.0.1:6379> set "restaurant_name_104" "Applebee's"
127.0.0.1:6379> set "restaurant_name_455" "Red Lobster"
127.0.0.1:6379> set "restaurant_name_333" "Boiling Crab"

-- 根据餐厅评分获取餐厅名称
127.0.0.1:6379> sort "user:123:favorite_restaurant_ids" by restaurant_rating_* desc get restaurant_name_*
1) "Applebee's"
2) "Red Lobster"
3) "Boiling Crab"
4) "Ruby Tuesday"
5) "TGI Friday"

STORE保存到新的键

把排序结果当做列表保存到指定的键中

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> sort "user:123:favorite_restaurant_ids" by restaurant_rating_* desc get restaurant_name_* store sort_by_rating
(integer) 5

127.0.0.1:6379> lrange sort_by_rating 0 -1
1) "Applebee's"
2) "Red Lobster"
3) "Boiling Crab"
4) "Ruby Tuesday"
5) "TGI Friday"

Redis 4.x系列(七):Redis 数据特性之位图、过期、排序

http://blog.gxitsky.com/2018/10/06/Redis-7-data-feature-bitmap-expire-sort/

作者

光星

发布于

2018-10-06

更新于

2022-08-14

许可协议

评论