autfish

导航

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);
		}
	}

源码下载

posted on 2016-06-23 15:13  autfish  阅读(197)  评论(0编辑  收藏  举报