Ver código fonte

MOD:祝福和节日召回分开

sunxy 1 ano atrás
pai
commit
f6feae7601

+ 4 - 4
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/client/ModelClient.java

@@ -13,7 +13,7 @@ import java.util.Map;
  * @author dyp
  */
 @Component
-@Slf4j
+//@Slf4j
 public class ModelClient {
     @GrpcClient("recommend-server")
     private ModelServiceGrpc.ModelServiceBlockingStub client;
@@ -28,12 +28,12 @@ public class ModelClient {
                 .build();
         ScoreResponse response = client.score(request);
         if (response == null || !response.hasResult()) {
-            log.info("score grpc error");
+//            log.info("score grpc error");
             return null;
         }
         if (response.getResult().getCode() != 1) {
-            log.info("score grpc code={}, msg={}", response.getResult().getCode(),
-                    response.getResult().getMessage());
+//            log.info("score grpc code={}, msg={}", response.getResult().getCode(),
+//                    response.getResult().getMessage());
             return null;
         }
         return response.getScoreMap();

+ 1 - 1
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java

@@ -68,7 +68,7 @@ public class RankService {
         // 1 通过 apptype 判断该小程序走怎样的排序策略。
         if (param.getAppType() == AppTypeEnum.PIAO_QUAN_MEIHAO_ZHUFU.getCode()){
             List<Video> results = new ArrayList<>();
-            results.addAll(extractAndSort(param, FestivalRecallStrategyV1.PUSH_FORM));
+            results.addAll(extractAndSort(param, BlessRecallStrategy.PUSH_FORM));
             List<String> videoIdKeys = results.stream()
                     .map(t -> param.getRankKeyPrefix() + t.getVideoId())
                     .collect(Collectors.toList());

+ 1 - 1
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java

@@ -87,7 +87,7 @@ public class RecallService implements ApplicationContextAware {
                 || param.getAppType() == AppTypeEnum.ZUI_JING_QI.getCode()) {
             strategies.addAll(getRegionRecallStrategy(param));
         } else if (param.getAppType() == AppTypeEnum.PIAO_QUAN_MEIHAO_ZHUFU.getCode()){
-            strategies.add(strategyMap.get(FestivalRecallStrategyV1.class.getSimpleName()));
+            strategies.add(strategyMap.get(BlessRecallStrategy.class.getSimpleName()));
             strategies.add(strategyMap.get(RegionRealtimeRecallStrategyV2.class.getSimpleName()));
             strategies.add(strategyMap.get(RegionRealtimeRecallStrategyV3.class.getSimpleName()));
             return strategies;

+ 97 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/BlessRecallStrategy.java

@@ -0,0 +1,97 @@
+package com.tzld.piaoquan.recommend.server.service.recall.strategy;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
+import com.tzld.piaoquan.recommend.server.service.filter.RegionFilterService;
+import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
+import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
+import com.tzld.piaoquan.recommend.server.service.score4recall.ScorerPipeline4Recall;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ * @author zhangbo
+ */
+@Slf4j
+@Component
+public class BlessRecallStrategy implements RecallStrategy {
+
+    public static final String PUSH_FORM = "bless_strategy_festival";
+    @Value("${yearly_festival_time_range:}")
+    private String yearlyFestivalTimeRange;
+    @Value("${daily_bless_time_range:}")
+    private String dailyBlessTimeRange;
+    @Autowired
+    private RegionFilterService filterService;
+    @Override
+    public List<Video> recall(RecallParam param) {
+
+        // 1 获取省份key 放入参数map中
+        String provinceCn = param.getProvince();
+        if (provinceCn == null){
+            provinceCn = "中国";
+        }else{
+            provinceCn = provinceCn.replaceAll("省$", "");
+        }
+        Map<String, String> param4Model = new HashMap<>(1);
+        param4Model.put("region_province", provinceCn);
+        param4Model.put("yearly_festival_time_range", yearlyFestivalTimeRange);
+        param4Model.put("daily_bless_time_range", dailyBlessTimeRange);
+
+        // 2 通过model拿到召回list
+        ScorerPipeline4Recall pipeline = ScorerUtils.getScorerPipeline4Recall("feeds_score_config_bless.conf");
+        List<List<Pair<Long, Double>>> results = pipeline.recall(param4Model);
+        List<Pair<Long, Double>> result = results.get(0);
+        for (int i=1; i<results.size(); ++i){
+            result.addAll(results.get(i));
+        }
+        Map<Long, Double> videoMap = new LinkedHashMap<>();
+        for (Pair<Long, Double> v: result){
+            videoMap.put(v.getLeft(), v.getRight());
+        }
+        long t1 = new Long(System.currentTimeMillis());
+        FilterParam filterParam = FilterParamFactory.create(param, Lists.newArrayList(videoMap.keySet()));
+        filterParam.setForceTruncation(10000);
+        filterParam.setConcurrent(true);
+        filterParam.setNotUsePreView(false);
+        FilterResult filterResult = filterService.filter(filterParam);
+        long t2 = new Long(System.currentTimeMillis());
+        JSONObject obj = new JSONObject();
+        obj.put("name", "FestivalRecallStrategyV1");
+        obj.put("filter_time", t2-t1);
+        obj.put("sizeOld", videoMap.size());
+        List<Video> videosResult = new ArrayList<>();
+        if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
+            obj.put("sizeNew", filterResult.getVideoIds().size());
+            filterResult.getVideoIds().stream().forEach(vid -> {
+                Video video = new Video();
+                video.setVideoId(vid);
+                video.setAbCode(param.getAbCode());
+                video.setRovScore(videoMap.get(vid));
+                video.setPushFrom(pushFrom());
+                videosResult.add(video);
+            });
+        }
+        log.info(obj.toString());
+        Collections.sort(videosResult, Comparator.comparingDouble(o -> -o.getRovScore()));
+        return videosResult;
+    }
+
+    @Override
+    public String pushFrom(){
+        return PUSH_FORM;
+    }
+
+
+}

+ 6 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/FestivalRecallStrategyV1.java

@@ -15,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
@@ -25,7 +26,11 @@ import java.util.*;
 @Slf4j
 @Component
 public class FestivalRecallStrategyV1 implements RecallStrategy {
+
     public static final String PUSH_FORM = "recall_strategy_festival";
+
+    @Value("${yearly_festival_time_range:}")
+    private String yearlyFestivalTimeRange;
     @Autowired
     private RegionFilterService filterService;
     @Override
@@ -40,6 +45,7 @@ public class FestivalRecallStrategyV1 implements RecallStrategy {
         }
         Map<String, String> param4Model = new HashMap<>(1);
         param4Model.put("region_province", provinceCn);
+        param4Model.put("yearly_festival_time_range", yearlyFestivalTimeRange);
         // 2 通过model拿到召回list
         ScorerPipeline4Recall pipeline = ScorerUtils.getScorerPipeline4Recall("feeds_score_config_festival.conf");
         List<List<Pair<Long, Double>>> results = pipeline.recall(param4Model);

+ 1 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/ScorerUtils.java

@@ -38,6 +38,7 @@ public final class ScorerUtils {
         ScorerUtils.init4Recall("feeds_recall_config_region_v3.conf");
         ScorerUtils.init4Recall("feeds_recall_config_region_v4.conf");
         ScorerUtils.init4Recall("feeds_score_config_festival.conf");
+        ScorerUtils.init4Recall("feeds_score_config_bless.conf");
     }
 
     private ScorerUtils() {

+ 208 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score4recall/strategy/BlessRecallScore.java

@@ -0,0 +1,208 @@
+package com.tzld.piaoquan.recommend.server.service.score4recall.strategy;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.tzld.piaoquan.recommend.server.service.score.ScorerConfigInfo;
+import com.tzld.piaoquan.recommend.server.service.score4recall.AbstractScorer4Recall;
+import com.tzld.piaoquan.recommend.server.service.score4recall.model4recall.Model4RecallKeyValue;
+import com.tzld.piaoquan.recommend.server.util.ListMerger;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+public class BlessRecallScore extends AbstractScorer4Recall {
+
+    public BlessRecallScore(ScorerConfigInfo configInfo) {
+        super(configInfo);
+    }
+
+    @Override
+    public void loadModel() {
+        doLoadModel(Model4RecallKeyValue.class);
+    }
+
+    final Set<String> NORTHERN_PROVINCES = new HashSet<>(Arrays.asList(
+            "北京", "天津", "河北", "山西", "内蒙古"
+            , "辽宁", "吉林", "黑龙江", "山东", "河南", "陕西", "甘肃", "宁夏", "新疆"
+    ));
+
+
+    @Override
+    public List<Pair<Long, Double>> recall(Map<String, String> params) {
+        // 1 获取省份,判断南北 小年
+        String key = params.getOrDefault("region_province", "中国");
+        boolean ifNorth = NORTHERN_PROVINCES.contains(key);
+
+
+        // 节假日、时效性,判断
+        Model4RecallKeyValue model = (Model4RecallKeyValue) this.getModel();
+        if (model == null || model.kv == null) {
+            return new ArrayList<>();
+        }
+        LocalDateTime now = LocalDateTime.now();
+        // 节日祝福-每年
+        List<Pair<Long, Double>> yearResult = new ArrayList<>();
+        String yearlyFestivalTimeRange = params.get("yearly_festival_time_range");
+        JSONObject jsonObject = JSONObject.parseObject(yearlyFestivalTimeRange);
+        for (String festival : jsonObject.keySet()) {
+            try {
+                if (festival.contains("小年")) {
+                    if ("北小年".contains(festival) && !ifNorth) {
+                        continue;
+                    } else if ("南小年".contains(festival) && ifNorth) {
+                        continue;
+                    }
+                    festival = "小年";
+                }
+                JSONArray jsonArray = jsonObject.getJSONArray(festival);
+                if (jsonArray == null) {
+                    continue;
+                }
+                List<String> timeRangeList = jsonArray.toJavaList(String.class);
+                if (isFestivalTime(now, timeRangeList)) {
+                    Pair<LocalDateTime, LocalDateTime> startTimeAndEndTime = getStartTimeAndEndTime(timeRangeList.get(0));
+                    if (startTimeAndEndTime == null) {
+                        continue;
+                    }
+                    // 节日峰值设置为结束时间的当天的7点
+                    double weight = DynamicGaussianFunction.calculateValue(LocalDateTime.now(), startTimeAndEndTime.getLeft(),
+                            startTimeAndEndTime.getRight(), startTimeAndEndTime.getRight().withHour(7));
+                    List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault(festival, new ArrayList<>());
+                    if (festivalLists.isEmpty()) {
+                        continue;
+                    }
+                    festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), weight))
+                            .limit(Math.min(50, festivalLists.size()))
+                            .collect(Collectors.toList());
+                    yearResult.addAll(festivalLists);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        List<Pair<Long, Double>> dayResult = new ArrayList<>();
+        // 每日祝福-每天固定时间段
+        String dailyFestivalTimeRange = params.get("daily_bless_time_range");
+        JSONObject dailyFestivalTimeRangeJson = JSONObject.parseObject(dailyFestivalTimeRange);
+        for (String bless : dailyFestivalTimeRangeJson.keySet()) {
+            try {
+                String timeRange = dailyFestivalTimeRangeJson.getString(bless);
+                if (isFestivalTime(now, Collections.singletonList(timeRange))) {
+                    List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault(bless, new ArrayList<>());
+                    if (festivalLists.isEmpty()) {
+                        continue;
+                    }
+                    festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), 0.0))
+                            .limit(Math.min(50, festivalLists.size()))
+                            .collect(Collectors.toList());
+                    dayResult.addAll(festivalLists);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        // 常规祝福类的小程序-任意时间
+        List<Pair<Long, Double>> anyResult = new ArrayList<>();
+        List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault("祝福", new ArrayList<>());
+        if (!festivalLists.isEmpty()) {
+            festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), 0.0))
+                    .limit(Math.min(50, festivalLists.size()))
+                    .collect(Collectors.toList());
+            anyResult.addAll(festivalLists);
+        }
+        return ListMerger.mergeLists(yearResult, dayResult, anyResult);
+    }
+
+    public Pair<LocalDateTime, LocalDateTime> getStartTimeAndEndTime(String timeRangeList) {
+        if (timeRangeList == null || timeRangeList.isEmpty()) {
+            return null;
+        }
+        // 时间格式 2024-12-20 00:00~2024-12-25 08:00
+        if (StringUtils.startsWith(timeRangeList, "daily")) {
+            // 判断是否是 daily 开头
+            return null;
+        } else {
+            String[] split = StringUtils.split(timeRangeList, "~");
+            if (split.length != 2) {
+                return null;
+            }
+            String startTime = split[0];
+            String endTime = split[1];
+            // 解析 startTime endTime
+            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+            LocalDateTime startLocalDateTime = LocalDateTime.parse(startTime, dateTimeFormatter);
+            LocalDateTime endLocalDateTime = LocalDateTime.parse(endTime, dateTimeFormatter);
+            return Pair.of(startLocalDateTime, endLocalDateTime);
+        }
+    }
+
+    public boolean isFestivalTime(LocalDateTime now, List<String> timeRangeList) {
+        if (timeRangeList == null || timeRangeList.isEmpty()) {
+            return false;
+        }
+        for (String timeRange : timeRangeList) {
+            // 判断是否是 daily 开头
+            if (StringUtils.startsWith(timeRange, "daily")) {
+                // 判断是否是 daily 开头
+                String dailyTimeRange = StringUtils.substring(timeRange, 6);
+                String[] split = StringUtils.split(dailyTimeRange, "-");
+                if (split.length != 2) {
+                    continue;
+                }
+                String startTime = split[0];
+                String endTime = split[1];
+                // 获取当前时间的小时和分钟
+                int hour = now.getHour();
+                int minute = now.getMinute();
+                // startTime: 21:00 endTime: 23:00
+                String[] startSplit = StringUtils.split(startTime, ":");
+                String[] endSplit = StringUtils.split(endTime, ":");
+                if (startSplit.length != 2 || endSplit.length != 2) {
+                    continue;
+                }
+                int startHour = Integer.parseInt(startSplit[0]);
+                int startMinute = Integer.parseInt(startSplit[1]);
+                int endHour = Integer.parseInt(endSplit[0]);
+                int endMinute = Integer.parseInt(endSplit[1]);
+                if (hour > startHour && hour < endHour) {
+                    return true;
+                } else if (hour == startHour && hour == endHour) {
+                    if (minute >= startMinute && minute <= endMinute) {
+                        return true;
+                    }
+                } else if (hour == startHour) {
+                    if (minute >= startMinute) {
+                        return true;
+                    }
+                } else if (hour == endHour) {
+                    if (minute <= endMinute) {
+                        return true;
+                    }
+                }
+                continue;
+            }
+            // 时间格式 2024-12-20 00:00~2024-12-25 08:00
+            String[] split = StringUtils.split(timeRange, "~");
+            if (split.length != 2) {
+                continue;
+            }
+            String startTime = split[0];
+            String endTime = split[1];
+            // 解析 startTime endTime
+            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+            LocalDateTime startLocalDateTime = LocalDateTime.parse(startTime, dateTimeFormatter);
+            LocalDateTime endLocalDateTime = LocalDateTime.parse(endTime, dateTimeFormatter);
+            if (now.isAfter(startLocalDateTime) && now.isBefore(endLocalDateTime)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+}

+ 37 - 168
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score4recall/strategy/FestivalRecallScore.java

@@ -1,9 +1,10 @@
 package com.tzld.piaoquan.recommend.server.service.score4recall.strategy;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.tzld.piaoquan.recommend.server.service.score.ScorerConfigInfo;
 import com.tzld.piaoquan.recommend.server.service.score4recall.AbstractScorer4Recall;
 import com.tzld.piaoquan.recommend.server.service.score4recall.model4recall.Model4RecallKeyValue;
-import com.tzld.piaoquan.recommend.server.util.ListMerger;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 
@@ -15,124 +16,6 @@ import java.util.stream.Collectors;
 
 public class FestivalRecallScore extends AbstractScorer4Recall {
 
-    private static final Map<String, String> DAILY_BLESSING_TIME_MAP = new HashMap<String, String>() {
-        {
-            put("晚安", "daily 21:00-24:00");
-            put("晚上好", "daily 18:00-20:00");
-            put("下午好", "daily 15:00-16:00");
-            put("中午好 ", "daily 11:00-13:00");
-            put("早上好", "daily 00:00-08:00");
-        }
-    };
-
-    private static final Map<String, List<String>> YEARLY_FESTIVAL_TIME_MAP = new HashMap<String, List<String>>() {
-        {
-            put("圣诞节", Arrays.asList("2024-12-20 00:00~2024-12-25 08:00", "2025-12-20 00:00~2025-12-25 08:00", "2026-12-20 " +
-                    "00:00~2026-12-25 08:00"));
-            put("平安夜", Arrays.asList("2024-12-19 00:00~2024-12-24 08:00", "2025-12-19 00:00~2025-12-24 08:00", "2026-12-19 " +
-                    "00:00~2026-12-24 08:00"));
-            put("冬至", Arrays.asList("2024-12-19 00:00~2024-12-21 08:00", "2025-12-19 00:00~2025-12-21 08:00", "2026-12-20 " +
-                    "00:00~2026-12-22 08:00"));
-            put("公祭日", Arrays.asList("2024-12-08 00:00~2024-12-13 08:00", "2025-12-08 00:00~2025-12-13 08:00", "2026-12-08 " +
-                    "00:00~2026-12-13 08:00"));
-            put("大雪", Arrays.asList("2024-12-04 00:00~2024-12-06 08:00", "2025-12-05 00:00~2025-12-07 08:00", "2026-12-05 " +
-                    "00:00~2026-12-07 08:00"));
-            put("感恩节", Arrays.asList("2024-11-23 00:00~2024-11-28 08:00", "2025-11-22 00:00~2025-11-27 08:00", "2026-11-21 " +
-                    "00:00~2026-11-26 08:00"));
-            put("小雪", Arrays.asList("2024-11-20 00:00~2024-11-22 08:00", "2025-11-20 00:00~2025-11-22 08:00", "2026-11-20 " +
-                    "00:00~2026-11-22 08:00"));
-            put("立冬", Arrays.asList("2024-11-05 00:00~2024-11-07 08:00", "2025-11-05 00:00~2025-11-07 08:00", "2026-11-05 " +
-                    "00:00~2026-11-07 08:00"));
-            put("霜降", Arrays.asList("2024-10-21 00:00~2024-10-23 08:00", "2025-10-21 00:00~2025-10-23 08:00", "2026-10-21 " +
-                    "00:00~2026-10-23 08:00"));
-            put("重阳节", Arrays.asList("2024-10-06 00:00~2024-10-11 08:00", "2025-10-24 00:00~2025-10-29 08:00", "2026-10-13 " +
-                    "00:00~2026-10-18 08:00"));
-            put("寒露", Arrays.asList("2024-10-06 00:00~2024-10-08 08:00", "2025-10-06 00:00~2025-10-08 08:00", "2026-10-06 " +
-                    "00:00~2026-10-08 08:00"));
-            put("国庆节", Arrays.asList("2024-09-26 00:00~2024-10-01 08:00", "2025-09-26 00:00~2025-10-01 08:00", "2026-09-26 " +
-                    "00:00~2026-10-01 08:00"));
-            put("秋分", Arrays.asList("2024-09-20 00:00~2024-09-22 08:00", "2025-09-21 00:00~2025-09-23 08:00", "2026-09-21 " +
-                    "00:00~2026-09-23 08:00"));
-            put("中秋节", Arrays.asList("2024-09-12 00:00~2024-09-17 08:00", "2025-10-01 00:00~2025-10-06 08:00", "2026-09-20 " +
-                    "00:00~2026-09-25 08:00"));
-            put("白露", Arrays.asList("2024-09-05 00:00~2024-09-07 08:00", "2025-09-05 00:00~2025-09-07 08:00", "2026-09-05 " +
-                    "00:00~2026-09-07 08:00"));
-            put("处暑", Arrays.asList("2024-08-20 00:00~2024-08-22 08:00", "2025-08-21 00:00~2025-08-23 08:00", "2026-08-21 " +
-                    "00:00~2026-08-23 08:00"));
-            put("中元节", Arrays.asList("2024-08-13 00:00~2024-08-18 08:00", "2025-09-01 00:00~2025-09-06 08:00", "2026-08-22 " +
-                    "00:00~2026-08-27 08:00"));
-            put("七夕节", Arrays.asList("2024-08-05 00:00~2024-08-10 08:00", "2025-08-24 00:00~2025-08-29 08:00", "2026-08-14 " +
-                    "00:00~2026-08-19 08:00"));
-            put("立秋", Arrays.asList("2024-08-05 00:00~2024-08-07 08:00", "2025-08-05 00:00~2025-08-07 08:00", "2026-08-05 " +
-                    "00:00~2026-08-07 08:00"));
-            put("建军节", Arrays.asList("2024-07-27 00:00~2024-08-01 08:00", "2025-07-27 00:00~2025-08-01 08:00", "2026-07-27 " +
-                    "00:00~2026-08-01 08:00"));
-            put("大暑", Arrays.asList("2024-07-20 00:00~2024-07-22 08:00", "2025-07-20 00:00~2025-07-22 08:00", "2026-07-21 " +
-                    "00:00~2026-07-23 08:00"));
-            put("小暑", Arrays.asList("2024-07-04 00:00~2024-07-06 08:00", "2025-07-05 00:00~2025-07-07 08:00", "2026-07-05 " +
-                    "00:00~2026-07-07 08:00"));
-            put("七七事变",Arrays.asList("2024-07-02 00:00~2024-07-07 08:00", "2025-07-02 00:00~2025-07-07 08:00", "2026" +
-                    "-07-02 " +
-                    "00:00~2026-07-07 08:00"));
-            put("建党节", Arrays.asList("2024-06-26 00:00~2024-07-01 08:00", "2025-06-26 00:00~2025-07-01 08:00", "2026-06-26 " +
-                    "00:00~2026-07-01 08:00"));
-            put("夏至", Arrays.asList("2024-06-19 00:00~2024-06-21 08:00", "2025-06-19 00:00~2025-06-21 08:00", "2026-06-19 " +
-                    "00:00~2026-06-21 08:00"));
-            put("父亲节", Arrays.asList("2024-06-11 00:00~2024-06-16 08:00", "2025-06-10 00:00~2025-06-15 08:00", "2026-06-16 " +
-                    "00:00~2026-06-21 08:00"));
-            put("端午节", Arrays.asList("2024-06-05 00:00~2024-06-10 08:00", "2025-05-26 00:00~2025-05-31 08:00", "2026-06-14 " +
-                    "00:00~2026-06-19 08:00"));
-            put("芒种", Arrays.asList("2024-06-03 00:00~2024-06-05 08:00", "2025-06-03 00:00~2025-06-05 08:00", "2026-06-03 " +
-                    "00:00~2026-06-05 08:00"));
-            put("儿童节", Arrays.asList("2024-05-27 00:00~2024-06-01 08:00", "2025-05-27 00:00~2025-06-01 08:00", "2026-05-27 " +
-                    "00:00~2026-06-01 08:00"));
-            put("小满", Arrays.asList("2024-05-18 00:00~2024-05-20 08:00", "2025-05-19 00:00~2025-05-21 08:00", "2026-05-19 " +
-                    "00:00~2026-05-21 08:00"));
-            put("母亲节", Arrays.asList("2024-05-07 00:00~2024-05-12 08:00", "2025-05-06 00:00~2025-05-11 08:00", "2026-05-05 " +
-                    "00:00~2026-05-10 08:00"));
-            put("立夏", Arrays.asList("2024-05-03 00:00~2024-05-05 08:00", "2025-05-03 00:00~2025-05-05 08:00", "2026-05-03 " +
-                    "00:00~2026-05-05 08:00"));
-            put("劳动节", Arrays.asList("2024-04-26 00:00~2024-05-01 08:00", "2025-04-26 00:00~2025-05-01 08:00", "2026-04-26 " +
-                    "00:00~2026-05-01 08:00"));
-            put("谷雨", Arrays.asList("2024-04-17 00:00~2024-04-19 08:00", "2025-04-18 00:00~2025-04-20 08:00", "2026-04-18 " +
-                    "00:00~2026-04-20 08:00"));
-            put("清明", Arrays.asList("2024-04-02 00:00~2024-04-04 08:00", "2025-04-02 00:00~2025-04-04 08:00", "2026-04-03 " +
-                    "00:00~2026-04-05 08:00"));
-            put("春分", Arrays.asList("2024-03-18 00:00~2024-03-20 08:00", "2025-03-18 00:00~2025-03-20 08:00", "2026-03-18 " +
-                    "00:00~2026-03-20 08:00"));
-            put("龙抬头", Arrays.asList("2024-03-06 00:00~2024-03-11 08:00", "2025-02-24 00:00~2025-03-01 08:00", "2026-03-15 " +
-                    "00:00~2026-03-20 08:00"));
-            put("妇女节", Arrays.asList("2024-03-03 00:00~2024-03-08 08:00", "2025-03-03 00:00~2025-03-08 08:00", "2026-03-03 " +
-                    "00:00~2026-03-08 08:00"));
-            put("惊蛰", Arrays.asList("2024-03-03 00:00~2024-03-05 08:00", "2025-03-03 00:00~2025-03-05 08:00", "2026-03-03 " +
-                    "00:00~2026-03-05 08:00"));
-            put("元宵节", Arrays.asList("2024-02-19 00:00~2024-02-24 08:00", "2025-02-17 00:00~2025-02-22 08:00", "2026-02-26 " +
-                    "00:00~2026-03-03 08:00"));
-            put("雨水", Arrays.asList("2024-02-17 00:00~2024-02-19 08:00", "2025-02-16 00:00~2025-02-18 08:00", "2026-02-16 " +
-                    "00:00~2026-02-18 08:00"));
-            put("情人节", Arrays.asList("2024-02-09 00:00~2024-02-14 08:00", "2025-02-09 00:00~2025-02-14 08:00", "2026-02-09 " +
-                    "00:00~2026-02-14 08:00"));
-            put("春节", Arrays.asList("2024-02-05 00:00~2024-02-10 08:00", "2025-01-24 00:00~2025-01-29 08:00", "2026-02-12 " +
-                    "00:00~2026-02-17 08:00"));
-            put("除夕", Arrays.asList("2024-02-04 00:00~2024-02-09 08:00", "2025-01-23 00:00~2025-01-28 08:00", "2026-02-11 " +
-                    "00:00~2026-02-16 08:00"));
-            put("立春", Arrays.asList("2024-02-03 15:00~2024-02-04 20:00", "2025-02-01 00:00~2025-02-03 08:00",
-                    "2026-02-02 00:00~2026-02-04 08:00"));
-            put("北小年", Arrays.asList("2024-01-29 00:00~2024-02-02 20:00", "2025-01-18 00:00~2025-01-22 10:00", "2026-02-06 " +
-                    "00:00~2026-02-10 10:00"));
-            put("南小年", Arrays.asList("2024-01-30 00:00~2024-02-03 20:00", "2025-01-19 00:00~2025-01-23 10:00", "2026-02-07 " +
-                    "00:00~2026-02-11 10:00"));
-            put("大寒", Arrays.asList("2024-01-18 00:00~2024-01-20 08:00", "2025-01-18 00:00~2025-01-20 08:00", "2026-01-18 " +
-                    "00:00~2026-01-20 08:00"));
-            put("腊八节", Arrays.asList("2024-01-13 00:00~2024-01-18 08:00", "2025-01-02 00:00~2025-01-07 08:00", "2026-01-21 " +
-                    "00:00~2026-01-26 08:00"));
-            put("小寒", Arrays.asList("2024-01-04 00:00~2024-01-06 08:00", "2025-01-03 00:00~2025-01-05 08:00", "2026-01-03 " +
-                    "00:00~2026-01-05 08:00"));
-            put("元旦", Arrays.asList("2023-12-27 00:00~2024-01-01 08:00", "2024-12-27 00:00~2025-01-01 08:00", "2025-12-27 " +
-                    "00:00~2026-01-01 08:00"));
-        }
-    };
-
     public FestivalRecallScore(ScorerConfigInfo configInfo) {
         super(configInfo);
     }
@@ -162,63 +45,49 @@ public class FestivalRecallScore extends AbstractScorer4Recall {
         }
         LocalDateTime now = LocalDateTime.now();
         // 节日祝福-每年
+
+        String yearlyFestivalTimeRange = params.get("yearly_festival_time_range");
+        JSONObject jsonObject = JSONObject.parseObject(yearlyFestivalTimeRange);
         List<Pair<Long, Double>> yearResult = new ArrayList<>();
-        for (Map.Entry<String, List<String>> entry : YEARLY_FESTIVAL_TIME_MAP.entrySet()) {
-            String festival = entry.getKey();
-            List<String> timeRangeList = entry.getValue();
-            if (festival.contains("小年")){
-                if ("北小年".contains(festival) && !ifNorth){
-                    continue;
-                } else if ("南小年".contains(festival) && ifNorth) {
-                    continue;
-                }
-                festival = "小年";
-            }
+        for (String festival : jsonObject.keySet()) {
+            try {
 
-            if (isFestivalTime(now, timeRangeList)) {
-                Pair<LocalDateTime, LocalDateTime> startTimeAndEndTime = getStartTimeAndEndTime(timeRangeList.get(0));
-                if (startTimeAndEndTime == null) {
-                    continue;
+
+                if (festival.contains("小年")) {
+                    if ("北小年".contains(festival) && !ifNorth) {
+                        continue;
+                    } else if ("南小年".contains(festival) && ifNorth) {
+                        continue;
+                    }
+                    festival = "小年";
                 }
-                // 节日峰值设置为结束时间的当天的7点
-                double weight = DynamicGaussianFunction.calculateValue(LocalDateTime.now(), startTimeAndEndTime.getLeft(),
-                        startTimeAndEndTime.getRight(), startTimeAndEndTime.getRight().withHour(7));
-                List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault(festival, new ArrayList<>());
-                if (festivalLists.isEmpty()) {
+                JSONArray jsonArray = jsonObject.getJSONArray(festival);
+                if (jsonArray == null) {
                     continue;
                 }
-                festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), weight))
-                        .limit(Math.min(50, festivalLists.size()))
-                        .collect(Collectors.toList());
-                yearResult.addAll(festivalLists);
-            }
-        }
-        List<Pair<Long, Double>> dayResult = new ArrayList<>();
-        // 每日祝福-每天固定时间段
-        for (Map.Entry<String, String> entry : DAILY_BLESSING_TIME_MAP.entrySet()) {
-            String festival = entry.getKey();
-            String timeRange = entry.getValue();
-            if (isFestivalTime(now, Collections.singletonList(timeRange))) {
-                List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault(festival, new ArrayList<>());
-                if (festivalLists.isEmpty()) {
-                    continue;
+                List<String> timeRangeList = jsonArray.toJavaList(String.class);
+                if (isFestivalTime(now, timeRangeList)) {
+                    Pair<LocalDateTime, LocalDateTime> startTimeAndEndTime = getStartTimeAndEndTime(timeRangeList.get(0));
+                    if (startTimeAndEndTime == null) {
+                        continue;
+                    }
+                    // 节日峰值设置为结束时间的当天的7点
+                    double weight = DynamicGaussianFunction.calculateValue(LocalDateTime.now(), startTimeAndEndTime.getLeft(),
+                            startTimeAndEndTime.getRight(), startTimeAndEndTime.getRight().withHour(7));
+                    List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault(festival, new ArrayList<>());
+                    if (festivalLists.isEmpty()) {
+                        continue;
+                    }
+                    festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), weight))
+                            .limit(Math.min(50, festivalLists.size()))
+                            .collect(Collectors.toList());
+                    yearResult.addAll(festivalLists);
                 }
-                festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), 0.0))
-                        .limit(Math.min(50, festivalLists.size()))
-                        .collect(Collectors.toList());
-                dayResult.addAll(festivalLists);
+            } catch (Exception e) {
+//                e.printStackTrace();
             }
         }
-        // 常规祝福类的小程序-任意时间
-        List<Pair<Long, Double>> anyResult = new ArrayList<>();
-        List<Pair<Long, Double>> festivalLists = model.kv.getOrDefault("祝福", new ArrayList<>());
-        if (!festivalLists.isEmpty()) {
-            festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), 0.0))
-                    .limit(Math.min(50, festivalLists.size()))
-                    .collect(Collectors.toList());
-            anyResult.addAll(festivalLists);
-        }
-        return ListMerger.mergeLists(yearResult, dayResult, anyResult);
+        return yearResult;
     }
 
     public Pair<LocalDateTime, LocalDateTime> getStartTimeAndEndTime(String timeRangeList) {

+ 7 - 0
recommend-server-service/src/main/resources/feeds_score_config_bless.conf

@@ -0,0 +1,7 @@
+scorer-config = {
+  festival-score-config = {
+    scorer-name = "com.tzld.piaoquan.recommend.server.service.score4recall.strategy.BlessRecallScore"
+    scorer-priority = 100
+    model-path = "alg_recall_file/05_festival.txt"
+  }
+}