RecommendByHot_scores
Change-Id: Icfef76f6ce21a60288c61d60ad1cd2d70045f953
diff --git a/src/main/java/com/example/g8backend/service/IPostService.java b/src/main/java/com/example/g8backend/service/IPostService.java
index a349b59..ca5376b 100644
--- a/src/main/java/com/example/g8backend/service/IPostService.java
+++ b/src/main/java/com/example/g8backend/service/IPostService.java
@@ -1,7 +1,9 @@
package com.example.g8backend.service;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.g8backend.entity.Post;
import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -20,4 +22,10 @@
@Transactional
void recordViewHistory(Long userId, Long postId);
+
+ @Scheduled(cron = "0 */10 * * * *") // 每10分钟执行一次
+ @Transactional
+ void calculateHotScores();
+
+ Page<Post> getRecommendedPosts(int page, int size, Long userId);
}
diff --git a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
index f2bef5f..ae47d8a 100644
--- a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
+++ b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
@@ -1,20 +1,25 @@
package com.example.g8backend.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.g8backend.entity.Post;
import com.example.g8backend.entity.PostLike;
import com.example.g8backend.entity.PostTag;
import com.example.g8backend.entity.PostView;
+import com.example.g8backend.mapper.CommentMapper;
import com.example.g8backend.mapper.PostMapper;
import com.example.g8backend.mapper.PostViewMapper;
import com.example.g8backend.service.IPostService;
import com.example.g8backend.service.IPostTagService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.List;
@Service
@@ -24,12 +29,15 @@
private final PostViewMapper postViewMapper;
+ private final CommentMapper commentMapper;
+
@Autowired
private IPostTagService postTagService;
- public PostServiceImpl(PostMapper postMapper, PostViewMapper postViewMapper) {
+ public PostServiceImpl(PostMapper postMapper, PostViewMapper postViewMapper, CommentMapper commentMapper) {
this.postMapper = postMapper;
this.postViewMapper = postViewMapper;
+ this.commentMapper = commentMapper;
this.baseMapper = postMapper; // 重要:设置 baseMapper
}
@@ -38,14 +46,15 @@
return postMapper.getPostsByUserId(userId);
}
- @Override
public void createPost(Post post) {
+ post.setHotScore(5.0); // 初始热度
post.setCreatedAt(new Timestamp(System.currentTimeMillis()));
save(post);
}
@Override
public void createPost(Post post, Long[] tagIds) {
+ post.setHotScore(5.0); // 初始热度
post.setCreatedAt(new Timestamp(System.currentTimeMillis()));
save(post);
for (long tagId : tagIds) {
@@ -110,4 +119,55 @@
postMapper.incrementViewCount(postId); // 直接调用原子操作
}
+ @Override
+ @Scheduled(cron = "0 */10 * * * *") // 每10分钟执行一次
+ @Transactional
+ public void calculateHotScores() {
+ // 1. 获取所有帖子
+ List<Post> posts = postMapper.selectList(new QueryWrapper<>());
+ Instant now = Instant.now();
+
+ // 2. 计算每个帖子的热度
+ posts.forEach(post -> {
+ // 计算时间衰减因子(以小时为单位)
+ long hoursSinceCreation = ChronoUnit.HOURS.between(
+ post.getCreatedAt().toInstant(),
+ now
+ );
+
+ // 获取互动数据(点赞数、评论数)
+ Long likeCount = postMapper.selectLikeCount(post.getPostId());
+ Long commentCount = commentMapper.selectCountByPostId(post.getPostId());
+
+ // 热度计算公式
+ double hotScore = (
+ Math.log(post.getViewCount() + 1) * 0.2 +
+ likeCount * 0.5 +
+ commentCount * 0.3
+ ) / Math.pow(hoursSinceCreation + 2, 1.5);
+
+ post.setHotScore(hotScore);
+ post.setLastCalculated(new Timestamp(System.currentTimeMillis()));
+ });
+
+ // 3. 批量更新热度(自定义SQL实现)
+ postMapper.batchUpdateHotScore(posts);
+ }
+
+ @Override
+ public Page<Post> getRecommendedPosts(int page, int size, Long userId) {
+ // 1. 获取用户已浏览的帖子ID列表
+ List<Long> viewedPostIds = postViewMapper.findViewedPostIds(userId);
+
+ // 2. 构建查询条件:排除已浏览帖子,按热度降序
+ QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
+ if (!viewedPostIds.isEmpty()) {
+ queryWrapper.notIn("post_id", viewedPostIds);
+ }
+ queryWrapper.orderByDesc("hot_score");
+
+ // 3. 分页查询
+ return postMapper.selectPage(new Page<>(page, size), queryWrapper);
+ }
+
}
\ No newline at end of file