Redis learning note 1: redis builds a simple back end of article voting website.

Keywords: Jedis Redis

Restrictions:

If an article gets at least 200 support votes, it is considered to be an interesting article. If the website publishes 1000 articles every day, and 50 of them meet the requirements of interesting articles, what the website has to do is to put these 50 articles in the top 100 of the article list for at least one day (the function of negative vote is not provided temporarily).

Score calculation method:

To generate a score that can be continuously reduced with the passage of time, the program needs to calculate the score of the article according to the release time and the current time of the article. The specific method is: multiply the number of support votes obtained by the article by a constant, and then add the release time of the article, and the result is the score of the article. This constant is set to 432 (8640 seconds in a day 0 divided by the number of support votes 200 needed for the article display in a day): that is, the article will increase the score of the article by 432 for each support vote obtained.

Selection of data structure:

Article information including article title, website, publishing user, publishing time, number of votes of the article is best stored by hash.

The data structure is as follows:

Two ordered sets to store articles:

The member of the first ordered set is the article id, and the score is the publication time of the article.

The member of the second ordered set is the article id, and the score is the score of the article.

To prevent teams from voting multiple times for the same article, the website needs to record a list of users who have voted for each article.

Implementation of voting function

Logical analysis:

  • Determine whether the article has been published for more than a week.
  • If it is within the voting range, the sadd command is used to add users to the collection that records the list of voted users of articles.
  • If the add operation is successful, it means that the user is the first time to vote for the article. Then use the zincrby command to increase 432 points for the article, and use the hincrby command to update the number of votes for the articles in the hash record.

Specific code implementation:

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) {//The redis transaction involved in this operation will not be processed temporarily
            conn.zincrby("score:", VOTE_SCORE, article);
            conn.hincrBy(article, "votes", 1);
        }
    }

Article publishing function:

Logical analysis:

  • The post creates a new post ID, which is done by the counter INCR command.
  • sadd adds the Publisher ID of the article to the collection of voted user list of the article record, and uses the expire command to set an expiration time for the collection, so that redis can automatically delete the collection one week after the expiration of the article publishing period.
  • The hmset command stores the related information of the article, and executes two zadd commands to add the initial score and release time of the article to two corresponding ordered sets.

Code implementation:

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;
    }

Get the most rated articles and get the latest articles

Logical analysis:

First, use the zrevrange command to get the ID of multiple articles, and then execute the hgetall command once for each article to remove the details of the article. This method can not only remove the articles with the highest score, but also remove the latest published articles.

The code is as follows:

 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;
    }

Group articles

Logical analysis:

The group consists of two parts, one is responsible for recording which group the articles belong to, the other is responsible for taking out the articles in the group. In order to record the articles saved by each group, the website needs to create a collection for each group, and record all the article ID S belonging to the same group into that collection

Code implementation:

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

Get articles in the group

Logical analysis:

Execute the zinterstore command on the set of stored group articles and the ordered set of stored article scores to get the group articles according to the latest scoring order of articles. If there are many articles in the group, it will take more time to execute the zinterstore command, reduce the workload of redis, and cache the calculation results of this program for 60s.

Code implementation:

 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);
    }

 

 

 

Published 33 original articles, won praise 13, visited 10000+
Private letter follow

Posted by namasteaz on Wed, 15 Jan 2020 03:43:27 -0800