Ver Fonte

videoContentList 支持按公众号(channel_level3)二级过滤,无数据时退化至渠道粒度

仅影响 prior/posterior 两路,hot 不动;
selectForRecommend 增加可选 channelLevel3 参数;
fetchPriorCandidates / fetchPosteriorCandidates 接收 param,
先用 ghName 查两阶段,两阶段都空时退化重查渠道粒度。
刘立冬 há 1 dia atrás
pai
commit
49a8649b7e

+ 1 - 0
api-module/src/main/java/com/tzld/piaoquan/api/dao/mapper/contentplatform/ext/ContentPlatformDemandVideoMapperExt.java

@@ -40,6 +40,7 @@ public interface ContentPlatformDemandVideoMapperExt {
                                                        @Param("dimension") String dimension,
                                                        @Param("dimensionExclude") String dimensionExclude,
                                                        @Param("demandFilterSortStrategyLike") String demandFilterSortStrategyLike,
+                                                       @Param("channelLevel3") String channelLevel3,
                                                        @Param("limit") int limit,
                                                        @Param("excludeSelfTitle") boolean excludeSelfTitle);
 

+ 3 - 0
api-module/src/main/java/com/tzld/piaoquan/api/model/param/contentplatform/VideoContentListParam.java

@@ -21,4 +21,7 @@ public class VideoContentListParam extends PageParam {
 
     @ApiModelProperty(value = "数据来源: prior-先验需求 / posterior-后验需求 / hot-全局热门 / 空-全部穿插")
     private String source;
+
+    @ApiModelProperty(value = "公众号名称(对应 demand.channel_level3),仅 prior/posterior 路使用,无数据时退化为渠道粒度")
+    private String ghName;
 }

+ 28 - 10
api-module/src/main/java/com/tzld/piaoquan/api/service/contentplatform/impl/ContentPlatformPlanServiceImpl.java

@@ -649,8 +649,8 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
             return getHotSourcePaged(param, user);
         }
         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) {
             v.setSource(source);
         }
@@ -705,8 +705,8 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
      * 用 (userId ^ 当天日期) 作为种子,保证同一用户当天翻页顺序一致、刷新一致。
      */
     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);
         for (VideoContentItemVO v : prior) v.setSource(SOURCE_PRIOR);
         for (VideoContentItemVO v : posterior) v.setSource(SOURCE_POSTERIOR);
@@ -763,18 +763,27 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
      * 先验池:A 段 dimension='传播头部' → B 段 其余 dimension。
      * 每段按 (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();
         if (!StringUtils.hasText(dt)) {
             return new ArrayList<>();
         }
         String crowdSegment = user.getChannel();
+        String ghName = StringUtils.hasText(param.getGhName()) ? param.getGhName() : null;
         int fetchLimit = Math.max(limit * 3, DEMAND_CANDIDATE_LIMIT);
 
         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(
-                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 ->
                 (r.getPointType() == null ? "" : r.getPointType()) + "\u0001"
@@ -789,18 +798,27 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
      * 后验池:A 段 "绝对高效率" → B 段 "相对裂变率"。
      * 每段按 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();
         if (!StringUtils.hasText(dt)) {
             return new ArrayList<>();
         }
         String crowdSegment = user.getChannel();
+        String ghName = StringUtils.hasText(param.getGhName()) ? param.getGhName() : null;
         int fetchLimit = Math.max(limit * 3, DEMAND_CANDIDATE_LIMIT);
 
         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(
-                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 ->
                 r.getDemandContentId() == null ? "" : r.getDemandContentId();

+ 3 - 0
api-module/src/main/resources/mapper/contentplatform/ext/ContentPlatformDemandVideoMapperExt.xml

@@ -99,6 +99,9 @@
         <if test="demandFilterSortStrategyLike != null and demandFilterSortStrategyLike != ''">
             AND demand_filter_sort_strategy LIKE #{demandFilterSortStrategyLike}
         </if>
+        <if test="channelLevel3 != null and channelLevel3 != ''">
+            AND channel_level3 = #{channelLevel3}
+        </if>
         <if test="excludeSelfTitle">
             AND (title IS NULL OR demand_content_title IS NULL OR title &lt;&gt; demand_content_title)
         </if>