feat(comment): 新增评论热度计算与更新功能
- 在评论数据对象中新增 childCommentTotal 和 heat 字段 - 扩展 CommentDOMapper 支持批量更新评论热度值 - 新增 CommentHeatBO 类用于封装评论热度信息 - 实现基于点赞数和回复数的热度值计算工具类 HeatCalculator - 添加 RocketMQ 消费者异步处理评论热度更新消息 - 引入 buffer-trigger依赖实现消息聚合发送 - 扩展 JsonUtils 工具类支持 Set 类型反序列化 - 新增 MQ 常量 TOPIC_COMMENT_HEAT_UPDATE用于热度更新主题 - 修改 SQL 脚本增加 heat 字段并设置默认值- 更新测试接口请求参数内容以适配新逻辑
This commit is contained in:
@@ -12,4 +12,9 @@ public interface MQConstants {
|
||||
*/
|
||||
String TOPIC_COUNT_NOTE_COMMENT = "CountNoteCommentTopic";
|
||||
|
||||
/**
|
||||
* Topic: 评论热度值更新
|
||||
*/
|
||||
String TOPIC_COMMENT_HEAT_UPDATE = "CommentHeatUpdateTopic";
|
||||
|
||||
}
|
||||
@@ -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<String> {
|
||||
|
||||
@Resource
|
||||
private CommentDOMapper commentDOMapper;
|
||||
|
||||
private final BufferTrigger<String> bufferTrigger = BufferTrigger.<String>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<String> bodys) {
|
||||
log.info("==> 【评论热度值计算】聚合消息, size: {}", bodys.size());
|
||||
log.info("==> 【评论热度值计算】聚合消息, {}", JsonUtils.toJsonString(bodys));
|
||||
|
||||
// 将聚合后的消息体 Json 转 Set<Long>, 去重相同的评论 ID, 防止重复计算
|
||||
Set<Long> commentIds = Sets.newHashSet();
|
||||
bodys.forEach(body -> {
|
||||
try {
|
||||
Set<Long> list = JsonUtils.parseSet(body, Long.class);
|
||||
commentIds.addAll(list);
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
});
|
||||
|
||||
log.info("==> 去重后的评论 ID: {}", commentIds);
|
||||
|
||||
// 批量查询评论
|
||||
List<CommentDO> commentDOS = commentDOMapper.selectByCommentIds(commentIds.stream().toList());
|
||||
|
||||
// 评论 ID
|
||||
List<Long> ids = Lists.newArrayList();
|
||||
// 热度值 BO
|
||||
List<CommentHeatBO> 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);
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,12 @@ public class CommentDO {
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 下级评论总数
|
||||
*/
|
||||
@TableField(value = "child_comment_total")
|
||||
private Long childCommentTotal;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
|
||||
@@ -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<CommentDO> {
|
||||
* @return 插入数量
|
||||
*/
|
||||
int batchInsert(@Param("comments") List<CommentBO> comments);
|
||||
|
||||
/**
|
||||
* 批量更新热度值
|
||||
*
|
||||
* @param commentIds 评论 ID 列表
|
||||
* @param commentHeatBOS 热度值列表
|
||||
* @return 更新数量
|
||||
*/
|
||||
int batchUpdateHeatByCommentIds(@Param("commentIds") List<Long> commentIds,
|
||||
@Param("commentHeatBOS") List<CommentHeatBO> commentHeatBOS);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -19,18 +19,35 @@
|
||||
<result column="is_top" jdbcType="TINYINT" property="isTop" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||
<result column="child_comment_total" jdbcType="BIGINT" property="childCommentTotal"/>
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
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
|
||||
<!--@mbg.generated-->
|
||||
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
|
||||
</sql>
|
||||
|
||||
<select id="selectByCommentIds" resultMap="BaseResultMap" parameterType="list">
|
||||
select id,
|
||||
level,
|
||||
parent_id,
|
||||
user_id
|
||||
user_id,
|
||||
child_comment_total,
|
||||
like_total
|
||||
from t_comment
|
||||
where id in
|
||||
<foreach collection="commentIds" open="(" separator="," close=")" item="commentId">
|
||||
@@ -52,4 +69,17 @@
|
||||
, #{comment.updateTime})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<update id="batchUpdateHeatByCommentIds" parameterType="map">
|
||||
UPDATE t_comment
|
||||
SET heat = CASE id
|
||||
<foreach collection="commentHeatBOS" item="bo" separator="">
|
||||
WHEN #{bo.id} THEN #{bo.heat}
|
||||
</foreach>
|
||||
ELSE heat END
|
||||
WHERE id IN
|
||||
<foreach collection="commentIds" item="commentId" open="(" close=")" separator=",">
|
||||
#{commentId}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user