序:
最近急需學習Redis相關內容,因此閱讀了一本相當不錯的書籍:《Redis實戰》,在這里記錄學習的過程以及遇到的問題。
一、第一章 根據文章點贊及發布日期list文章
業務:
全部代碼示例:
import redis.clients.jedis.Jedis; import redis.clients.jedis.ZParams; import java.util.*; public class Chapter01 { 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 static final void main(String[] args) { new Chapter01().run(); } public void run() { Jedis conn = new Jedis("localhost"); conn.select(15); String articleId = postArticle( conn, "username", "A title", "http://www.google.com"); System.out.println("We posted a new article with id: " + articleId); System.out.println("Its HASH looks like:"); Map<String,String> articleData = conn.hgetAll("article:" + articleId); for (Map.Entry<String,String> entry : articleData.entrySet()){ System.out.println(" " + entry.getKey() + ": " + entry.getValue()); } System.out.println(); articleVote(conn, "other_user", "article:" + articleId); String votes = conn.hget("article:" + articleId, "votes"); System.out.println("We voted for the article, it now has votes: " + votes); assert Integer.parseInt(votes) > 1; System.out.println("The currently highest-scoring articles are:"); List<Map<String,String>> articles = getArticles(conn, 1); printArticles(articles); assert articles.size() >= 1; addGroups(conn, articleId, new String[]{"new-group"}); System.out.println("We added the article to a new group, other articles include:"); articles = getGroupArticles(conn, "new-group", 1); printArticles(articles); assert articles.size() >= 1; } 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; } 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) { conn.zincrby("score:", VOTE_SCORE, article); conn.hincrBy(article, "votes", 1); } } 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; } public void addGroups(Jedis conn, String articleId, String[] toAdd) { String article = "article:" + articleId; for (String group : toAdd) { conn.sadd("group:" + group, article); } } 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); } private void printArticles(List<Map<String,String>> articles){ for (Map<String,String> article : articles){ System.out.println(" id: " + article.get("id")); for (Map.Entry<String,String> entry : article.entrySet()){ if (entry.getKey().equals("id")){ continue; } System.out.println(" " + entry.getKey() + ": " + entry.getValue()); } } } }
對文章進行分組:
群組功能由兩個部分組成,一個部分負責記錄文章屬於哪個群組,另一個部分負責取出群組里的文章。為了記錄群組里都保存了哪些文章,網站需要為每個群組創建一個集合,並將所有同屬於一個群組的文章ID都記錄到那個集合里。
package com.ual; import redis.clients.jedis.Jedis; import redis.clients.jedis.ZParams; import java.util.*; public class ArticleService { //設置過期時間 private static final int One_Week_In_Seconds=7*86400; //設置評分常量:一天的秒數除以200(默認熱門文章點贊數) private static final int Vote_Score=432; //設置分頁展示文章數量 private static final int Article_Pre_Page=25; /*發布並獲取文章*/ public String postArticle(Jedis conn,String user,String title,String link){ //設置文章id, 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; //文章數據存儲在hash表中 HashMap<String ,String> articleData=new HashMap<>(); articleData.put("id",articleId); articleData.put("title",title); articleData.put("link",link); articleData.put("user",user); articleData.put("time",String.valueOf(now)); articleData.put("votes","0"); conn.hmset(article,articleData); conn.zadd("score:",now+Vote_Score,article); conn.zadd("time:",now,article); return articleId; } 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){ //score表中article分值加432 conn.zincrby("score:",Vote_Score,article); //article表中votes字段加1 conn.hincrBy(article,"votes",1); } } public List<Map<String,String>> getArticle(Jedis conn,int page,String order){ //定義分頁開始結束序號 int start=(page-1)*Article_Pre_Page; int end=start+Article_Pre_Page-1; //從order(time:或score:)中取出全部文章id Set<String> ids=conn.zrevrange(order,start,end); //定義一個鏈表,存儲要取出的全部文章 List<Map<String,String>> articles=new ArrayList<>(); for(String id:ids){ //從對應文章表中取出文章數據(hgetAll為取出全部字段) Map<String,String> articleData=conn.hgetAll(id); articles.add(articleData); } return articles; } //添加分組分組 一篇文章可以屬於多個群組 public void addGroups(Jedis conn,String articleId,String[] toadd){ String article="article:"+articleId; for (String group:toadd){ conn.sadd("group"+group,article); } } 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); //獲取分組文章與排序文章id的交集存入key中,key中的排序方式依據排序文章的方式進行排序 conn.zinterstore(key,params,"group:"+group,order); //設置過期時間為60s conn.expire(key,60); } return getArticle(conn,page,key); } public void printArticles(List<Map<String,String>> articles){ for(Map<String,String> article:articles){ System.out.println("id:"+article.get("id")); for(Map.Entry<String,String> entry:article.entrySet()){ if(entry.getKey().equals("id")){ continue; } System.out.println(" "+entry.getKey()+" : "+entry.getValue()); } } } }
Redis不僅可以對多個多個集合執行操作,甚至在一些情況下,還可以在集合和有序集合之間執行操作。
為了能根據評分對群組文章進行排序和分頁,網站需要將同一個群組里的所有文章都按照評分有序的存儲到一個有序的集合里(設置60秒后就過期),Redis的ZINTERSTORE命令可以j接受多個集合和多個有序集合作為輸入,找出所有同時存在於集合和有序集合的成員,並以幾種不同的方式來合並這些成員的分值(即沒有排序規則的集合成員的分值都會被視為1,在這里指的是普通分組成員)。對於我們的文章投票網站來說,程序需要使用ZINTERSTORE命令選出相同成員中最大的那個分值來作為交集的分值:取決於所使用的排序選項,這些分值既可以是文字的評分,也可以是文字的發布時間。
第二章
1)登陸和cookie緩存