|
@@ -132,22 +132,63 @@ public class ArticlePromotionService {
|
|
|
return ciLow > 0;
|
|
|
}
|
|
|
|
|
|
+ private Double nullSafe(Double value) {
|
|
|
+ return value != null ? value : 0.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer nullSafe(Integer value) {
|
|
|
+ return value != null ? value : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<DatastatSortStrategy> promotionWithReadOpenFissionRate(double threshold, List<DatastatSortStrategy> list) {
|
|
|
+ // 参数校验
|
|
|
+ if (CollectionUtils.isEmpty(list)) {
|
|
|
+ throw new IllegalArgumentException("List cannot be empty");
|
|
|
+ }
|
|
|
+
|
|
|
+ return list.stream().filter(o -> {
|
|
|
+ // 处理分母部分(各级别之和)
|
|
|
+ double denominator =
|
|
|
+ nullSafe(o.getFirstLevel()) +
|
|
|
+ nullSafe(o.getSecondFirstLevel()) +
|
|
|
+ nullSafe(o.getThirdFirstLevel());
|
|
|
+
|
|
|
+ // 分母为零处理
|
|
|
+ if (denominator == 0) return false;
|
|
|
+
|
|
|
+ // 处理分子部分(所有裂变值求和)
|
|
|
+ double numerator =
|
|
|
+ nullSafe(o.getFission0()) + nullSafe(o.getFission1()) + nullSafe(o.getFission2()) +
|
|
|
+ nullSafe(o.getSecondFission0()) + nullSafe(o.getSecondFission1()) + nullSafe(o.getSecondFission2()) +
|
|
|
+ nullSafe(o.getThirdFission0()) + nullSafe(o.getThirdFission1()) + nullSafe(o.getThirdFission2());
|
|
|
+
|
|
|
+ // 处理可能为空的阅读率参数
|
|
|
+ double readRate = nullSafe(o.getReadRate());
|
|
|
+ double firstReadRate = nullSafe(o.getFirstReadRate());
|
|
|
+
|
|
|
+ // 计算完整公式
|
|
|
+ double result = readRate * firstReadRate * (numerator / denominator);
|
|
|
+
|
|
|
+ return result > threshold;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
public void articlePromotion(String pos, String way, String accountNickName, String tag,
|
|
|
Integer viewCountFilter, Double viewCountRateFilter, List<Integer> positionFilter) {
|
|
|
String today = DateUtils.getCurrentDateStr("yyyyMMdd");
|
|
|
String dateStrFilter = DateUtils.getBeforeDaysDateStr("yyyyMMdd", 10);
|
|
|
// 获取内部表现
|
|
|
List<DatastatSortStrategy> list;
|
|
|
+ list = longArticleBaseMapper.getArticlePromotionCandidates(10000, dateStrFilter, positionFilter);
|
|
|
+ // 使用阅读均值倍数+阅读量晋级
|
|
|
+ List<DatastatSortStrategy> listStrategyV1 = list.stream()
|
|
|
+ .filter(o -> o.getReadRate() >= viewCountRateFilter && o.getViewCount() >= viewCountFilter)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ List<String> StrategyV1WxSn = listStrategyV1.stream().map(DatastatSortStrategy::getWxSn).collect(Collectors.toList());
|
|
|
+ List<DatastatSortStrategy> listStrategyV2;
|
|
|
if (pos.equals("【2】")) {
|
|
|
- list = longArticleBaseMapper.getArticlePromotionCandidates(10000, dateStrFilter, positionFilter);
|
|
|
-
|
|
|
- // 使用阅读均值倍数+阅读量晋级
|
|
|
- List<DatastatSortStrategy> listStrategy1 = list.stream()
|
|
|
- .filter(o -> o.getReadRate() >= 1.33 && o.getViewCount() >= 100)
|
|
|
- .collect(Collectors.toList());
|
|
|
-
|
|
|
// 使用显著性检验晋级
|
|
|
- List<DatastatSortStrategy> listStrategy2 = list.stream()
|
|
|
+ listStrategyV2 = list.stream()
|
|
|
.filter(o -> {
|
|
|
try {
|
|
|
return isExperimentGroupStatisticallySuperior(o.getAvgViewCount() * 1.1 * 30, o.getFans() * 30,
|
|
@@ -159,26 +200,26 @@ public class ArticlePromotionService {
|
|
|
}
|
|
|
})
|
|
|
.collect(Collectors.toList());
|
|
|
-
|
|
|
- list = Stream.concat(listStrategy1.stream(), listStrategy2.stream())
|
|
|
- .collect(Collectors.collectingAndThen(
|
|
|
- Collectors.toMap(
|
|
|
- DatastatSortStrategy::getWxSn,
|
|
|
- Function.identity(),
|
|
|
- (existing, replacement) -> existing
|
|
|
- ),
|
|
|
- map -> new ArrayList<>(map.values())
|
|
|
- ));
|
|
|
} else {
|
|
|
- list = longArticleBaseMapper.getArticlePromotion(viewCountFilter, viewCountRateFilter,
|
|
|
- 10000, dateStrFilter, positionFilter);
|
|
|
+ // 使用新规则过滤
|
|
|
+ listStrategyV2 = promotionWithReadOpenFissionRate(0.01, list);
|
|
|
}
|
|
|
+ listStrategyV2 = listStrategyV2.stream().filter(o -> !StrategyV1WxSn.contains(o.getWxSn())).collect(Collectors.toList());
|
|
|
+
|
|
|
+ //策略 1 晋级
|
|
|
+ filterAndAdd2CrawlerPlan(listStrategyV1, "promotionStrategyV1", accountNickName, tag, pos, way, today);
|
|
|
+
|
|
|
+ //策略 2 晋级
|
|
|
+ filterAndAdd2CrawlerPlan(listStrategyV2, "promotionStrategyV2", accountNickName, tag, pos, way, today);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void filterAndAdd2CrawlerPlan(List<DatastatSortStrategy> list, String promotionStrategy, String accountNickName, String tag, String pos, String way, String today) {
|
|
|
list = filterEarlyContent(list, true);
|
|
|
log.info("优质{}文章数量: {}", accountNickName, list.size());
|
|
|
List<DatastatSortStrategy> distinct = filterSameTitle(list);
|
|
|
distinct.sort(Comparator.comparing(DatastatSortStrategy::getDateStr, Comparator.reverseOrder()));
|
|
|
log.info("优质{}文章数量(去重后): {}", accountNickName, distinct.size());
|
|
|
- addUrlListToAccount(accountNickName, distinct, pos, way, today, tag);
|
|
|
+ addUrlListToAccount(accountNickName, distinct, pos, way, today, tag, promotionStrategy);
|
|
|
}
|
|
|
|
|
|
private List<DatastatSortStrategy> filterEarlyContent(List<DatastatSortStrategy> list, Boolean filterVideoPool) {
|
|
@@ -217,7 +258,7 @@ public class ArticlePromotionService {
|
|
|
}
|
|
|
|
|
|
private void addUrlListToAccount(String accountNickName, List<DatastatSortStrategy> list, String pos, String way,
|
|
|
- String today, String tag) {
|
|
|
+ String today, String tag, String promotionStrategy) {
|
|
|
List<String> urlList = list.stream().map(DatastatSortStrategy::getLink).collect(Collectors.toList());
|
|
|
if (!produceConfig.containsKey(accountNickName)) {
|
|
|
log.info("account_nickname not in produceConfig: " + accountNickName);
|
|
@@ -264,7 +305,7 @@ public class ArticlePromotionService {
|
|
|
}
|
|
|
}
|
|
|
if (CollectionUtils.isNotEmpty(filterUrlList)) {
|
|
|
- String planName = String.format("%d_%s_%s_%s【%s】_%s", filterUrlList.size(), today, accountNickName, pos, way, today);
|
|
|
+ String planName = String.format("%d_%s_%s_%s【%s】_%s_%s", filterUrlList.size(), today, accountNickName, pos, way, today, promotionStrategy);
|
|
|
log.info("url_len: " + list.size() + ", " + filterUrlList.size());
|
|
|
IdNameVO<String> planInfo = aigcCrawlerPlanSaveService.createArticleUrlPlan(planName, filterUrlList, tag, CrawlerModeEnum.ContentIDs.getVal());
|
|
|
if (StringUtils.hasText(produceId)) {
|
|
@@ -274,14 +315,14 @@ public class ArticlePromotionService {
|
|
|
log.info("{}, {}, produce plan not exist: {}, {}, {}", planInfo.getName(), planInfo.getId(), accountNickName, pos, way);
|
|
|
}
|
|
|
if (CollectionUtils.isNotEmpty(publishContentIds)) {
|
|
|
- String planName = String.format("%d_%s_%s_%s【%s】_%s", publishContentIds.size(), today, accountNickName, pos, way, today);
|
|
|
+ String planName = String.format("%d_%s_%s_%s【%s】_%s_%s", publishContentIds.size(), today, accountNickName, pos, way, today, promotionStrategy);
|
|
|
IdNameVO<String> planInfo = aigcCrawlerPlanSaveService.createArticleUrlPlan(planName, publishContentIds, tag, CrawlerModeEnum.PublishContentIds.getVal());
|
|
|
if (StringUtils.hasText(produceId)) {
|
|
|
String inputSourceLabel = String.format("原始帖子-长文-微信公众号-内容添加计划-%s", planInfo.getName());
|
|
|
articleAddDependPlan(produceId, planInfo.getId(), inputSourceLabel, ProducePlanInputSourceTypeEnum.contentPlan.getVal());
|
|
|
}
|
|
|
}
|
|
|
- sendFeishuJobFinishMessage(accountNickName, filterUrlList.size(), publishContentIds.size());
|
|
|
+ sendFeishuJobFinishMessage(accountNickName, filterUrlList.size(), publishContentIds.size(), promotionStrategy);
|
|
|
} catch (Exception e) {
|
|
|
log.error("articlePromotion error: ", e);
|
|
|
FeishuMessageSender.sendWebHookMessage(FeishuRobotIdEnum.DAILY.getRobotId(),
|
|
@@ -292,13 +333,14 @@ public class ArticlePromotionService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void sendFeishuJobFinishMessage(String accountNickName, Integer urlListSize, Integer contentListSize) {
|
|
|
+ private void sendFeishuJobFinishMessage(String accountNickName, Integer urlListSize, Integer contentListSize, String promotionStrategy) {
|
|
|
log.info("articlePromotion finish: 晋级任务:{}, id晋级数量:{}, url晋级数量:{}", accountNickName, contentListSize, urlListSize);
|
|
|
FeishuMessageSender.sendWebHookMessage(FeishuRobotIdEnum.DAILY.getRobotId(),
|
|
|
"【文章晋级job完成】\n" +
|
|
|
"晋级任务:" + accountNickName + "\n" +
|
|
|
"id晋级数量:" + contentListSize + "\n" +
|
|
|
- "url晋级数量:" + urlListSize + "\n");
|
|
|
+ "url晋级数量:" + urlListSize + "\n" +
|
|
|
+ "晋级策略: " + promotionStrategy + "\n");
|
|
|
}
|
|
|
|
|
|
private List<ProduceContentListItemVO> getProduceContentList(String accountNickName, String pos, String way) {
|