关于redis:redis-文章投票

39次阅读

共计 3459 个字符,预计需要花费 9 分钟才能阅读完成。

参考《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 name
1) "张三"
// 取对应 key 的所有属性值
local:0>hgetall person:001
1) "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 name
1) "张三"
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 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 分。

第五个需要

投票要依据分数来排序,所以同需要三,用有序汇合。

实际

公布文章

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 后面。第二行后果就是按工夫排序的。

正文完
 0