소스 검색

全部模式改为三路随机穿插

getInterleavedPage 由严格 1/1/1 轮转改为每步在未耗尽池中等概率随机选一个。
池内仍保持"需求强度优先、组内 score DESC"次序。种子 = userId ^ 当天日期,
保证同一用户当天翻页/刷新顺序一致。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
刘立冬 1 일 전
부모
커밋
4442a17937
1개의 변경된 파일13개의 추가작업 그리고 7개의 파일을 삭제
  1. 13 7
      api-module/src/main/java/com/tzld/piaoquan/api/service/contentplatform/impl/ContentPlatformPlanServiceImpl.java

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

@@ -47,6 +47,7 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 
+import java.time.LocalDate;
 import java.util.*;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -699,8 +700,9 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
     }
 
     /**
-     * 三路 1/1/1 严格穿插 + 跨路 video_id 去重。
-     * 缺路顺位补;先到先得(顺序:prior > posterior > hot)。
+     * 三路随机穿插 + 跨路 video_id 去重。
+     * 每步在未耗尽的池中等概率随机选一个,从该池头部取下一条(池内仍保持需求强度优先、组内 score DESC 的次序)。
+     * 用 (userId ^ 当天日期) 作为种子,保证同一用户当天翻页顺序一致、刷新一致。
      */
     private Page<VideoContentItemVO> getInterleavedPage(VideoContentListParam param, ContentPlatformAccount user) {
         List<VideoContentItemVO> prior = fetchPriorCandidates(user, DEMAND_CANDIDATE_LIMIT);
@@ -716,13 +718,17 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
         Set<Long> emittedIds = new HashSet<>();
         List<VideoContentItemVO> merged = new ArrayList<>();
 
-        int idx = 0;
+        long userSeed = user.getId() == null ? 0L : user.getId();
+        long seed = userSeed ^ LocalDate.now().toString().hashCode();
+        Random rng = new Random(seed);
+
         while (!(exhausted[0] && exhausted[1] && exhausted[2])) {
-            int cur = idx % 3;
-            idx++;
-            if (exhausted[cur]) {
-                continue;
+            List<Integer> alive = new ArrayList<>(3);
+            for (int i = 0; i < 3; i++) {
+                if (!exhausted[i]) alive.add(i);
             }
+            int cur = alive.get(rng.nextInt(alive.size()));
+
             List<VideoContentItemVO> pool = pools.get(cur);
             while (pointers[cur] < pool.size() && emittedIds.contains(pool.get(pointers[cur]).getVideoId())) {
                 pointers[cur]++;