diff --git a/han-note-comment/han-note-comment-biz/pom.xml b/han-note-comment/han-note-comment-biz/pom.xml index a229522..96ffe1e 100644 --- a/han-note-comment/han-note-comment-biz/pom.xml +++ b/han-note-comment/han-note-comment-biz/pom.xml @@ -113,6 +113,12 @@ han-note-kv-api + + + com.github.phantomthief + buffer-trigger + + diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java index cd39c26..85628d4 100644 --- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java @@ -12,4 +12,9 @@ public interface MQConstants { */ String TOPIC_COUNT_NOTE_COMMENT = "CountNoteCommentTopic"; + /** + * Topic: 评论热度值更新 + */ + String TOPIC_COMMENT_HEAT_UPDATE = "CommentHeatUpdateTopic"; + } \ No newline at end of file diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java new file mode 100644 index 0000000..65a8ea4 --- /dev/null +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java @@ -0,0 +1,90 @@ +package com.hanserwei.hannote.comment.biz.consumer; + +import com.github.phantomthief.collection.BufferTrigger; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.hanserwei.framework.common.utils.JsonUtils; +import com.hanserwei.hannote.comment.biz.constants.MQConstants; +import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO; +import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper; +import com.hanserwei.hannote.comment.biz.model.bo.CommentHeatBO; +import com.hanserwei.hannote.comment.biz.utils.HeatCalculator; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.time.Duration; +import java.util.List; +import java.util.Set; + +@Component +@RocketMQMessageListener(consumerGroup = "han_note_group_" + MQConstants.TOPIC_COMMENT_HEAT_UPDATE, // Group 组 + topic = MQConstants.TOPIC_COMMENT_HEAT_UPDATE // 主题 Topic +) +@Slf4j +public class CommentHeatUpdateConsumer implements RocketMQListener { + + @Resource + private CommentDOMapper commentDOMapper; + + private final BufferTrigger bufferTrigger = BufferTrigger.batchBlocking() + .bufferSize(50000) // 缓存队列的最大容量 + .batchSize(300) // 一批次最多聚合 300 条 + .linger(Duration.ofSeconds(2)) // 多久聚合一次(2s 一次) + .setConsumerEx(this::consumeMessage) // 设置消费者方法 + .build(); + + @Override + public void onMessage(String body) { + // 往 bufferTrigger 中添加元素 + bufferTrigger.enqueue(body); + } + + private void consumeMessage(List bodys) { + log.info("==> 【评论热度值计算】聚合消息, size: {}", bodys.size()); + log.info("==> 【评论热度值计算】聚合消息, {}", JsonUtils.toJsonString(bodys)); + + // 将聚合后的消息体 Json 转 Set, 去重相同的评论 ID, 防止重复计算 + Set commentIds = Sets.newHashSet(); + bodys.forEach(body -> { + try { + Set list = JsonUtils.parseSet(body, Long.class); + commentIds.addAll(list); + } catch (Exception e) { + log.error("", e); + } + }); + + log.info("==> 去重后的评论 ID: {}", commentIds); + + // 批量查询评论 + List commentDOS = commentDOMapper.selectByCommentIds(commentIds.stream().toList()); + + // 评论 ID + List ids = Lists.newArrayList(); + // 热度值 BO + List commentBOS = Lists.newArrayList(); + + //重新计算每条评论的热度值 + commentDOS.forEach(commentDO -> { + Long commentId = commentDO.getId(); + // 被点赞数 + Long likeTotal = commentDO.getLikeTotal(); + // 被回复数 + Long childCommentTotal = commentDO.getChildCommentTotal(); + + // 计算热度值 + BigDecimal heatNum = HeatCalculator.calculateHeat(likeTotal, childCommentTotal); + ids.add(commentId); + commentBOS.add(CommentHeatBO.builder() + .id(commentId) + .heat(heatNum.doubleValue()) + .build()); + }); + // 批量更新评论热度值 + commentDOMapper.batchUpdateHeatByCommentIds(ids, commentBOS); + } +} \ No newline at end of file diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java index 36650aa..ef05284 100644 --- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java @@ -104,6 +104,12 @@ public class CommentDO { @TableField(value = "create_time") private LocalDateTime createTime; + /** + * 下级评论总数 + */ + @TableField(value = "child_comment_total") + private Long childCommentTotal; + /** * 更新时间 */ diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java index 3e2d1be..9c09da1 100644 --- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java @@ -3,6 +3,7 @@ package com.hanserwei.hannote.comment.biz.domain.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO; import com.hanserwei.hannote.comment.biz.model.bo.CommentBO; +import com.hanserwei.hannote.comment.biz.model.bo.CommentHeatBO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -26,4 +27,14 @@ public interface CommentDOMapper extends BaseMapper { * @return 插入数量 */ int batchInsert(@Param("comments") List comments); + + /** + * 批量更新热度值 + * + * @param commentIds 评论 ID 列表 + * @param commentHeatBOS 热度值列表 + * @return 更新数量 + */ + int batchUpdateHeatByCommentIds(@Param("commentIds") List commentIds, + @Param("commentHeatBOS") List commentHeatBOS); } \ No newline at end of file diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java new file mode 100644 index 0000000..6cf0458 --- /dev/null +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java @@ -0,0 +1,22 @@ +package com.hanserwei.hannote.comment.biz.model.bo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CommentHeatBO { + /** + * 评论 ID + */ + private Long id; + + /** + * 热度值 + */ + private Double heat; +} \ No newline at end of file diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java new file mode 100644 index 0000000..e8c384c --- /dev/null +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java @@ -0,0 +1,40 @@ +package com.hanserwei.hannote.comment.biz.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class HeatCalculator { + + // 热度计算的权重配置 + private static final double LIKE_WEIGHT = 0.7; // 点赞权重 70% + private static final double REPLY_WEIGHT = 0.3; // 回复权重 30% + + public static BigDecimal calculateHeat(long likeCount, long replyCount) { + // 点赞数权重 70%,被回复数权重 30% + BigDecimal likeWeight = new BigDecimal(LIKE_WEIGHT); + BigDecimal replyWeight = new BigDecimal(REPLY_WEIGHT); + + // 转换点赞数和回复数为 BigDecimal + BigDecimal likeCountBD = new BigDecimal(likeCount); + BigDecimal replyCountBD = new BigDecimal(replyCount); + + // 计算热度 (点赞数*点赞权重 + 回复数*回复权重) + BigDecimal heat = likeCountBD.multiply(likeWeight).add(replyCountBD.multiply(replyWeight)); + + // 四舍五入保留两位小数 + return heat.setScale(2, RoundingMode.HALF_UP); + } + + public static void main(String[] args) { + int likeCount = 150; // 点赞数 + int replyCount = 10; // 被回复数 + + // 计算热度 + BigDecimal heat = calculateHeat(likeCount, replyCount); + + // 输出热度值 + System.out.println("Calculated Heat: " + heat); + } + + +} \ No newline at end of file diff --git a/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml b/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml index 7751a6d..eb904bc 100644 --- a/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml +++ b/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml @@ -19,18 +19,35 @@ + - - id, note_id, user_id, content_uuid, is_content_empty, image_url, `level`, reply_total, - like_total, parent_id, reply_comment_id, reply_user_id, is_top, create_time, update_time + + id, + note_id, + user_id, + content_uuid, + is_content_empty, + image_url, + `level`, + reply_total, + like_total, + parent_id, + reply_comment_id, + reply_user_id, + is_top, + create_time, + update_time, + child_comment_total