跳转到内容

Redis Set 类型


Set 是 Redis 中无序、不重复的字符串集合,自动对插入的重复元素去重,并支持集合间的交集、并集、差集运算。

Set 结构示意:
key = "user:1001:follow" key = "user:1002:follow"
┌─────────────────────┐ ┌─────────────────────┐
│ Alice Bob Carol │ SINTER │ Bob Carol Dave │
│ Dave Eve │ ────────▶ │ │
└─────────────────────┘ └─────────────────────┘
结果:{Bob, Carol}(共同关注)
特点说明
不重复自动去重,插入重复元素会被忽略
无序元素没有固定顺序,不支持按索引访问
集合运算原生支持交集、并集、差集
随机访问SRANDMEMBER 随机取元素,适合抽奖
上限单个 Set 最多 2^32 - 1 个元素
Terminal window
# 添加
SADD tags "Java" "Redis" "Spring" # 添加元素,返回成功添加的数量
SADD tags "Java" # 重复元素,返回 0(自动忽略)
# 删除
SREM tags "Spring" # 删除指定元素
# 查询
SMEMBERS tags # 获取所有元素(无序)
SCARD tags # 获取元素数量
SISMEMBER tags "Redis" # 判断元素是否存在 → 1/0
SMISMEMBER tags "Java" "Python" # 批量判断(Redis 6.2+)→ [1, 0]
# 随机操作
SRANDMEMBER tags # 随机返回 1 个元素(不删除)
SRANDMEMBER tags 3 # 随机返回 3 个不重复元素
SPOP tags # 随机弹出 1 个元素(删除)
SPOP tags 2 # 随机弹出 2 个元素
Terminal window
SADD set1 a b c d
SADD set2 c d e f
SINTER set1 set2 # 交集 → {c, d}
SUNION set1 set2 # 并集 → {a, b, c, d, e, f}
SDIFF set1 set2 # 差集(set1 中有但 set2 中没有)→ {a, b}
# 将运算结果存入新 key(不直接返回)
SINTERSTORE result set1 set2 # 交集存入 result
SUNIONSTORE result set1 set2 # 并集存入 result
SDIFFSTORE result set1 set2 # 差集存入 result
命令说明复杂度
SADD key v1 v2添加元素O(N)
SREM key v1删除元素O(N)
SMEMBERS key获取全部元素O(N)
SCARD key元素数量O(1)
SISMEMBER key v判断是否存在O(1)
SRANDMEMBER key n随机获取 n 个O(N)
SPOP key n随机弹出 n 个O(N)
SINTER / SUNION / SDIFF集合运算O(N*M)
Set 底层编码
├── listpack(紧凑列表)
│ → 元素数 ≤ 128 且每个元素为整数或长度 ≤ 64 字节
│ → Redis 7.2+ 引入,替代旧版 intset/ziplist
├── intset(整数集合)
│ → 所有元素均为整数且数量 ≤ 512
│ → 内存极为紧凑,查找使用二分搜索
└── hashtable(哈希表)
→ 超过阈值后自动升级
→ 查找 O(1)
@Autowired
private StringRedisTemplate redisTemplate;
SetOperations<String, String> setOps = redisTemplate.opsForSet();
// 添加
setOps.add("user:1001:tags", "Java", "Redis", "Spring");
// 查询
Set<String> tags = setOps.members("user:1001:tags");
Long size = setOps.size("user:1001:tags");
Boolean exists = setOps.isMember("user:1001:tags", "Redis");
// 删除
setOps.remove("user:1001:tags", "Spring");
// 随机取元素
String one = setOps.randomMember("user:1001:tags");
List<String> three = setOps.randomMembers("user:1001:tags", 3);
// 集合运算
Set<String> inter = setOps.intersect("user:1001:follow", "user:1002:follow");
Set<String> union = setOps.union("user:1001:follow", "user:1002:follow");
Set<String> diff = setOps.difference("user:1001:follow", "user:1002:follow");
@Service
@RequiredArgsConstructor
public class FollowService {
private final StringRedisTemplate redisTemplate;
private String followKey(Long userId) {
return "user:follow:" + userId;
}
// 关注
public void follow(Long userId, Long targetId) {
redisTemplate.opsForSet().add(followKey(userId), String.valueOf(targetId));
}
// 取关
public void unfollow(Long userId, Long targetId) {
redisTemplate.opsForSet().remove(followKey(userId), String.valueOf(targetId));
}
// 是否已关注
public boolean isFollowing(Long userId, Long targetId) {
return Boolean.TRUE.equals(
redisTemplate.opsForSet().isMember(followKey(userId), String.valueOf(targetId))
);
}
// 共同关注(两人都关注的人)
public Set<String> commonFollow(Long userId1, Long userId2) {
return redisTemplate.opsForSet().intersect(followKey(userId1), followKey(userId2));
}
// 可能认识的人(对方关注但我没关注)
public Set<String> recommendFollow(Long userId, Long targetId) {
return redisTemplate.opsForSet().difference(followKey(targetId), followKey(userId));
}
}
@Service
@RequiredArgsConstructor
public class LotteryService {
private final StringRedisTemplate redisTemplate;
// 参与抽奖
public void join(String activityId, Long userId) {
redisTemplate.opsForSet().add("lottery:" + activityId, String.valueOf(userId));
}
// 不重复抽奖(中奖者不再参与)
public List<String> draw(String activityId, int count) {
// SPOP:弹出并从集合中删除,保证同一用户不会重复中奖
List<String> winners = new ArrayList<>();
for (int i = 0; i < count; i++) {
String winner = redisTemplate.opsForSet().pop("lottery:" + activityId);
if (winner != null) winners.add(winner);
}
return winners;
}
// 可重复抽奖(大奖可重复参与)
public List<String> drawRepeat(String activityId, int count) {
// SRANDMEMBER:随机取元素但不删除
return redisTemplate.opsForSet().randomMembers("lottery:" + activityId, count);
}
}
场景实现方式关键命令
用户标签每个用户一个 Set 存标签SADD / SMEMBERS
共同好友两个用户关注列表取交集SINTER
好友推荐对方关注列表与我的关注列表取差集SDIFF
UV 统计去重用户 ID 加入 Set,SCARD 统计SADD / SCARD
抽奖参与者加入 Set,SPOP 随机弹出SPOP
黑名单/白名单SADD 维护名单,SISMEMBER 验证SISMEMBER