集合(Set)允许用户将多个各不相同的元素(文本或二进制数据)存储到集合中,以无序的方式存储元素。
有序集合(Sorted Set)同时具有"有序"和"集合"两种性质。每个元素由一个成员和分值组成。成员以字符串方式存储,而分值以64位双精度浮点数格式存储。
1 集合 Set
|-------|-----------------------------------------------------------------------------------------------------------------------------|
| 添加和移除 | SADD、SREM |
| 集合 | 移动一个元素到另一个集合:SMOVE 返回集合包含的所有元素:SMEMBERS 返回集合包含的元素数量:SCARD 检查元素是否存在于集合:SISMEMBER 随机获取集合中的元素:SRANDMEMBER 随机从集合中移除指定数量的元素:SPOP |
| 集合运算 | 交集:SINTER、SINTERSTORE 并集:SUNION、SUNIONSTORE 差集:SDIFF、SDIFFSTORE |
表 集合数据结构相关命令
1.1 示例
打标签:购物网站为商品添加标签,方便顾客了解商品的不同特性及筛选商品。
java
public class GoodsTags {
private final static Jedis jedis = RedisPool.getJEdis();
private final static String GOODS_TAGS_KEY = "goods_tags_set::%s";
public static void addTags(String goodsId,String ... tags) {
jedis.sadd(String.format(GOODS_TAGS_KEY,goodsId),tags);
}
public static boolean hasTag(String goodsId,String tag) {
return jedis.sismember(String.format(GOODS_TAGS_KEY,goodsId),tag);
}
public static void removeTag(String goodsId,String tag) {
jedis.srem(String.format(GOODS_TAGS_KEY,goodsId),tag);
}
public static void showTags(String goodsId) {
System.out.println(jedis.smembers(String.format(GOODS_TAGS_KEY,goodsId)));
}
public static void main(String[] args) {
addTags("1","苹果","电脑","M2","办公","程序员");
showTags("1");
System.out.println("has 办公:" + hasTag("1","办公"));
removeTag("1","办公");
System.out.println("has 办公:" + hasTag("1","办公"));
}
}
共同关注与推荐关注:在抖音上,访问某个用户的个人主页时,页面会展示出我们和这个用户都在关注的人。
除此之外,还会为用户推荐他可能感兴趣的关注对象。简单的实现算法是:从用户正在关注集合中随机选出指定数量的用户作为种子用户,然后对这些种子用户的正在关注集合执行并集计算,最后从这个并集中随机选出一些用户作为推荐关注对象。
java
public class CommonAndRecommendUser {
private final static Jedis jedis = RedisPool.getJEdis();
private final static String FOLLOWING_KEY = "user_following_set:%s";
private final static String TEMP_USER_RECOMMEND_KEY = "temp_user_recommend_set";
public static void addFollowing(String user,String ... targetUsers) {
String key = String.format(FOLLOWING_KEY, user);
jedis.spop(key,999);
jedis.sadd(key,targetUsers);
}
public static void showFollowing(String user) {
System.out.println(jedis.smembers(String.format(FOLLOWING_KEY,user)));
}
public static void showCommon(String user,String target) {
System.out.println(jedis.sinter(String.format(FOLLOWING_KEY,user),String.format(FOLLOWING_KEY,target)));
}
public static void showRecommend(String user) {
List<String> members = jedis.srandmember(String.format(FOLLOWING_KEY, user), 5);
Set<String> keys = new HashSet<>();
if (members != null && !members.isEmpty()) {
for (String it : members) keys.add(String.format(FOLLOWING_KEY,it));
jedis.sunionstore(TEMP_USER_RECOMMEND_KEY,keys.toArray(new String[1]));
jedis.sdiffstore(TEMP_USER_RECOMMEND_KEY,TEMP_USER_RECOMMEND_KEY,String.format(FOLLOWING_KEY, user));
jedis.srem(TEMP_USER_RECOMMEND_KEY,user);
System.out.println(jedis.srandmember(TEMP_USER_RECOMMEND_KEY,5));
}
}
public static void main(String[] args) {
addFollowing("黄先生","刘女士","小陈","小吴","小李","小张");
addFollowing("刘女士","黄先生","小陈","小吴");
addFollowing("小李","黄先生","小吴","小张","小孔");
addFollowing("小张","老李","老吴","黄先生");
showFollowing("黄先生");
showFollowing("刘女士");
showCommon("黄先生","刘女士");
showCommon("小李","小张");
showRecommend("黄先生");
showRecommend("刘女士");
}
}
2 有序集合Sorted Set
有序集合具有以下特点:
- 有序性:按照分数的大小进行排序。
- 唯一性:不会出现重复的元素。
- 快速查找:可以快速查找某个元素的位置、分数以及排名等信息。
- 范围操作:根据分数的范围来获取一段区间内的元素。
- 更新分数:可以对集合中的元素进行分数增减操作。
|-------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 添加和移除 | ZADD、ZREM 弹出分值最高、最低的成员:ZPOPMAX、ZPOPMIN |
| 分值 | 获取成员的分值:ZSCORE 对成员的分值执行整数运算:ZINCRBY |
| 集合 | 集合的大小:ZCARD 成员在集合中的排名:ZRANK、ZREVRANK 指定索引范围内的成员:ZRANGE、ZREVRANGE 指定分数范围内的成员:ZRANGEBYSCORE、ZREVRANGEBYSCORE(指定范围时,更大的分数在前面) 统计指定分值范围内的成员数量:ZCOUNT 移除指定排名范围内的成员:ZREMRANGEBYRANK 移除指定分值范围内的成员:ZREMRANGEBYSCORE |
| 集合运算 | 并集:ZUNIONSTORE 交集:ZINTERSTORE |
| 字典 | 指定字典序列范围内的成员:ZRANGEBYLEX、ZREVRANGEBYLEX 统计字典序列指定范围内的成员数量:ZLENCOUNT 移除位于字典序列指定范围内的成员:ZREMRANGEBYLEX |
| 阻塞 | BZPOPMAX、BZPOPMIN |
表 有序集合相关命令
2.1 示例
自动补全:在搜索框输入某些文字的时候,系统的自动补全特性就会列出一些比较著名的以这些文字开头的选项。
java
public class AutoComplete {
private final static Jedis jedis = RedisPool.getJEdis();
private final static String COMPLETE_KEY = "auto_complete_sorted_set::%s";
public static void feed(String str) {
if (str != null) {
for (int i = 1; i < str.length() + 1; i++) {
String key = String.format(COMPLETE_KEY,str.substring(0,i));
System.out.println("key:" + key);
jedis.zincrby(key,1,str);
}
}
}
public static void hint(String str) {
if (str != null) {
String key = String.format(COMPLETE_KEY,str);
Set<String> set = jedis.zrange(key, 0, -1);
System.out.println(set);
}
}
public static void main(String[] args) {
feed("黄子韬");
feed("黄晓明");
feed("黄渤");
feed("黄金海岸");
feed("黄嘉千");
feed("黄金价格");
feed("黄历");
feed("黄石公园");
feed("黄家驹");
feed("黄雷");
hint("黄");
hint("黄金");
}
}