Redis从基础命令到实战之有序集合类型(SortedSet)
有序集合类型是Redis五种数据类型中最高级的、也是最复杂的类型。有序集合具有集合类型的特性,在其基础上给每个元素关联了一个分值,或称为权重,操作时既可以在添加元素时指定分值,也可以单独修改集合中某一个元素的分值。使用时可以按分值排序(从低到高或从高到低)并顺序读取全部或某一范围内的元素,或者获得某一分值范围内的元素。利用这一特点,可以很方便的实现排行榜、热门文章等功能。
在本节的实例中,使用有序集合类型为商品管理模块添加一个按浏览量排序的功能。
一、常用命令
import java.util.Set; import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple; public class SortedSetExample { public static void main(String[] args) {
Jedis jedis = JedisProvider.getJedis();
jedis.flushDB(); // 向有序集合中加入元素, 成功返回1, 失败返回0
Long zadd = jedis.zadd("fruit", 5.0, "apple");
print("zadd fruit apple=" + zadd);
// 重复添加, 会修改权重
zadd = jedis.zadd("fruit", 6.0, "apple");
print("zadd fruit apple again=" + zadd); jedis.zadd("fruit", 2.0, "banana");
jedis.zadd("fruit", 4.0, "orange");
jedis.zadd("fruit", 8.0, "grape");
jedis.zadd("fruit", 10.0, "lemon");
jedis.zadd("fruit", 7.0, "cherry"); // 统计元素个数
print("zcard fruit=" + jedis.zcard("fruit")); // 统计某个权重范围内元素个数
print("zcount fruit [1.0,5.0]=" + jedis.zcount("fruit", 1.0, 5.0)); // 查看排名
print("zrank fruit grape=" + jedis.zrank("fruit", "grape"));
print("zrevrank fruit grape=" + jedis.zrevrank("fruit", "grape")); // 按权重排序后读取索引范围内元素及权重
System.out.println("zrangeWithScores fruit");
Set<Tuple> tuples = jedis.zrangeWithScores("fruit", 0, -1);
for (Tuple t : tuples) {
System.out.println(t.getElement() + ":" + t.getScore());
}
System.out.println("------------------------------------------------------");
System.out.println(); // 按权重反向排序后读取索引范围内元素及权重
System.out.println("zrevrangeWithScores fruit");
tuples = jedis.zrevrangeWithScores("fruit", 0, -1);
for (Tuple t : tuples) {
System.out.println(t.getElement() + ":" + t.getScore());
}
System.out.println("------------------------------------------------------");
System.out.println(); // 按权重排序后读取索引范围内元素
Set<String> set = jedis.zrange("fruit", 1, 3);
print("zrange fruit [1,3]=" + set); // 按权重反向排序后读取索引范围内元素
set = jedis.zrevrange("fruit", 1, 3);
print("zrevrange fruit [1,3]=" + set); // 读取权重在指定范围内的元素及其权重并按权重排序
System.out.println("zrangeByScoreWithScores fruit [1.0,8.0]");
tuples = jedis.zrangeByScoreWithScores("fruit", 1.0, 8.0);
for (Tuple t : tuples) {
System.out.println(t.getElement() + ":" + t.getScore());
}
System.out.println("------------------------------------------------------");
System.out.println(); // 读取权重在指定范围内的元素及其权重并按权重反向排序
System.out.println("zrevrangeByScoreWithScores fruit [8.0,1.0]");
tuples = jedis.zrevrangeByScoreWithScores("fruit", 8.0, 1.0);
for (Tuple t : tuples) {
System.out.println(t.getElement() + ":" + t.getScore());
}
System.out.println("------------------------------------------------------");
System.out.println(); // 读取权重在指定范围内的元素并按权重排序
set = jedis.zrangeByScore("fruit", 1.0, 7.0);
print("zrangeByScore fruit [1.0,7.0]=" + set); // 读取权重在指定范围内的元素并按权重反向排序
set = jedis.zrevrangeByScore("fruit", 7.0, 1.0);
print("zrevrangeByScore fruit [7.0,1.0]=" + set); // 查看集合中指定元素的权重
double zscore = jedis.zscore("fruit", "grape");
print("zscore fruit grape=" + zscore); // 修改指定元素权重
print("zincrby fruit -2 grape=" + jedis.zincrby("fruit", -2, "grape"));
print("zincrby fruit 5.0 lemon=" + jedis.zincrby("fruit", 5.0, "lemon"));
print("after zincrby: zscore fruit grape=" + jedis.zscore("fruit", "grape")); // 删除元素
print("zrem fruit cherry=" + jedis.zrem("fruit", "cherry"));
print("zremrangeByScore fruit [3.0,6.0]=" + jedis.zremrangeByScore("fruit", 3.0, 6.0)); jedis.close();
} private static void print(String info) {
System.out.println(info);
System.out.println("------------------------------------------------------");
System.out.println();
}
}
二、实践练习
在上一节的基础上,给每个商品增加一个浏览量的记录,商品每次被浏览,设置浏览量加1。
首先修改添加商品的代码,设置商品的初始浏览量为0。
/**
* 添加一个商品
* @param goods
* @return
*/
public boolean addGoods(Goods goods) {
long id = getIncrementId();
Map<String, String> map = new HashMap<>();
map.put("id", String.valueOf(id));
map.put("title", goods.getTitle());
map.put("price", String.valueOf(goods.getPrice())); //随机获得三个分类
String size = SIZE[new Random().nextInt(SIZE.length)];
String color = COLOR[new Random().nextInt(COLOR.length)]; String key = "goods:" + id;
boolean added = jedis.hmset(key, map).equals("OK");
if(added) {
jedis.rpush("goods:list", String.valueOf(id));
//初始浏览量默认为0
jedis.zadd("goods:views", 0, String.valueOf(id));
//记录商品所属分类
jedis.sadd("goods:" + id + ":tags", size, color);
//记录每个分类下包含的商品ID
jedis.sadd("tag:" + size + ":goods", String.valueOf(id));
jedis.sadd("tag:" + color + ":goods", String.valueOf(id));
}
return added;
}
用户浏览商品方法,浏览量加1。
/**
* 浏览商品
* @param id
*/
public void view(long id) {
jedis.zincrby("goods:views", 1, String.valueOf(id));
}
按浏览量排序
/**
* 读取商品列表并按浏览量排序
* @param pageIndex
* @param pageSize
* @return
*/
public List<Goods> getGoodsListOrderByViews(int pageIndex, int pageSize) {
int totals = (int)getTotalCount();
int from = (pageIndex - 1) * pageSize;
if(from < 0) {
from = 0;
}
else if(from > totals) {
from = (totals / pageSize) * pageSize;
}
int to = from + pageSize - 1;
if(to > totals) {
to = totals;
}
List<Goods> goodsList = new ArrayList<>();
Set<String> idList = jedis.zrevrange("goods:views", from, to);
for(String id : idList) {
String key = "goods:" + id;
Map<String, String> maps = jedis.hgetAll(key);
Goods goods = new Goods();
goods.setId(NumberUtils.toLong(maps.get("id")));
goods.setTitle(maps.get("title"));
goods.setPrice(NumberUtils.toFloat(maps.get("price")));
//读取分类
goods.setTags(jedis.smembers("goods:" + id + ":tags"));
goodsList.add(goods);
}
return goodsList;
}
测试代码
public static void main(String[] args) {
SortedSetLession sl = new SortedSetLession();
sl.clear();
//添加一批商品
for(int i = 0; i< 42; i++) {
Goods goods = new Goods(0, "goods" + String.format("%05d", (i + 1)), i);
sl.addGoods(goods);
}
//读取商品总数
System.out.println("商品总数: " + sl.getTotalCount());
//删除第29件商品
sl.delGoods(29);
System.out.println("删除后商品总数: " + sl.getTotalCount());
//分页显示
List<Goods> list = sl.getGoodsList(2, 20);
System.out.println("第二页商品:");
for(Goods goods : list) {
System.out.println(goods);
}
//按分类查找
List<Goods> listByTag = sl.findGoodsByTag("big", "green");
System.out.println("所有尺寸为big,颜色为green的商品:");
for(Goods goods : listByTag) {
System.out.println(goods);
}
//模拟点击商品
sl.view(3);
sl.view(3);
sl.view(4);
//按点击量排序
List<Goods> listWithOrder = sl.getGoodsListOrderByViews(1, 20);
System.out.println("按点击量排序:");
for(Goods goods : listWithOrder) {
System.out.println(goods);
}
}
Redis从基础命令到实战之有序集合类型(SortedSet)的更多相关文章
- Redis从基础命令到实战之散列类型(Hash)
从上一篇的实例中可以看出,用字符串类型存储对象有一些不足,在存储/读取时需要进行序列化/反序列化,即时只想修改一项内容,如价格,也必须修改整个键值.不仅增大开发的复杂度,也增加了不必要的性能开销. 一 ...
- Redis常用命令入门5:有序集合类型
有序集合类型 上节我们一起学习了集合类型,感受到了redis的强大.现在我们接着学Redis的最后一个类型——有序集合类型. 有序集合类型,大家从名字上应该就可以知道,实际上就是在集合类型上加了个有序 ...
- Redis从基础命令到实战之列表类型(List)
经过上一篇基于Redis散列类型的改造后,实战练习中的商品管理已经具备了增加.修改整体.修改部分属性和分页查询功能,但仍然不支持删除商品的功能.这是因为商品总数是以一个自增数字记录的,且关联了新商品k ...
- Redis从基础命令到实战之集合类型(Set)
Redis集合类型的基础功能也是存储字符串列表,和列表类型的区别是字符串不能重复且没有顺序.当然,存储元素唯一性也可以通过应用程序保证,单从这一点上并没有体现出对比列表类型的特点. 其实,集合类型的一 ...
- Redis从基础命令到实战之字符串类型
字符串类型是Redis中最基本的数据类型,能存储任何形式的字符串和和二进制数据.本文以代码形式列举常用的操作命令,并在实践部分演示一个简单的商品管理功能,实现了通常使用关系型数据库开发的增改查功能,注 ...
- Redis 常用命令学四:有序集合类型命令
1.增加元素,修改存在元素的分数 127.0.0.1:6379> zadd score 99 a 88 b 66 c (integer) 3 127.0.0.1:6379> ZADD sc ...
- redis的基础命令操作
文章目录 前言 一.字符串类型 二.哈希类型 三.列表类型 四.集合类型 五.有序集合类型 六.通过命令 前言 redis的数据结构 redis存储的是key,value格式的数据,其中的key是字符 ...
- Redis自学笔记:3.6入门-有序集合类型
3.6有序集合类型 3.6.1介绍 在集合类型基础上,为集合中每个元素都关联了一个分数,故可以获得 分数最高(最低)的前N个元素,可以获得指定范围内的元素等 有序集合中每个元素不同,但它们的分数却可以 ...
- 第二百九十九节,python操作redis缓存-SortSet有序集合类型,可以理解为有序列表
python操作redis缓存-SortSet有序集合类型,可以理解为有序列表 有序集合,在集合的基础上,为每元素排序:元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值, ...
随机推荐
- NVMe over Fabrics:概念、应用和实现
对于大部分人来说,NVMe over Fabrics(简称NVMf)还是个新东西,因为其第一个正式版本的协议在今年6月份才发布.但是这并不影响人们对NVMf的关注,因为这项依托于NVMe的技术很可能继 ...
- php 获取远程图片保存到本地
php 获取远程图片保存到本地 使用两个函数 1.获取远程文件 2.把图片保存到本地 /** * 获取远程图片并把它保存到本地 * $url 是远程图片的完整URL地址,不能为空. */ functi ...
- TensorFlow中max pooling层各参数的意义
官方教程中没有解释pooling层各参数的意义,找了很久终于找到,在tensorflow/python/ops/gen_nn_ops.py中有写: def _max_pool(input, ksize ...
- [ActionScript 3.0] 通过内联函数对addFrameScript方法传递参数
虽然说不推荐使用影片剪辑隐藏方法addFrameScript();但是解决某些问题,此方法的确会方便很多. 但是却不能直接传递参数,不过可以用迂回的方法,如下: mc.addFrameScript(m ...
- Vs2015智能提示英文?
Vs2015智能提示英文? 装了vs2015代码的智能提示全部变成英文了 找到这个目录 C:\Program Files (x86)\Reference Assemblies\Microsoft\ ...
- 三维空间旋转和Three.JS中的实现
三维空间中主要有两种几何变换,一种是位置的变换,位置变换和二维空间的是一样的.假设一点P(X1,Y1,Z1) 移动到Q(X2,Y2,Z2)只要简单的让P点的坐标值加上偏移值就可以了.但是三维空间的旋转 ...
- 从高处理解android与服务器交互(看懂了做开发就会非常的容易)
今天帮一个朋友改一个bug 他可以算是初学者吧 .我给他看了看代码,从代码和跟他聊天能明显的发现他对客户端与服务器交互 基本 不是很了解.所以我花了更多时间去给他讲客户端与服务器的关系.我觉得从这个高 ...
- 学习游戏渲染(Shader)的用处
本文在讨论的主题并不限于具体引擎或具体语言,为了说明方便可能会提到Unity的一些内容. 最近渐渐发现很多从事游戏开发的新人,对于学会写Shader似乎总是有几分神往,但一般入了门或者学了一段时间后 ...
- New Begin--工作一年所思所感小记
有段日子没有更新Blog了,这段时间过得有些散漫,今天看完了两本书,感触颇多,让我繁杂的心绪又重归平静,想写一些什么,遂有了这篇文章. 所谓的一年是从13年7月9日我正是入职算起,到现在为止一年有余, ...
- Installing Intellij IDEA sublime-text-2 on Ubuntu
he installation on Linux is traditionally more complicated. I wonder why people complain about the l ...