您现在的位置是:网站首页> 编程资料编程资料

Redis实战之百度首页新闻热榜的实现代码_Redis_

2023-05-27 362人已围观

简介 Redis实战之百度首页新闻热榜的实现代码_Redis_

目标

 利用Redis实现类似百度首页新闻热榜功能。

功能

新闻排行榜以热度为指标降序排序,这里假设热度就是评论数量且统计的热度时间范围以当天为准;根据新闻的时效性,这里假设每15分钟刷新一次新闻榜单。


分析 Zset数据类型:一个有序集合最多 2^{32}-1 个元素,集合元素有序不可重复,每个元素都会关联一个double类型的分数。元素根据分数从小到大的排序,分数可以重复。zscore命令可以对分数实现增量,且如果该Zset中没有该元素,则会创建该条数据。可以将模块名+当天的时间作为Zset的键,用户评论量作为分数,新闻标题作为值,每当用户评论一次新闻,分数则相应地加1。每隔15分钟提取新闻统计中的前30名(包含第30名)榜单,放入到新闻热榜的Zset中。


代码实现

控制层

 package com.shoppingcart.controller; import com.shoppingcart.service.NewsTopServer; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; import java.util.Map; /** * 新闻排行榜 */ @RestController @RequestMapping("/newsTop") public class NewsTopController { @Resource public NewsTopServer newsTopServer; /** * http://localhost:8099/newsTop/zscoreNews?newTitle=《欢乐喜剧人7》全新赛制养成新人&score=434000 * 创建新闻统计&实时统计新闻热度 * @param newTitle 新闻标题 (根据业务也可以写成新闻ID) * @param score 热度增量 * @return 给新闻一个增量以后,返回新闻的当前分数。 */ @GetMapping("/zscoreNews") public Map zscoreNews( @RequestParam(value = "newTitle", required = true) String newTitle, @RequestParam(value = "score", defaultValue = "1") double score ) { Map map = newsTopServer.incrementScore(newTitle, score); return map; } /** * http://localhost:8099/newsTop/findNewByNewTitle?newTitle=《欢乐喜剧人7》全新赛制养成新人 * 查询某条新闻的热度 * @param newTitle * @return */ @GetMapping("/findNewByNewTitle") public Map findNewByNewTitle( @RequestParam(value = "newTitle", required = true) String newTitle ) { Map map = newsTopServer.findNewByNewTitle(newTitle); return map; } /** * http://localhost:8099/newsTop/createNewsTop?startPage=0&endPage=29 * 对统计的新闻数据降序排序,并将[29,0]之间的数据放入新闻排行榜。(这个方法可以设置成定时任务。) * @param startPage 开始下标 * @param endPage 结束下标 * @return */ @GetMapping("/createNewsTop") public Map createNewsTop( @RequestParam(value = "startPage", defaultValue = "0") int startPage, @RequestParam(value = "endPage", defaultValue = "29") int endPage ) { Map map = newsTopServer.createNewsTop(startPage, endPage); return map; } /** * http://localhost:8099/newsTop/newsTop?startPage=20&endPage=29 * 对统计的新闻数据降序排序,并将[29,0]之间的数据放入新闻排行榜。(这个方法可以设置成定时任务。) * * @param startPage 开始下标 * @param endPage 结束下标 * @return */ @GetMapping("/newsTop") public Map newsTop( @RequestParam(value = "startPage", defaultValue = "0") int startPage, @RequestParam(value = "endPage", defaultValue = "9") int endPage ) { Map map = newsTopServer.newsTop(startPage, endPage); return map; } /** * http://localhost:8099/newsTop/addTestData * 批量增加测试数据(新闻统计) */ @PostMapping("/addTestData") public void addTestData(@RequestBody List> list) { for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).get("value").toString()); System.out.println(Double.parseDouble(list.get(i).get("score").toString())); zscoreNews(list.get(i).get("value").toString(), Double.parseDouble(list.get(i).get("score").toString())); } } /**新增测试数据: [ { "score": 2356428.0, "value": "《蒙面唱将猜猜猜》第五季收官" }, { "score": 2335456.0, "value": "《欢乐喜剧人7》全新赛制养成新人" }, { "score": 987655.0, "value": "《星光大道》2020年度总决赛" }, { "score": 954566.0, "value": "网易北京:重构梦幻西游项目" }, { "score": 943665.0, "value": "神武惊现靓号:44488888" }, { "score": 876653.0, "value": "小米手机:红米" }, { "score": 875444.0, "value": "英特尔扩大外包" }, { "score": 755656.0, "value": "多益广州举办神武4手游比赛" }, { "score": 687466.0, "value": "亮剑重播超记录" }, { "score": 567645.0, "value": "春节快到了" }, { "score": 554342.0, "value": "购票狂潮" }, { "score": 466654.0, "value": "达摩院旗下拥有20多位世界级的科学家" }, { "score": 456666.0, "value": "NBA MVP候选人" }, { "score": 435654.0, "value": "CBA最佳新秀" }, { "score": 392875.0, "value": "数字货币新时代" }, { "score": 300454.0, "value": "网易新手游即将发布" }, { "score": 277654.0, "value": "CBA12强排名:四强格局已定" }, { "score": 265656.0, "value": "用黑科技悄悄改变大众生活" }, { "score": 234665.0, "value": "玉溪:致力打造全省数字经济第一城" }, { "score": 234665.0, "value": "广西培育消费新业态新模式" }, { "score": 234656.0, "value": "互联网产品是顺从用户?还是教育用户?" }, { "score": 234564.0, "value": "蒋军:企业做强,做大跟产品的关系是什么?" }, { "score": 234564.0, "value": "热搜第一!微信又有重大更新,这次有点炸" }, { "score": 234555.0, "value": "成功的人,往往都读这“6”种书" }, { "score": 134566.0, "value": "外地职工留苏州过年 落户加15分" }, { "score": 133455.0, "value": "蒋军:成功创业的7种思维!创业者必读!" }, { "score": 98554.0, "value": "阿里平头哥:首个RISC - V版安卓10系统顺畅运行" }, { "score": 87654.0, "value": "不断增强人民群众就医获得感" }, { "score": 54347.0, "value": "《星光大道》年度总冠军出炉" }, { "score": 43335.0, "value": "流量应是榜样,榜样应成力量" }, { "score": 23555.0, "value": "《山海情》:主旋律可以这样好看" }, { "score": 23456.0, "value": "2021艺考新动向" } ] */ }

 

业务层

 package com.shoppingcart.service; import java.util.Map; public interface NewsTopServer { Map incrementScore(String newTitle,double zscore); Map findNewByNewTitle(String newTitle); Map createNewsTop(int startPage, int endPage); Map newsTop(int startPage, int endPage); }
 package com.shoppingcart.service.impl; import com.shoppingcart.service.NewsTopServer; import com.shoppingcart.utils.RedisService; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.*; @Service public class NewsTopServerImpl implements NewsTopServer { @Resource private RedisService redisService; @Override public Map incrementScore(String newTitle, double score) { Map map = new HashMap<>(); //String key= "newsSta:"+DateUtils.dateToString(new Date(),"yyyyMMdd"); String key = "newsSta:" + "20210123"; Double d = redisService.incrementScore(key, newTitle, score); Map m = new HashMap() { { put("key", key); put("newTitle", newTitle); put("score", d); } }; map.put("data", m); map.put("code", 0); return map; } @Override public Map findNewByNewTitle(String newTitle) { //String key= "newsSta:"+DateUtils.dateToString(new Date(),"yyyyMMdd"); String key = "newsSta:" + "20210123"; Double d = redisService.score(key, newTitle); Map map = new HashMap<>(); Map m = new HashMap() { { put("key", key); put("newTitle", newTitle); put("score", d); } }; map.put("data", m); map.put("code", 0); return map; } /** * @param startPage * @param endPage * @return */ @Override public Map createNewsTop(int startPage, int endPage) { Map map = new HashMap<>(); //新闻统计键 //String newsStaKey= "newsSta:"+DateUtils.dateToString(new Date(),"yyyyMMdd"); String newsStaKey = "newsSta:" + "20210123"; //新闻前30排名键 //String newsTopKey= "newsSta:"+DateUtils.dateToString(new Date(),"yyyyMMdd"); String newsTopKey = "newsTop:" + "20210123"; //查询前30的信息(Interface Comparable :该接口对实现它的每个类的对象强加一个整体排序。) Set> set = redisService.reverseRangeWithScores(newsStaKey, startPage, endPage); if (set == null || set.size() == 0) { map.put("data", null); map.put("code", 1); return map; } //删除旧的新闻排行榜 redisService.del(newsTopKey); //添加新闻排行榜数据 Long zsetSize = redisService.zsetAdd(newsTopKey, set); Map m = new HashMap() { { put("data", set); put("size", zsetSize); } }; map.put("data", m); map.put("code", 0); return map; } /** * 查看新闻热榜(TOP30) * * @param startPage * @param endPage * @return */ @Override public Map newsTop(int startPage, int endPage) { //新闻统计键 //String newsStaKey= "newsSta:"+DateUtils.dateToString(new Date(),"yyyyMMdd"); String newsStaKey = "newsSta:" + "20210123"; //新闻前30排名键 //String newsTopKey= "newsSta:"+DateUtils.dateToString(new Date(),"yyyyMMdd"); String newsTopKey = "newsTop:" + "20210123"; Set> set = redisService.reverseRangeWithScores(newsTopKey, startPage, endPage); Map m = new HashMap(); m.put("data", set); m.put("size", set.size()); //新闻排行榜为空,也许现在正在添加数据,先查询新闻统计键。 if (set == null || set.size() == 0) { //查询前30的信息(Interface Comparable :该接口对实现它的每个类的对象强加一个整体排序。) Set> set2 = redisService.reverseRangeWithScores(newsStaKey, startPage, endPage); m.put("data", set); m.put("size", set.size()); } Map map = new HashMap<>(); map.put("data", m); map.put("code", 0); return map; } }

 

工具类

 package com.shoppingcart.utils; import java.text.SimpleDateFormat; import java.util.Date; public class DateUtils { // 日期转字符串,返回指定的格式 public static String dateToString(Date date, String dateFormat) { SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); return sdf.format(date); } }
 package com.shoppingcart.utils; import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.core.DefaultTypedTuple; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Service; import org.spring
                
                

-六神源码网