redis - 文章投票

參考《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因爲是做者,已經投過票了,因此不能投票
image.png排序

排序

@Test
public void sortArticle() {
    // 根據時間排序
    System.out.println(JedisUtils.zrevrange("score:", 0, -1));
    // 根據分值排序
    System.out.println(JedisUtils.zrevrange("time:", 0, -1));
}

運行結果以下,第一行結果,因爲文章1被投了一票,雖然發佈時間比文章5早,可是拍在文章5前面。第二行結果就是按時間排序的。
image.pngget

相關文章
相關標籤/搜索