当前位置:网站首页>Number 16, top posts
Number 16, top posts
2022-07-31 02:40:00 【A snicker】
1、Post scores are time-dependent,而且点赞,Collections and other operations are very high frequency,Generally, post scores are calculated through timed tasks(分布式定时任务 Spring Quartz)
2、Put posts with changed scores in the cache,Time to time to calculate the posts in the cache(Redis)
1、Put the post that needs to calculate the scoreRedis中
1、生成RedisKey
2、When an action that affects the post score occurs,Put the post inRedis
RedisKeyUtil.java
// 帖子分数
public static String getPostScoreKey() {
return PREFIX_POST + SPLIT + "score";
}
DiscussPostController.java
A)When posting a new post,将帖子id放入Redis(Give the post an initial score):RedisKey:postId 存放在Set里.
@PostMapping("/add")
@ResponseBody
public String addDiscussPost(String title, String content) {
...
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, post.getId());
}
B)加精、评论、When liking the action,Also put the post inRedis
// 加精 HomeController.java
@PostMapping("/wonderful")
@ResponseBody
public String setWonderful(int id) {
discussPostService.updateStatus(id, 1);
...
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, id);
}
// 评论 CommentController.java
@PostMapping("/add/{discussPostId}")
public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment) {
if (comment.getEntityType() == ENTITY_TYPE_POST) {
...
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, discussPostId);
}
2、使用Quartz实现定时任务
1、Job接口实现
quartz包下 PostScoreRefreshJob 类
public class PostScoreRefreshJob implements Job, CommunityConstant {
private static final Logger LOGGER = LoggerFactory.getLogger(PostScoreRefreshJob.class);
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private DiscussPostService discussPostService;
@Autowired
private LikeService likeService;
@Autowired
private ElasticsearchService elasticsearchService;
private static final Date EPOCH;
static {
try {
EPOCH = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-08-01 00:00:00");
} catch (ParseException e) {
throw new RuntimeException("初始化牛客纪元失败!", e);
}
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
String redisKey = RedisKeyUtil.getPostScoreKey();
BoundSetOperations operations = redisTemplate.boundSetOps(redisKey);
if (operations.size() == 0) {
LOGGER.info("任务取消,没有需要刷新的帖子!");
return;
}
LOGGER.info("[任务开始] 正在刷新帖子分数:" + operations.size());
while (operations.size() > 0) {
this.refresh((Integer) operations.pop());
}
LOGGER.info("[任务结束] 帖子分数刷新完毕!");
}
private void refresh(int postId) {
DiscussPost post = discussPostService.findDiscussPostById(postId);
if (post == null) {
LOGGER.error("该帖子不存在:id = " + postId);
return;
}
// 是否精华
boolean wonderful = post.getStatus() == 1;
// 评论数量
int commentCount = post.getCommentCount();
// 点赞数量
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);
// 计算权重
double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
// 分数 = 帖子权重 + 距离天数
double score =
Math.log10(Math.max(w, 1))
+ (post.getCreateTime().getTime() - EPOCH.getTime()) / (1000 * 3600 * 24);
// 更新帖子分数
discussPostService.updateScore(postId, score);
// 同步搜索数据
post.setScore(score);
elasticsearchService.saveDiscussPost(post);
}
}
- Niu Ke era domain:private static final Date epoch,由于epoch只需要初始化一次,Initialize in a static code block
- 使用BoundSetOperations 绑定 Key,BoundSetOperationsis a bindingkey的对象,We can use this object to ANDkey相关的操作.
- 从Redis里取数据,若没有数据,Return directly after logging.若Set为空,对每个postId执行 refresh 方法.
refreshA method to refresh a post:
1、根据帖子id查找post实体
2、Determine whether to add refined、评论数量、点赞数量,计算分数(getTime() Get the millisecond value)
3、更新帖子分数
4、同步搜索数据
5、对Quartz进行配置:Time interval in milliseconds
对Quartz进行配置
// 配置 -> 数据库 -> 调用
@Configuration
public class QuartzConfig {
// 刷新帖子分数任务
@Bean
public JobDetailFactoryBean postScoreRefreshJobDetail() {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(PostScoreRefreshJob.class);
factoryBean.setName("postScoreRefreshJob");
factoryBean.setGroup("communityJobGroup");
factoryBean.setDurability(true);
factoryBean.setRequestsRecovery(true);
return factoryBean;
}
// 配置Trigger(SimpleTriggerFactoryBean, CronTriggerFactoryBean)
@Bean
public SimpleTriggerFactoryBean postScoreRefreshTrigger(JobDetail postScoreRefreshJobDetail) {
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(postScoreRefreshJobDetail);
factoryBean.setName("postScoreRefreshTrigger");
factoryBean.setGroup("communityTriggerGroup");
factoryBean.setRepeatInterval(1000 * 60 * 5);
factoryBean.setJobDataMap(new JobDataMap());
return factoryBean;
}
}
3、Home page interface processing
1、Sort posts by hottest
对 selectDiscussPostsThe method can be refactored
@Mapper
public interface DiscussPostMapper {
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);
// 增加了一个orderMode参数: orderMode=0 时按照“最新” 排序,orderMode=1 时按照“最热” 排序
}
discusspost-mapper.xml
<select id="selectDiscussPosts" resultType="DiscussPost">
select <include refid="selectFields"></include>
from discuss_post
where status != 2
<if test="userId!=0">
and user_id = #{
userId}
</if>
<if test="orderMode==0">
order by type desc, create_time desc
</if>
<if test="orderMode==1">
order by type desc, score desc, create_time desc
</if>
limit #{
offset}, #{
limit}
</select>
2、所有调用 selectDiscussPosts 的地方进行修改
3、HomeController:
从前端获取ordermode参数,and spell in path returned to the template
@RequestMapping(path = "/index", method = RequestMethod.GET)
public String getIndexPage(Model model, Page page,
@RequestParam(name = "orderMode", defaultValue = "0") int orderMode) {
// 1.默认orderMode=0,For example, when visiting the home page
// 方法调用钱,SpringMVC会自动实例化Model和Page,并将Page注入Model.
// 所以,在thymeleaf中可以直接访问Page对象中的数据.
page.setRows(discussPostService.findDiscussPostRows(0));
page.setPath("/index?orderMode=" + orderMode); // 2.修改Page的路径,加上orderMode参数
// 3.Use the refactored onediscussPostService
List<DiscussPost> list = discussPostService
.findDiscussPosts(0, page.getOffset(), page.getLimit(), orderMode);
List<Map<String, Object>> discussPosts = new ArrayList<>();
if (list != null) {
for (DiscussPost post : list) {
Map<String, Object> map = new HashMap<>();
map.put("post", post);
User user = userService.findUserById(post.getUserId());
map.put("user", user);
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());
map.put("likeCount", likeCount);
discussPosts.add(map);
}
}
model.addAttribute("discussPosts", discussPosts);
model.addAttribute("orderMode", orderMode);
return "/index";
}
4、index.html
1)th:href Hyperlink modification,传入orderMode 参数
2)由orderMode The parameter determines whether there is active 参数
<!-- 筛选条件 -->
<ul class="nav nav-tabs mb-3">
<li class="nav-item">
<a th:class="|nav-link ${orderMode==0?'active':''}|" th:href="@{/index(orderMode=0)}">最新</a>
</li>
<li class="nav-item">
<a th:class="|nav-link ${orderMode==1?'active':''}|" th:href="@{/index(orderMode=1)}">最热</a>
</li>
</ul>
边栏推荐
- 图像处理技术的心酸史
- StringJoiner详解
- Mathematical Ideas in AI
- 工程(五)——小目标检测tph-yolov5
- 经典链表OJ强训题——快慢双指针高效解法
- Tower of Hanoi problem
- Live Preview | KDD2022 Doctoral Dissertation Award Champion and Runner-up Dialogue
- Draw Your Cards
- php 网站的多语言设置(IP地址区分国内国外)
- MPPT solar charge controller data collection - through the gateway acquisition capacity battery SOC battery voltage, wi-fi
猜你喜欢
12 磁盘相关命令
YOLOV5学习笔记(三)——网络模块详解
Fiddler captures packets to simulate weak network environment testing
coldfusion8 background scheduled tasks take shell
Shell script to loop through values in log file to sum and calculate average, max and min
LeetCode 1161 最大层内元素和[BFS 二叉树] HERODING的LeetCode之路
Layer 2 broadcast storm (cause + judgment + solution)
Face detection based on opencv
What level of software testing does it take to get a 9K job?
User interaction + formatted output
随机推荐
vlan间路由+静态路由+NAT(PAT+静态NAT)综合实验
The application of AI in the whole process of medical imaging equipment
自动化办公案例:如何自动生成期数据?
Basic learning about Redis related content
Force buckled brush the stairs (7/30)
Classic linked list OJ strong training problem - fast and slow double pointer efficient solution
工程(五)——小目标检测tph-yolov5
Discourse Custom Header Links
Maximum area of solar panel od js
19.支持向量机-优化目标和大间距直观理解
Detailed explanation of STP election (step + case)
15、网站统计数据
[1154] How to convert string to datetime
医疗影像领域AI软件开发流程
Coldfusion file read holes (CVE - 2010-2861)
YOLOV5 study notes (3) - detailed explanation of network module
全流程调度——MySQL与Sqoop
MPPT solar charge controller data collection - through the gateway acquisition capacity battery SOC battery voltage, wi-fi
数学解决——环形链表问题
关于 mysql8.0数据库中主键位id,使用replace插入id为0时,实际id插入后自增导致数据重复插入 的解决方法