参考《redis实战》
需要
1、文章信息包含:题目、内容、链接、公布工夫、公布人,公布后就给本人投一张票。
2、一个人只能给一篇文章投一张票。
3、文章只能七天内容许投票。
4、文章投票排名思考文章公布工夫以及投票数量,以公布工夫作为降序排序,如果投票数量为200,则工夫向前移一天。
5、文章排序包含公布工夫排序,投票得分排序
剖析
第一个需要
能够采纳散列来保留文章信息。存入信息用HMSET,取出对应字段信息用HMGET,取出key的所有信息用HGETALL,根本用法如下:
// 赋值local:0>hmset person:001 name '张三' age 18"OK"// 取对应key的某个属性值 local:0>hmget person:001 name1) "张三"// 取对应key的所有属性值local:0>hgetall person:0011) "name"2) "张三"3) "age"4) "18"
第二个需要
这边思考到不能反复的概念,在java里用set,redis也有汇合的概念。汇合简略的说,就是不能有反复的数据,根本用法如下:
// 赋值local:0>sadd name '张三'"1"// 赋值local:0>sadd name '李四'"1"// 赋值失败,返回0,因为曾经增加过local:0>sadd name '张三'"0"// 获取对应key的所有成员local:0>smembers name1) "张三"2) "李四"
第三个需要
有工夫管制需要,须要把文章id和公布工夫保存起来,思考到前面用工夫进行排序,所以用有序汇合。有序汇合和下面汇合不一样的是,多了一个分值的概念,能够通过分值进行排序等操作。七天后不能投票就能够通过这个分值来计算。
// 增加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 withscores1) "王五"2) "65"3) "赵大"4) "88"5) "李四"6) "89"7) "张三"8) "92"// 从高到低排序,取前四个local:0>zrevrange score 0 3 withscores1) "熊二"2) "93"3) "张三"4) "92"5) "李四"6) "89"7) "赵大"8) "88"// 获取分数值local:0>zscore score '张三'"92"
第四个需要
一天有84600秒,200票工夫向前挪动一天,则每票就是84600/200=432分。
第五个需要
投票要依据分数来排序,所以同需要三,用有序汇合。
实际
公布文章
private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;private static final int VOTE_SCORE = 432;@Testpublic 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); }}
投票
@Testpublic 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因为是作者,曾经投过票了,所以不能投票
排序
@Testpublic void sortArticle() { // 依据工夫排序 System.out.println(JedisUtils.zrevrange("score:", 0, -1)); // 依据分值排序 System.out.println(JedisUtils.zrevrange("time:", 0, -1));}
运行后果如下,第一行后果,因为文章1被投了一票,尽管公布工夫比文章5早,然而拍在文章5后面。第二行后果就是按工夫排序的。