redis学习笔记一:redis构建一个简单的文章投票网站的后端。

限制条件:

如果一篇文章获得了至少200张支持票,那么就认为这篇文章是一篇有趣的文章,如果网站每天发布1000篇文章,而其中五十篇文章符合文章有趣的要求,那么网站要做的就是将这50篇文章放到文章列表前100位至少一天(暂时不提供反对票的功能)。

得分计算方式:

产生一个能够随着时间流逝的不断减少的评分,程序需要根据文章的发布时间和当前的时间来计算文章的评分,具体的办法就是:将文章得到的支持票数乘以一个常量,然后加上文章的发布时间,得到的结果就是文章的评分,这个常量设置的是432(将一天的秒数86400除以文章展示一天所需要的支持票数200的出的):即文章每获取一张支持票就将文章的评分增加432。

数据结构的选择:

文章信息包括文章的标题、网址、发布用户、发布时间、文章的得票数使用hash来进行存储最好。

数据结构如下:

两个有序集合来存储文章:

第一个有序集合的成员为文章id,分值为文章的发布时间。

第二个有序集合的成员为文章id,分值则为文章的评分。

防止队同一篇文章多次投票,网站需要为每篇文章记录一个已投票的用户名单。

群组使用set就可以,一个群组一个set

投票功能实现

逻辑分析:

  • 判断文章的发布时间是否超过一周。
  • 如果在投票范围之内,那么使用sadd命令,将用户添加到记录文章已投票用户名单的集合里面。
  • 如果添加执行的操作成功的话,那么说明用户是第一次对文章进行投票,那么使用zincrby命令为文章增加432分,并使用hincrby命令对散列记录的文章投票数量进行更新。

具体代码实现:


private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;
private static final int VOTE_SCORE = 432;

public void articleVote(Jedis conn, String user, String article) {
        long cutoff = (System.currentTimeMillis() / 1000) - ONE_WEEK_IN_SECONDS;
        if (conn.zscore("time:", article) < cutoff){
            return;
        }

        String articleId = article.substring(article.indexOf(':') + 1);
       if (conn.sadd("voted:" + articleId, user) == 1) {//此处操作涉及redis事务暂时不做处理
            conn.zincrby("score:", VOTE_SCORE, article);
            conn.hincrBy(article, "votes", 1);
        }
    }

文章发布功能:

逻辑分析:

  • 发布文章创建一个新的文章ID,通过计数器INCR命令完成。
  • sadd将文章的发布者ID添加到文章记录的已投票用户名单集合,并使用expire命令为这个集合设置一个过期时间,让redis在文章发布期满一周之后自动删除这个集合。
  • hmset命令来存储文章的相关信息,并执行两个zadd命令,将文章的初始评分,和发布时间分别添加到两个相应的有序集合。

代码实现:

private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;
private static final int VOTE_SCORE = 432;

public String postArticle(Jedis conn, String user, String title, String link) {
        String articleId = String.valueOf(conn.incr("article:"));

        String voted = "voted:" + articleId;
        conn.sadd(voted, user);
        conn.expire(voted, ONE_WEEK_IN_SECONDS);

        long now = System.currentTimeMillis() / 1000;
        String article = "article:" + articleId;
        HashMap<String,String> articleData = new HashMap<String,String>();
        articleData.put("title", title);
        articleData.put("link", link);
        articleData.put("user", user);
        articleData.put("now", String.valueOf(now));
        articleData.put("votes", "1");
        conn.hmset(article, articleData);
        conn.zadd("score:", now + VOTE_SCORE, article);
        conn.zadd("time:", now, article);

        return articleId;
    }

获取评分最高的文章和获取最新文章

逻辑分析:

先使用zrevrange命令取出多个文章的ID,然后在对每个文章执行一次hgetall命令来去除文章的详细信息,这个方法既可以使用去除评分最高的文章,又可以取出最新发布的文章。

代码如下:

 private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;
 private static final int VOTE_SCORE = 432;
 private static final int ARTICLES_PER_PAGE = 25;

  public List<Map<String,String>> getArticles(Jedis conn, int page) {
        return getArticles(conn, page, "score:");
    }

  public List<Map<String,String>> getArticles(Jedis conn, int page, String order) {
        int start = (page - 1) * ARTICLES_PER_PAGE;
        int end = start + ARTICLES_PER_PAGE - 1;

        Set<String> ids = conn.zrevrange(order, start, end);
        List<Map<String,String>> articles = new ArrayList<Map<String,String>>();
        for (String id : ids){
            Map<String,String> articleData = conn.hgetAll(id);
            articleData.put("id", id);
            articles.add(articleData);
        }

        return articles;
    }

对文章添加分组

逻辑分析:

群组有两个部分组成,一部分负责记录文章属于哪个群组,另一部分负责取出群组里面的文章,为了记录各个群组都保存了那些文章,网站需要为每个群组创建一个集合,并将所有同属于一个群组的文章ID都记录到那个集合里面

代码实现:

public void addGroups(Jedis conn, String articleId, String[] toAdd) {
        String article = "article:" + articleId;
        for (String group : toAdd) {
            conn.sadd("group:" + group, article);
        }
    }

获取组内的文章

逻辑分析:

对储存群组文章的集合和存储文章评分的有序集合执行zinterstore命令,可以得到按照文章的最新评分顺序的群组文章,如果群组的包含的文章多,那么执行zinterstore命令就会比较花时间,减少redis的工作量,将这个程序的计算结果缓存60s。

代码实现:

 private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;
    private static final int VOTE_SCORE = 432;
    private static final int ARTICLES_PER_PAGE = 25;



 public List<Map<String,String>> getGroupArticles(Jedis conn, String group, int page) {
        return getGroupArticles(conn, group, page, "score:");
    }

    public List<Map<String,String>> getGroupArticles(Jedis conn, String group, int page, String order) {
        String key = order + group;
        if (!conn.exists(key)) {
            ZParams params = new ZParams().aggregate(ZParams.Aggregate.MAX);
            conn.zinterstore(key, params, "group:" + group, order);
            conn.expire(key, 60);
        }
        return getArticles(conn, page, key);
    }

 

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值