|
@@ -649,8 +649,8 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
return getHotSourcePaged(param, user);
|
|
return getHotSourcePaged(param, user);
|
|
|
}
|
|
}
|
|
|
List<VideoContentItemVO> list = SOURCE_PRIOR.equals(source)
|
|
List<VideoContentItemVO> list = SOURCE_PRIOR.equals(source)
|
|
|
- ? fetchPriorCandidates(user, DEMAND_CANDIDATE_LIMIT)
|
|
|
|
|
- : fetchPosteriorCandidates(user, DEMAND_CANDIDATE_LIMIT);
|
|
|
|
|
|
|
+ ? fetchPriorCandidates(param, user, DEMAND_CANDIDATE_LIMIT)
|
|
|
|
|
+ : fetchPosteriorCandidates(param, user, DEMAND_CANDIDATE_LIMIT);
|
|
|
for (VideoContentItemVO v : list) {
|
|
for (VideoContentItemVO v : list) {
|
|
|
v.setSource(source);
|
|
v.setSource(source);
|
|
|
}
|
|
}
|
|
@@ -705,8 +705,8 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
* 用 (userId ^ 当天日期) 作为种子,保证同一用户当天翻页顺序一致、刷新一致。
|
|
* 用 (userId ^ 当天日期) 作为种子,保证同一用户当天翻页顺序一致、刷新一致。
|
|
|
*/
|
|
*/
|
|
|
private Page<VideoContentItemVO> getInterleavedPage(VideoContentListParam param, ContentPlatformAccount user) {
|
|
private Page<VideoContentItemVO> getInterleavedPage(VideoContentListParam param, ContentPlatformAccount user) {
|
|
|
- List<VideoContentItemVO> prior = fetchPriorCandidates(user, DEMAND_CANDIDATE_LIMIT);
|
|
|
|
|
- List<VideoContentItemVO> posterior = fetchPosteriorCandidates(user, DEMAND_CANDIDATE_LIMIT);
|
|
|
|
|
|
|
+ List<VideoContentItemVO> prior = fetchPriorCandidates(param, user, DEMAND_CANDIDATE_LIMIT);
|
|
|
|
|
+ List<VideoContentItemVO> posterior = fetchPosteriorCandidates(param, user, DEMAND_CANDIDATE_LIMIT);
|
|
|
List<VideoContentItemVO> hot = fetchHotCandidates(param, user, HOT_CANDIDATE_LIMIT);
|
|
List<VideoContentItemVO> hot = fetchHotCandidates(param, user, HOT_CANDIDATE_LIMIT);
|
|
|
for (VideoContentItemVO v : prior) v.setSource(SOURCE_PRIOR);
|
|
for (VideoContentItemVO v : prior) v.setSource(SOURCE_PRIOR);
|
|
|
for (VideoContentItemVO v : posterior) v.setSource(SOURCE_POSTERIOR);
|
|
for (VideoContentItemVO v : posterior) v.setSource(SOURCE_POSTERIOR);
|
|
@@ -763,18 +763,27 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
* 先验池:A 段 dimension='传播头部' → B 段 其余 dimension。
|
|
* 先验池:A 段 dimension='传播头部' → B 段 其余 dimension。
|
|
|
* 每段按 (point_type, standard_element) 分组,组按 total_rov DESC、组内 score DESC 取前 K;段间拼接 + video_id 去重。
|
|
* 每段按 (point_type, standard_element) 分组,组按 total_rov DESC、组内 score DESC 取前 K;段间拼接 + video_id 去重。
|
|
|
*/
|
|
*/
|
|
|
- private List<VideoContentItemVO> fetchPriorCandidates(ContentPlatformAccount user, int limit) {
|
|
|
|
|
|
|
+ private List<VideoContentItemVO> fetchPriorCandidates(VideoContentListParam param, ContentPlatformAccount user, int limit) {
|
|
|
String dt = demandVideoMapperExt.getMaxDt();
|
|
String dt = demandVideoMapperExt.getMaxDt();
|
|
|
if (!StringUtils.hasText(dt)) {
|
|
if (!StringUtils.hasText(dt)) {
|
|
|
return new ArrayList<>();
|
|
return new ArrayList<>();
|
|
|
}
|
|
}
|
|
|
String crowdSegment = user.getChannel();
|
|
String crowdSegment = user.getChannel();
|
|
|
|
|
+ String ghName = StringUtils.hasText(param.getGhName()) ? param.getGhName() : null;
|
|
|
int fetchLimit = Math.max(limit * 3, DEMAND_CANDIDATE_LIMIT);
|
|
int fetchLimit = Math.max(limit * 3, DEMAND_CANDIDATE_LIMIT);
|
|
|
|
|
|
|
|
List<ContentPlatformDemandVideo> stageA = demandVideoMapperExt.selectForRecommend(
|
|
List<ContentPlatformDemandVideo> stageA = demandVideoMapperExt.selectForRecommend(
|
|
|
- dt, crowdSegment, DEMAND_STRATEGY_PRIOR, PRIOR_PREMIUM_DIMENSION, null, null, fetchLimit, false);
|
|
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_PRIOR, PRIOR_PREMIUM_DIMENSION, null, null, ghName, fetchLimit, false);
|
|
|
List<ContentPlatformDemandVideo> stageB = demandVideoMapperExt.selectForRecommend(
|
|
List<ContentPlatformDemandVideo> stageB = demandVideoMapperExt.selectForRecommend(
|
|
|
- dt, crowdSegment, DEMAND_STRATEGY_PRIOR, null, PRIOR_PREMIUM_DIMENSION, null, fetchLimit, false);
|
|
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_PRIOR, null, PRIOR_PREMIUM_DIMENSION, null, ghName, fetchLimit, false);
|
|
|
|
|
+
|
|
|
|
|
+ // 退化:该 ghName 在两阶段都无数据 → 退回渠道粒度
|
|
|
|
|
+ if (ghName != null && stageA.isEmpty() && stageB.isEmpty()) {
|
|
|
|
|
+ stageA = demandVideoMapperExt.selectForRecommend(
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_PRIOR, PRIOR_PREMIUM_DIMENSION, null, null, null, fetchLimit, false);
|
|
|
|
|
+ stageB = demandVideoMapperExt.selectForRecommend(
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_PRIOR, null, PRIOR_PREMIUM_DIMENSION, null, null, fetchLimit, false);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
Function<ContentPlatformDemandVideo, String> keyFn = r ->
|
|
Function<ContentPlatformDemandVideo, String> keyFn = r ->
|
|
|
(r.getPointType() == null ? "" : r.getPointType()) + "\u0001"
|
|
(r.getPointType() == null ? "" : r.getPointType()) + "\u0001"
|
|
@@ -789,18 +798,27 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
* 后验池:A 段 "绝对高效率" → B 段 "相对裂变率"。
|
|
* 后验池:A 段 "绝对高效率" → B 段 "相对裂变率"。
|
|
|
* 每段按 demand_content_id 分组,组按 total_rov DESC、组内 score DESC 取前 K;段间拼接 + video_id 去重。
|
|
* 每段按 demand_content_id 分组,组按 total_rov DESC、组内 score DESC 取前 K;段间拼接 + video_id 去重。
|
|
|
*/
|
|
*/
|
|
|
- private List<VideoContentItemVO> fetchPosteriorCandidates(ContentPlatformAccount user, int limit) {
|
|
|
|
|
|
|
+ private List<VideoContentItemVO> fetchPosteriorCandidates(VideoContentListParam param, ContentPlatformAccount user, int limit) {
|
|
|
String dt = demandVideoMapperExt.getMaxDt();
|
|
String dt = demandVideoMapperExt.getMaxDt();
|
|
|
if (!StringUtils.hasText(dt)) {
|
|
if (!StringUtils.hasText(dt)) {
|
|
|
return new ArrayList<>();
|
|
return new ArrayList<>();
|
|
|
}
|
|
}
|
|
|
String crowdSegment = user.getChannel();
|
|
String crowdSegment = user.getChannel();
|
|
|
|
|
+ String ghName = StringUtils.hasText(param.getGhName()) ? param.getGhName() : null;
|
|
|
int fetchLimit = Math.max(limit * 3, DEMAND_CANDIDATE_LIMIT);
|
|
int fetchLimit = Math.max(limit * 3, DEMAND_CANDIDATE_LIMIT);
|
|
|
|
|
|
|
|
List<ContentPlatformDemandVideo> stageAbs = demandVideoMapperExt.selectForRecommend(
|
|
List<ContentPlatformDemandVideo> stageAbs = demandVideoMapperExt.selectForRecommend(
|
|
|
- dt, crowdSegment, DEMAND_STRATEGY_POSTERIOR, null, null, POSTERIOR_FILTER_ABS_LIKE, fetchLimit, true);
|
|
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_POSTERIOR, null, null, POSTERIOR_FILTER_ABS_LIKE, ghName, fetchLimit, true);
|
|
|
List<ContentPlatformDemandVideo> stageRel = demandVideoMapperExt.selectForRecommend(
|
|
List<ContentPlatformDemandVideo> stageRel = demandVideoMapperExt.selectForRecommend(
|
|
|
- dt, crowdSegment, DEMAND_STRATEGY_POSTERIOR, null, null, POSTERIOR_FILTER_REL_LIKE, fetchLimit, true);
|
|
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_POSTERIOR, null, null, POSTERIOR_FILTER_REL_LIKE, ghName, fetchLimit, true);
|
|
|
|
|
+
|
|
|
|
|
+ // 退化:该 ghName 在两阶段都无数据 → 退回渠道粒度
|
|
|
|
|
+ if (ghName != null && stageAbs.isEmpty() && stageRel.isEmpty()) {
|
|
|
|
|
+ stageAbs = demandVideoMapperExt.selectForRecommend(
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_POSTERIOR, null, null, POSTERIOR_FILTER_ABS_LIKE, null, fetchLimit, true);
|
|
|
|
|
+ stageRel = demandVideoMapperExt.selectForRecommend(
|
|
|
|
|
+ dt, crowdSegment, DEMAND_STRATEGY_POSTERIOR, null, null, POSTERIOR_FILTER_REL_LIKE, null, fetchLimit, true);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
Function<ContentPlatformDemandVideo, String> keyFn = r ->
|
|
Function<ContentPlatformDemandVideo, String> keyFn = r ->
|
|
|
r.getDemandContentId() == null ? "" : r.getDemandContentId();
|
|
r.getDemandContentId() == null ? "" : r.getDemandContentId();
|