【快速了解redis】五种数据类型-Set篇

前记

最近因为要部署一套供演示的集群环境,断更了一段时间。重新续上。

在redis官网上找到了个在线熟悉redis指令的网站,给个链接点击

所有文章里提到的指令,均可以直接在上面练手了。挺方便的
redis try

Set数据类型

今天讲的set,意为集合,它和另一种数据类型sorted set 的区别,在于它是无序的。他可以允许用户将多个不同的元素,存储到set集合的健值中,这些数据既可以是二进制的,也可以是文本数据。、

另一方面,他也有点类似我们之前说的Lists数据类型,可以一个健存储多个元素,但区别在于: set集合的元素是唯一的,不重复的,而lists列表的元素是允许重复的。

所以,当我们用redis进行数据存储的时候,如果你再纠结用set还是lists来保存数据的时候,考虑下你所需要保存的数据,允不允许出现重复的情况。

如果允许,比如,记录一天的作息安排,那么一天的时间里,可以你上午会有个会,中午午休,下午有个会议,这种可以用lists来保存,如[“开会”,“午休”,“开会”]等。但如果我们要记录一篇文章,有哪些小伙伴点了赞,这个时候,一个用户是只能点一个赞的,拿就要用到集合了,它会忽略掉已经存在的元素。

set在数据存储上有两种编码方式;intset编码和hashtable编码方式,如果我们用set存储的是数字,那么数字存储的结构是一个从小到大的整数集合,如果存储的是字符串,那么存储的结构是一个字典对象,字典的键值为我们所要保存的值,字典的值为null。
set 的数据结构粗略图

这里有个注意的点,我们说set是个无序的集合,但前面讲到,如果保存的值是个数字,它会从小到大排列,这无序体现在哪里呢? 其实这里的无序指的是数据存储的顺序和你录入数据的顺序无关,而不是指数值大小。

常用方法

接下来,我们来敲下指令,熟悉下set的指令

SADD

SADD 将元素添加到集合

1
2
3
4
5
6
# 添加一个元素
127.0.0.1:6379> SADD fruit Apple
(integer) 1
# 添加两个元素
127.0.0.1:6379> SADD fruit Banana Orange
(integer) 2

这里我们可以看到,SADD 指令成功后,会返回当前设置成功的元素数目

SADD 会忽略已存在的元素,比如我们重新设置Apple

1
2
127.0.0.1:6379> SADD fruit Apple
(integer) 0

可见,设置返回了0,说明当前fruit这个集合中,并没有元素的变化

SREM

SRMEset remove 的缩写,意为“从集合中移除元素”。

1
2
3
4
127.0.0.1:6379> SREM fruit Apple
(integer) 1
127.0.0.1:6379> SREM Banana Orange
(integer) 2

这里指令成功后,返回了被移除的元素数量,它也支持同时移除多个元素。(redis只有版本2.4以上的才允许一次删除多个值,这需要确认你安装的redis版本)

SREM 会忽略不存在的元素,比如我们再次删除Apple

1
2
127.0.0.1:6379> SREM fruit Apple
(integer) 0

可以看到,返回了0,代表当前没有元素被移除。

SMOVE

SMOVE 是“set move”的缩写 ,其含义就是“将元素移动到另一个集合”,例如: 水果“fruit”里有个西红柿“tomato”,我们把西红柿移动到蔬菜“vegetables”这个集合中

1
2
3
# SMOVE source target element
127.0.0.1:6379> SMOVE fruit vegetables Tomato
(integer) 0

由此可见,SMOVE 返回值是指令成功的元素数量,0代表没有元素发生转移,这里是因为之前我们没有将Tomato加入到fruit,可以先用SADD加入之后再执行上面的指令

SMEMBERS

SMEMBERS, 是“set members”,意思是,set集合的成员,用于查询集合的元素,我们查看一下“fruit”这个集合有哪些水果

1
2
3
4
127.0.0.1:6379> SMEMBERS fruit
1) "Apple"
2) "Orange"
3) "Banana"

此前录入的水果都查出来了

SISMEMBER

SISMEMBER ,是“set is member”?的意思,用于查询元素是否存在于集合之中。,例如我们查下水果里是否还存在Tomato.

1
2
3
4
127.0.0.1:6379> SISMEMBER fruit Tomato
(integer) 0
127.0.0.1:6379> SISMEMBER vegetables Tomato
(integer) 1

由上面的指令可以看出,Tomato已经不存在于fruit了,而是存在于vegetables这个集合中了

SCARD

最后,我们还学一个指令,SCARD, 用于统计集合的元素的数量,如

1
2
127.0.0.1:6379>  SCARD fruit
(integer) 3

由此可知,fruit有三个元素

举个栗子

我们就拿博客文章的点赞模块的实现来举例子。

需求是:
1.每篇文章都有一个点赞的模块,记录点赞情况

  1. 用户点击一次,如果已点赞则取消点赞,如果未点赞,则点赞成功
  2. 查看文章的点赞数
  3. 查看文章的点赞用户列表

我用nodejs实现了这个点赞类。大家可以用其他的语言实现一次。

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* @author lamwimham
* @date 2021-04-28
*/
const redis = require('redis');
//TODO: 1. 连接redis服务器

class LikeModule {

/**
*
* @param key 集合键,也可以用文章的id作为键等
*/
constructor(key) {
this.key = key
}
/**
* @description 点击,如果没点赞,则记录点赞者的唯一标识,如果已点赞,则取消点赞
* @param {String} uid 点击者的用户id
* @returns {Number} 返回操作成功与否,0-失败,1-成功
*/
click(uid) {
let code = redis.SISMEMBER(this.key, uid); // 判断uid是否应点赞
if (code) {
return redis.SREM(this.key, uid);
} else {
return redis.SADD(this.key, uid);
}
}

/**
* 获取点赞的用户列表
* @returns {String[]} 用户列表
*/
getLikedList() {
return redis.SMEMBERS(this.key)
}

/**
* 获取点赞的数量
* @returns {Number}
*/
getLikeListCount() {
return redis.SCARD(this.key)
}
}


// 实例

// 创建文章id为1223921的点赞实例
const likeInstance = new LikeModule('passage:1223921');
// 用户id为user18849494992的用户给文章点了一个赞
likeInstance.click('user18849494992');
// 用户id为user18849494444的用户给文章点了一个赞
likeInstance.click('user18849494444');
// 用户id为user18849494333的用户给文章点了一个赞
likeInstance.click('user18849494333');
// 获取文章的点赞数
const num = likeInstance.getLikeListCount();
// 获取文章的点赞用户列表
const userList = likeInstance.getLikedList()

课后作业

今天的课后作业,就是大家可以用python做一次点赞的实现。