參考《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