|
|
@@ -644,21 +644,50 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
new PriorPoolConfig(PriorDimensionEnum.PREMIUM, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.SCENE, true),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.GROWTH, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.SCENE, true),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.DISTRIBUTION, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.SCENE, true),
|
|
|
+ new PriorPoolConfig(PriorDimensionEnum.GROWTH_DISTRIBUTION, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.SCENE, true),
|
|
|
// 策略2: 人群需求*特征点*向量匹配
|
|
|
new PriorPoolConfig(PriorDimensionEnum.PREMIUM, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.GROWTH, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.DISTRIBUTION, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
+ new PriorPoolConfig(PriorDimensionEnum.GROWTH_DISTRIBUTION, DemandTypeEnum.STANDARD, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
// 策略3: 人群需求*特征点泛化*向量匹配
|
|
|
new PriorPoolConfig(PriorDimensionEnum.PREMIUM, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.GROWTH, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.DISTRIBUTION, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
+ new PriorPoolConfig(PriorDimensionEnum.GROWTH_DISTRIBUTION, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.VECTOR_SIMILARITY, false),
|
|
|
// 策略4: 人群需求*特征点泛化*精准匹配
|
|
|
new PriorPoolConfig(PriorDimensionEnum.PREMIUM, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.PRECISION, false),
|
|
|
new PriorPoolConfig(PriorDimensionEnum.GROWTH, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.PRECISION, false),
|
|
|
- new PriorPoolConfig(PriorDimensionEnum.DISTRIBUTION, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.PRECISION, false)
|
|
|
+ new PriorPoolConfig(PriorDimensionEnum.DISTRIBUTION, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.PRECISION, false),
|
|
|
+ new PriorPoolConfig(PriorDimensionEnum.GROWTH_DISTRIBUTION, DemandTypeEnum.GENERALIZED, DemandMatchMethodEnum.PRECISION, false)
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 按渠道返回人群需求池配置,不同渠道排除特定策略组合。
|
|
|
+ */
|
|
|
+ private static List<PriorPoolConfig> getPriorPoolConfigs(DemandChannelEnum channel) {
|
|
|
+ List<PriorPoolConfig> configs = new ArrayList<>(PRIOR_POOL_CONFIGS);
|
|
|
+ if (channel == DemandChannelEnum.GZH_JIZHUAN) {
|
|
|
+ // 公众号即转合作:干掉 增长头部*场景已看、传播头部*场景已看
|
|
|
+ configs.removeIf(cfg ->
|
|
|
+ (cfg.dimension == PriorDimensionEnum.GROWTH && cfg.demandType == DemandTypeEnum.STANDARD && cfg.matchMethod == DemandMatchMethodEnum.SCENE)
|
|
|
+ || (cfg.dimension == PriorDimensionEnum.PREMIUM && cfg.demandType == DemandTypeEnum.STANDARD && cfg.matchMethod == DemandMatchMethodEnum.SCENE));
|
|
|
+ } else if (channel == DemandChannelEnum.XCX) {
|
|
|
+ // 小程序投流:干掉 增长头部*向量匹配、增长头部*泛化*精准匹配、传播头部*场景已看
|
|
|
+ configs.removeIf(cfg ->
|
|
|
+ (cfg.dimension == PriorDimensionEnum.GROWTH && cfg.demandType == DemandTypeEnum.STANDARD && cfg.matchMethod == DemandMatchMethodEnum.VECTOR_SIMILARITY)
|
|
|
+ || (cfg.dimension == PriorDimensionEnum.GROWTH && cfg.demandType == DemandTypeEnum.GENERALIZED && cfg.matchMethod == DemandMatchMethodEnum.PRECISION)
|
|
|
+ || (cfg.dimension == PriorDimensionEnum.PREMIUM && cfg.demandType == DemandTypeEnum.STANDARD && cfg.matchMethod == DemandMatchMethodEnum.SCENE));
|
|
|
+ } else if (channel == DemandChannelEnum.QW) {
|
|
|
+ // 企微合作:干掉 传播头部*泛化*精准匹配、传播分发*泛化*精准匹配
|
|
|
+ configs.removeIf(cfg ->
|
|
|
+ (cfg.dimension == PriorDimensionEnum.PREMIUM && cfg.demandType == DemandTypeEnum.GENERALIZED && cfg.matchMethod == DemandMatchMethodEnum.PRECISION)
|
|
|
+ || (cfg.dimension == PriorDimensionEnum.DISTRIBUTION && cfg.demandType == DemandTypeEnum.GENERALIZED && cfg.matchMethod == DemandMatchMethodEnum.PRECISION));
|
|
|
+ }
|
|
|
+ return configs;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 人群需求单池配置
|
|
|
*/
|
|
|
@@ -739,6 +768,15 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
return matchExposurePv == null || matchExposurePv > minExposurePv;
|
|
|
}
|
|
|
|
|
|
+ static boolean passesSearchDemandRovFilter(String matchMethod, Double rov, Double sceneSumRov,
|
|
|
+ double demandMinRov, double priorSceneMinSumRov) {
|
|
|
+ if (DemandMatchMethodEnum.SCENE.getValue().equals(matchMethod)) {
|
|
|
+ return rov != null && rov > 0
|
|
|
+ && sceneSumRov != null && sceneSumRov >= priorSceneMinSumRov;
|
|
|
+ }
|
|
|
+ return rov != null && rov >= demandMinRov;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public Page<VideoContentItemVO> getVideoContentList(VideoContentListParam param) {
|
|
|
ContentPlatformAccount user = LoginUserContext.getUser();
|
|
|
@@ -772,12 +810,13 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
String dt = demandVideoMapperExt.getMaxDt(channel == null ? null : channel.getValue());
|
|
|
List<VideoContentItemVO> list;
|
|
|
if (VideoContentSource.PRIOR == source) {
|
|
|
- // 人群需求池并行拉取, 按 PRIOR_POOL_CONFIGS 配置
|
|
|
- int poolCount = PRIOR_POOL_CONFIGS.size();
|
|
|
+ // 人群需求池并行拉取, 按渠道差异化配置
|
|
|
+ List<PriorPoolConfig> configs = getPriorPoolConfigs(channel);
|
|
|
+ int poolCount = configs.size();
|
|
|
ExecutorService executor = Executors.newFixedThreadPool(poolCount);
|
|
|
try {
|
|
|
List<Future<List<VideoContentItemVO>>> futures = new ArrayList<>(poolCount);
|
|
|
- for (PriorPoolConfig cfg : PRIOR_POOL_CONFIGS) {
|
|
|
+ for (PriorPoolConfig cfg : configs) {
|
|
|
futures.add(executor.submit(cfg.scene
|
|
|
? () -> fetchPriorSceneCandidates(param, user, DEMAND_CANDIDATE_LIMIT, channel, dt, cfg.dimension, cfg.demandType, cfg.matchMethod)
|
|
|
: () -> fetchPriorPool(param, user, DEMAND_CANDIDATE_LIMIT, channel, dt, cfg.dimension, cfg.demandType, cfg.matchMethod)));
|
|
|
@@ -921,16 +960,18 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
* 用 (userId ^ 当天日期) 作为种子,保证同一用户当天翻页顺序一致、刷新一致。
|
|
|
*/
|
|
|
private Page<VideoContentItemVO> getInterleavedPage(VideoContentListParam param, ContentPlatformAccount user) {
|
|
|
- int priorCount = PRIOR_POOL_CONFIGS.size();
|
|
|
- int totalCount = priorCount + 2; // + posterior + hot
|
|
|
// 杠杆1: channel + dt 每请求只解析一次,传入各 demand 池(hot 池用自己的 dt,不受影响)
|
|
|
DemandChannelEnum channel = resolveChannelName(param);
|
|
|
String dt = demandVideoMapperExt.getMaxDt(channel == null ? null : channel.getValue());
|
|
|
+ // 人群需求池按渠道差异化配置
|
|
|
+ List<PriorPoolConfig> priorConfigs = getPriorPoolConfigs(channel);
|
|
|
+ int priorCount = priorConfigs.size();
|
|
|
+ int totalCount = priorCount + 2; // + posterior + hot
|
|
|
ExecutorService executor = Executors.newFixedThreadPool(totalCount);
|
|
|
try {
|
|
|
// prior 池并行拉取
|
|
|
List<Future<List<VideoContentItemVO>>> futures = new ArrayList<>(totalCount);
|
|
|
- for (PriorPoolConfig cfg : PRIOR_POOL_CONFIGS) {
|
|
|
+ for (PriorPoolConfig cfg : priorConfigs) {
|
|
|
futures.add(executor.submit(cfg.scene
|
|
|
? () -> fetchPriorSceneCandidates(param, user, DEMAND_CANDIDATE_LIMIT, channel, dt, cfg.dimension, cfg.demandType, cfg.matchMethod)
|
|
|
: () -> fetchPriorPool(param, user, DEMAND_CANDIDATE_LIMIT, channel, dt, cfg.dimension, cfg.demandType, cfg.matchMethod)));
|
|
|
@@ -2034,7 +2075,8 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
if (!StringUtils.hasText(dt)) return empty;
|
|
|
|
|
|
List<ContentPlatformDemandVideo> whitelist = demandVideoMapperExt.selectSearchWhitelist(
|
|
|
- dt, ch, isXcx ? crowdPackage : null, isXcx ? null : ghName);
|
|
|
+ dt, ch, isXcx ? crowdPackage : null, isXcx ? null : ghName,
|
|
|
+ demandMinRov, priorSceneMinSumRov);
|
|
|
if (CollectionUtils.isEmpty(whitelist)) return empty;
|
|
|
|
|
|
// SQL 已 ORDER BY rov DESC,putIfAbsent 即拿到 max rov 代表行(设计意图:与排序键一致)
|
|
|
@@ -2048,6 +2090,8 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
for (ContentPlatformDemandVideo demand : bestPerVideo.values()) {
|
|
|
if (demand.getTitle() == null) continue;
|
|
|
if (!demand.getTitle().toLowerCase().contains(kw)) continue;
|
|
|
+ if (!passesSearchDemandRovFilter(demand.getMatchMethod(), demand.getRov(), demand.getSceneSumRov(),
|
|
|
+ demandMinRov, priorSceneMinSumRov)) continue;
|
|
|
VideoContentItemVO vo = buildDemandVideoContentItemVOList(Collections.singletonList(demand)).get(0);
|
|
|
vo.setSearchSource("keyword");
|
|
|
vo.setScore(null);
|