top推荐

This commit is contained in:
2025-11-25 16:00:09 +08:00
parent 24c5188eb0
commit 48ee6442b3
6 changed files with 414 additions and 138 deletions

View File

@@ -289,7 +289,24 @@ INSERT INTO `tb_crontab_task_meta` (
'topRecommendTask',
'execute',
'',
'[]',
'[
{
"name": "viewNum",
"description": "按浏览量取多少条",
"type": "InputNumber",
"valueType": "Integer",
"value": 10,
"required": true
},
{
"name": "timeNum",
"description": "按时间取多少条",
"type": "InputNumber",
"valueType": "Integer",
"value": 10,
"required": true
}
]',
0,
9,
'system',
@@ -310,7 +327,7 @@ INSERT INTO `tb_crontab_task` (
'topRecommendTask',
'0 0 1 * * ?',
'execute',
'{}',
'{"viewNum":10,"timeNum":10}',
1,
'system',
NOW()

View File

@@ -43,49 +43,108 @@ public class TopRecommendTask extends BaseTask {
logger.info("开始执行热门资源推荐任务");
try {
// 从参数中获取配置浏览量和时间排序各取多少条默认都为10
Integer viewNum = taskParams != null ? taskParams.getParamAsInt("viewNum") : null;
Integer timeNum = taskParams != null ? taskParams.getParamAsInt("timeNum") : null;
if (viewNum == null || viewNum <= 0) {
viewNum = 10;
}
if (timeNum == null || timeNum <= 0) {
timeNum = 10;
}
// 1. 清除旧的热门推荐recommend_type = 1
// clearOldRecommends();
// 2. 获取浏览量前10的资源
List<ResourceVO> topViewCountResources = getTopResourcesByViewCount(10);
logger.info("获取到浏览量前10的资源数量: {}", topViewCountResources.size());
// 3. 获取发布时间前10的资源
List<ResourceVO> topPublishTimeResources = getTopResourcesByPublishTime(10);
logger.info("获取到发布时间前10的资源数量: {}", topPublishTimeResources.size());
// 4. 合并并去重(使用 Set 确保资源ID唯一
// 2. 合并并去重(使用 Set 确保资源ID唯一并处理补位逻辑
Set<String> resourceIds = new HashSet<>();
List<TbResourceRecommend> recommendList = new ArrayList<>();
int orderNum = 1;
// 添加浏览量前10
for (ResourceVO vo : topViewCountResources) {
if (vo.getResource() != null && resourceIds.add(vo.getResource().getResourceID())) {
recommendList.add(createRecommend(vo.getResource().getResourceID(), orderNum++));
}
}
int viewAdded = 0;
int timeAdded = 0;
// 添加发布时间前10
for (ResourceVO vo : topPublishTimeResources) {
if (vo.getResource() != null && resourceIds.add(vo.getResource().getResourceID())) {
recommendList.add(createRecommend(vo.getResource().getResourceID(), orderNum++));
}
}
// 4.1 按浏览量补足 viewNum 条,采用分页方式逐页向后拿
int viewPageNumber = 1;
int viewPageSize = viewNum; // 每页拉 viewNum 条
// 5. 批量插入新推荐
if (!recommendList.isEmpty()) {
for (TbResourceRecommend recommend : recommendList) {
ResultDomain<TbResourceRecommend> addResult = resourceRecommendService.addRecommend(recommend);
if (!addResult.isSuccess()) {
logger.warn("插入推荐失败: 资源ID={}, 原因={}", recommend.getResourceID(), addResult.getMessage());
while (viewAdded < viewNum) {
List<ResourceVO> viewPageList = getViewCountPage(viewPageNumber, viewPageSize);
if (viewPageList == null || viewPageList.isEmpty()) {
logger.info("按浏览量补位时已经没有更多候选数据page={}", viewPageNumber);
break;
}
for (ResourceVO vo : viewPageList) {
if (viewAdded >= viewNum) {
break;
}
if (vo.getResource() == null) {
continue;
}
String resourceId = vo.getResource().getResourceID();
// 已经是热门推荐了,跳过,向后拿下一条
if (isAlreadyHotRecommend(resourceId)) {
logger.info("资源 {} 已经是热门推荐(按浏览量列表),跳过并向后补位", resourceId);
continue;
}
// 本次任务中已选过(可能来自另外一个列表),跳过并向后拿
if (!resourceIds.add(resourceId)) {
continue;
}
recommendList.add(createRecommend(resourceId, orderNum++));
viewAdded++;
}
logger.info("成功插入{}条热门推荐记录", recommendList.size());
} else {
logger.warn("没有找到符合条件的资源,未插入推荐记录");
viewPageNumber++;
}
// 4.2 按发布时间补足 timeNum 条,采用分页方式逐页向后拿
int timePageNumber = 1;
int timePageSize = timeNum; // 每页拉 timeNum 条,基本一两页就足够
while (timeAdded < timeNum) {
List<ResourceVO> pageList = getPublishTimePage(timePageNumber, timePageSize);
if (pageList == null || pageList.isEmpty()) {
logger.info("按时间补位时已经没有更多候选数据page={}", timePageNumber);
break;
}
for (ResourceVO vo : pageList) {
if (timeAdded >= timeNum) {
break;
}
if (vo.getResource() == null) {
continue;
}
String resourceId = vo.getResource().getResourceID();
// 已经是热门推荐了,跳过,向后拿下一条
if (isAlreadyHotRecommend(resourceId)) {
logger.info("资源 {} 已经是热门推荐(按时间列表),跳过并向后补位", resourceId);
continue;
}
// 本次任务中已选过(例如在浏览量列表中已经加入),跳过并向后拿
if (!resourceIds.add(resourceId)) {
continue;
}
recommendList.add(createRecommend(resourceId, orderNum++));
timeAdded++;
}
timePageNumber++;
}
logger.info("热门资源推荐任务执行成功,共推荐{}个资源", resourceIds.size());
} catch (Exception e) {
@@ -104,21 +163,20 @@ public class TopRecommendTask extends BaseTask {
}
/**
* 获取浏览量前N的资源
* 获取浏览量排序的一页资源,用于分页向后补位
*/
private List<ResourceVO> getTopResourcesByViewCount(int limit) {
private List<ResourceVO> getViewCountPage(int pageNumber, int pageSize) {
TbResource filter = new TbResource();
filter.setStatus(1); // 只查询已发布的资源
// 设置排序:按浏览量降序
// 设置排序:按浏览量降序,再按发布时间降序
List<BaseDTO.OrderType> orderTypes = new ArrayList<>();
orderTypes.add(new BaseDTO.OrderType("view_count", "DESC"));
orderTypes.add(new BaseDTO.OrderType("publish_time", "DESC"));
filter.setOrderTypes(orderTypes);
PageParam pageParam = new PageParam();
pageParam.setPageSize(limit);
pageParam.setOffset(0L);
pageParam.setPageSize(pageSize);
ResultDomain<ResourceVO> result = resourceService.getResourcePageOrder(filter, pageParam);
if (result.isSuccess() && result.getDataList() != null) {
@@ -128,21 +186,20 @@ public class TopRecommendTask extends BaseTask {
}
/**
* 获取发布时间前N的资源(最新发布)
* 获取发布时间排序的一页资源(最新发布),用于分页向后补位
*/
private List<ResourceVO> getTopResourcesByPublishTime(int limit) {
private List<ResourceVO> getPublishTimePage(int pageNumber, int pageSize) {
TbResource filter = new TbResource();
filter.setStatus(1); // 只查询已发布的资源
// 设置排序:按发布时间降序
List<BaseDTO.OrderType> orderTypes = new ArrayList<>();
orderTypes.add(new BaseDTO.OrderType("publish_time", "DESC"));
orderTypes.add(new BaseDTO.OrderType("create_time", "DESC"));
filter.setOrderTypes(orderTypes);
PageParam pageParam = new PageParam();
pageParam.setPageSize(limit);
pageParam.setOffset(0L);
pageParam.setPageSize(pageSize);
ResultDomain<ResourceVO> result = resourceService.getResourcePageOrder(filter, pageParam);
if (result.isSuccess() && result.getDataList() != null) {
@@ -165,4 +222,19 @@ public class TopRecommendTask extends BaseTask {
recommend.setDeleted(false);
return recommend;
}
/**
* 判断资源是否已经在热门推荐中recommend_type = 1
*/
private boolean isAlreadyHotRecommend(String resourceId) {
try {
ResultDomain<Boolean> result = resourceRecommendService.isResourceRecommendedByType(resourceId, 1);
if (result != null && result.isSuccess() && result.getData() != null) {
return Boolean.TRUE.equals(result.getData());
}
} catch (Exception e) {
logger.error("检查资源是否已为热门推荐失败, resourceId={}", resourceId, e);
}
return false;
}
}