天天看點

用Redis的zset有序集合實作一個本周熱議功能

項目名稱:eblog

項目 Git 倉庫:https://github.com/MarkerHub/eblog(給個 star 支援哈)

前幾篇項目講解文章:

1、Github 上最值得學習的 Springboot 開源部落格項目!

2、小 Hub 手把手教你如何從 0 搭建一個開源項目架構

3、整合Redis,以及項目優雅的異常處理與傳回結果封裝

本周熱議,本周發表并且評論最多的文章排行,如果直接查詢資料庫的話很快就可以實作,隻需要限定一下文章建立時間,然後更加評論數量倒叙取前幾篇即可搞定。

但這裡我們使用redis來完成。之前上課時候我們說過,排行榜功能,我們可以使用redis的有序集合zset來完成。現在我們就這個資料結構來完成本周熱議的功能。

在編碼之前,我們需要先來回顧一下zset的幾個基本指令。

zrange key start stop [WITHSCORES]

withscores代表的是否顯示順序号  start和stop代表所在的位置的索引。可以這樣了解:将集合元素依照順序值升序排序再輸出,start和stop限制周遊的限制範圍

zincrby key increment member

為有序集 key 的成員 member 的 score 值加上增量 increment 。

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

計算給定的一個或多個有序集的并集,其中給定 key 的數量必須以 numkeys 參數指定,并将該并集(結果集)儲存到 destination 。

預設情況下,結果集中某個成員的 score 值是所有給定集下該成員 score 值之 和 。

其他指令可以參考這裡:http://doc.redisfans.com/

以下是我做的實驗:

用Redis的zset有序集合實作一個本周熱議功能

我們來分析一下我們的需求。我們想用緩存來完成這本周熱議排行榜功能,不依賴資料庫(除了初始化資料)。有人發表評論之後,直接使用指令加一,并重新計算并集得到排行榜。

項目啟動時候我們先初始化最近文章的評論數量。基本邏輯如下:

查庫擷取最近7天的所有文章(或者加多一個條件:評論數量大于0)

然後把文章的評論數量作為有序集合的分數,文章id作為ID存儲到zset中。

本周熱議上有标題和評論數量,是以,我們還需要把文章的基本資訊存儲到redis總。這樣得到文章的id之後,我們再從緩存中得到标題等資訊,這裡我們可以使用hash的結構來存儲文章的資訊。

另外,因為是本周熱議,如果文章發表超過7天了之後就沒啥用了,是以我們可以給文章的有序集合一個有效時間。超過7天之後就自定删除緩存。

具體代碼如下:

com.example.service.impl.PostServiceImpl#initIndexWeekRank

對應的緩存文章資訊的方法如下:

統計7天的文章集合交集數量:

寫好了之後,我們再我們的項目啟動類中調用一下即可完成了初始化。

<code>@Slf4j</code>

<code>@Order(1000)</code>

<code>@Component</code>

<code>public class ContextStartup implements ApplicationRunner, ServletContextAware {</code>

<code>   private ServletContext servletContext;</code>

<code>   @Autowired</code>

<code>   PostService postService;</code>

<code>   @Override</code>

<code>   public void setServletContext(ServletContext servletContext) {</code>

<code>       this.servletContext = servletContext;</code>

<code>   }</code>

<code>   public void run(ApplicationArguments args) throws Exception {</code>

<code>       servletContext.setAttribute("base", servletContext.getContextPath());</code>

<code>       //初始化首頁的周評論排行榜</code>

<code>       postService.initIndexWeekRank();</code>

<code>}</code>

以上就完成了初始化。這時候我們在本周熱議子產品已經可以看到效果了。緩存中已經有我們想要的資料,接下我們在controller中擷取出來,然後傳回給個我們的頁面,頁面用異步加載的模式,是以這裡定義一個異步接口:

com.example.controller.PostController

<code>@ResponseBody</code>

<code>@GetMapping("/post/hots")</code>

<code>public Result hotPost() {</code>

<code>   Set&lt;ZSetOperations.TypedTuple&gt; lastWeekRank = redisUtil.getZSetRank("last_week_rank", 0, 6);</code>

<code>   List&lt;Map&lt;String, Object&gt;&gt; hotPosts = new ArrayList&lt;&gt;();</code>

<code>   for (ZSetOperations.TypedTuple typedTuple : lastWeekRank) {</code>

<code>       Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();</code>

<code>       map.put("comment_count", typedTuple.getScore());</code>

<code>       map.put("id", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:id"));</code>

<code>       map.put("title", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:title"));</code>

<code>       hotPosts.add(map);</code>

<code>   return Result.succ(hotPosts);</code>

}

用Redis的zset有序集合實作一個本周熱議功能

緻此,我們已經完成了擷取本周熱議的資料,但是,隻是一個初始化而已,當有評論的時候還應該添加資料到我們的緩存中,還有頁面的内容我們也應該寫一些ajax加載資料,這些我們先留着,先到這裡,以上是我們之前課程講過的内容,大家先行消化一下。