参考《redis实战》java
一、文章信息包括:标题、内容、连接、发布时间、发布人,发布后就给本身投一张票。
二、一我的只能给一篇文章投一张票。
三、文章只能七天内容许投票。
四、文章投票排名考虑文章发布时间以及投票数量,以发布时间做为降序排序,若是投票数量为200,则时间向前移一天。
五、文章排序包括发布时间排序,投票得分排序
能够采用散列来保存文章信息。存入信息用HMSET,取出对应字段信息用HMGET,取出key的全部信息用HGETALL,基本用法以下:redis
// 赋值 local:0>hmset person:001 name '张三' age 18 "OK" // 取对应key的某个属性值 local:0>hmget person:001 name 1) "张三" // 取对应key的全部属性值 local:0>hgetall person:001 1) "name" 2) "张三" 3) "age" 4) "18"
这边考虑到不能重复的概念,在java里用set,redis也有集合的概念。集合简单的说,就是不能有重复的数据,基本用法以下:post
// 赋值 local:0>sadd name '张三' "1" // 赋值 local:0>sadd name '李四' "1" // 赋值失败,返回0,由于已经添加过 local:0>sadd name '张三' "0" // 获取对应key的全部成员 local:0>smembers name 1) "张三" 2) "李四"
有时间控制需求,须要把文章id和发布时间保存起来,考虑到后面用时间进行排序,因此用有序集合。有序集合和上面集合不同的是,多了一个分值的概念,能够经过分值进行排序等操做。七天后不能投票就能够经过这个分值来计算。spa
// 添加 local:0>zadd score 88 '赵大' "1" // 添加 local:0>zadd score 93 '熊二' "1" // 添加 local:0>zadd score 92 '张三' "1" // 添加 local:0>zadd score 89 '李四' "1" // 添加 local:0>zadd score 70 '王五' "1" // 重复添加失败返回0, local:0>zadd score 60 '王五' "0" // 分数加5,返回最终值 local:0>zincrby score 5 '王五' "65" // 从低到高排序,取前四个 local:0>zrange score 0 3 withscores 1) "王五" 2) "65" 3) "赵大" 4) "88" 5) "李四" 6) "89" 7) "张三" 8) "92" // 从高到低排序,取前四个 local:0>zrevrange score 0 3 withscores 1) "熊二" 2) "93" 3) "张三" 4) "92" 5) "李四" 6) "89" 7) "赵大" 8) "88" // 获取分数值 local:0>zscore score '张三' "92"
一天有84600秒,200票时间向前移动一天,则每票就是84600/200=432分。code
投票要根据分数来排序,因此同需求三,用有序集合。blog
private static final int ONE_WEEK_IN_SECONDS = 7 * 86400; private static final int VOTE_SCORE = 432; @Test public void postArticle() throws InterruptedException { for (int i = 0; i < 5; i++) { // 经过incre获取自增加主键 String articleId = String.valueOf(JedisUtils.incre("article:")); // 定义主键 String article = "article:" + articleId; long now = System.currentTimeMillis() / 1000; String user = "发布人" + i; // 设置文章 Map<String, String> articleMap = new HashMap<>(); articleMap.put("title", "文章标题" + i); articleMap.put("content", "文章内容" + i); articleMap.put("link", "文章连接" + i); articleMap.put("user", user); articleMap.put("now", String.valueOf(now)); // 记录投票数 articleMap.put("votes", "1"); // 记录投票人,防止重复投票,设置过时时间 String voted = "voted:" + articleId; JedisUtils.sadd(voted, user); JedisUtils.expire(voted, ONE_WEEK_IN_SECONDS); // 经过文章主键插入 JedisUtils.hmset(article, articleMap); //须要时间和分数排序 JedisUtils.zadd("score:", now + VOTE_SCORE, article); JedisUtils.zadd("time:", now, article); TimeUnit.SECONDS.sleep(1); } }
@Test public void voteArticle() { for (int i = 1; i < 3; i++) { String article = "article:" + i; String voted = "voted:" + i; System.out.println("投票前,第一篇文章和第二篇文章的投票数:"); System.out.println("文章信息:" + getArticle(article)); System.out.println("投票信息:" + getVotesUser(voted)); } String user = "发布人1"; for (int i = 1; i < 3; i++) { String article = "article:" + i; String voted = "voted:" + i; // 获取发布时间 Double zscore = JedisUtils.zscore("time:", article); long now = System.currentTimeMillis() / 1000; // 失效了,不能投票 if (zscore < (now - ONE_WEEK_IN_SECONDS)) { continue; } // 返回0说明已经存在没有插入 if (JedisUtils.sadd(voted, user) == 0) { continue; } // 没有返回0怎插入成功,顺便更新分数 JedisUtils.zincrby("score:", VOTE_SCORE, article); // 更新文章投票数 JedisUtils.hincrBy(article, "votes", 1); } for (int i = 1; i < 3; i++) { String article = "article:" + i; String voted = "voted:" + i; System.out.println("投票后,第一篇文章和第二篇文章的投票数:"); System.out.println("文章信息:" + getArticle(article)); System.out.println("投票信息:" + getVotesUser(voted)); } } private Map<String, String> getArticle(String article) { Map<String, String> articleMap = JedisUtils.hgetAll(article); return articleMap; } private Set<String> getVotesUser(String key) { return JedisUtils.smembers(key); }
运行结果以下,能够看到,文章1被投了一票,文章2因为是做者,已经投过票了,因此不能投票排序
@Test public void sortArticle() { // 根据时间排序 System.out.println(JedisUtils.zrevrange("score:", 0, -1)); // 根据分值排序 System.out.println(JedisUtils.zrevrange("time:", 0, -1)); }
运行结果以下,第一行结果,因为文章1被投了一票,虽然发布时间比文章5早,可是拍在文章5前面。第二行结果就是按时间排序的。get