Преглед изворни кода

Merge branch 'master' into vlog_merge_refactor_smz

# Conflicts:
#	recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/client/ModelClient.java
sunxy пре 1 година
родитељ
комит
eb323c01ae
29 измењених фајлова са 761 додато и 311 уклоњено
  1. 1 1
      recommend-server-client/pom.xml
  2. 1 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/client/ModelClient.java
  3. 19 19
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/Recommend.java
  4. 138 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequest.java
  5. 12 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequestOrBuilder.java
  6. 1 0
      recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/recommend.proto
  7. 1 1
      recommend-server-service/pom.xml
  8. 4 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java
  9. 6 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java
  10. 4 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankParam.java
  11. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java
  12. 23 13
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorBoost.java
  13. 41 24
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorInsert.java
  14. 28 65
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorTagFilter.java
  15. 5 4
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4Density.java
  16. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV3.java
  17. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV6.java
  18. 2 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallParam.java
  19. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java
  20. 97 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/BlessRecallStrategy.java
  21. 6 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/FestivalRecallStrategyV1.java
  22. 1 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/ScorerUtils.java
  23. 195 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score4recall/strategy/BlessRecallScore.java
  24. 39 175
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score4recall/strategy/FestivalRecallScore.java
  25. 28 2
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/DateUtils.java
  26. 18 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/ListMerger.java
  27. 79 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/ProbabilityCalculator.java
  28. 1 2
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/web/RecommendController.java
  29. 7 0
      recommend-server-service/src/main/resources/feeds_score_config_bless.conf

+ 1 - 1
recommend-server-client/pom.xml

@@ -10,7 +10,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>recommend-server-client</artifactId>
-    <version>1.0.1</version>
+    <version>1.0.2</version>
 
     <dependencies>
         <dependency>

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

@@ -12,6 +12,7 @@ import java.util.Map;
  * @author dyp
  */
 @Component
+//@Slf4j
 public class ModelClient {
     @GrpcClient("recommend-server")
     private ModelServiceGrpc.ModelServiceBlockingStub client;

+ 19 - 19
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/Recommend.java

@@ -51,7 +51,7 @@ public final class Recommend {
       "\n2com/tzld/piaoquan/recommend/server/rec" +
       "ommend.proto\032\031google/protobuf/any.proto\032" +
       "/com/tzld/piaoquan/recommend/server/comm" +
-      "on.proto\"\226\003\n\020RecommendRequest\022\022\n\nrequest" +
+      "on.proto\"\255\003\n\020RecommendRequest\022\022\n\nrequest" +
       "_id\030\001 \001(\t\022\013\n\003mid\030\002 \001(\t\022\013\n\003uid\030\003 \001(\t\022\014\n\004s" +
       "ize\030\004 \001(\005\022\020\n\010app_type\030\005 \001(\005\022\021\n\tcity_code" +
       "\030\006 \001(\t\022\025\n\rprovince_code\030\007 \001(\t\022\023\n\013ab_exp_" +
@@ -60,23 +60,23 @@ public final class Recommend {
       "atus\030\n \001(\005\022\032\n\022recommend_trace_id\030\013 \001(\t\022\020" +
       "\n\010video_id\030\014 \001(\003\022\014\n\004city\030\r \001(\t\022\020\n\010provin" +
       "ce\030\016 \001(\t\022\'\n\014machine_info\030\017 \001(\0132\021.Machine" +
-      "InfoProto\032.\n\014EventIdEntry\022\013\n\003key\030\001 \001(\t\022\r" +
-      "\n\005value\030\002 \001(\t:\0028\001\"\177\n\020MachineInfoProto\022\r\n" +
-      "\005brand\030\001 \001(\t\022\r\n\005model\030\002 \001(\t\022\020\n\010platform\030" +
-      "\003 \001(\t\022\023\n\013sdk_version\030\004 \001(\t\022\016\n\006system\030\005 \001" +
-      "(\t\022\026\n\016wechat_version\030\006 \001(\t\"H\n\021RecommendR" +
-      "esponse\022\027\n\006result\030\001 \001(\0132\007.Result\022\032\n\005vide" +
-      "o\030\002 \003(\0132\013.VideoProto\"\265\001\n\nVideoProto\022\020\n\010v" +
-      "ideo_id\030\001 \001(\003\022\021\n\trov_score\030\002 \001(\001\022\021\n\tpush" +
-      "_from\030\003 \001(\t\022\017\n\007ab_code\030\004 \001(\t\022\022\n\nsort_sco" +
-      "re\030\005 \001(\001\022\020\n\010position\030\006 \001(\005\022\021\n\tflow_pool\030" +
-      "\007 \001(\t\022\027\n\017is_in_flow_pool\030\010 \001(\005\022\014\n\004rand\030\t" +
-      " \001(\0012\212\001\n\020RecommendService\022:\n\021HomepageRec" +
-      "ommend\022\021.RecommendRequest\032\022.RecommendRes" +
-      "ponse\022:\n\021RelevantRecommend\022\021.RecommendRe" +
-      "quest\032\022.RecommendResponseB7\n0com.tzld.pi" +
-      "aoquan.recommend.server.gen.recommendP\001\210" +
-      "\001\001b\006proto3"
+      "InfoProto\022\025\n\rnew_exp_group\030\020 \001(\t\032.\n\014Even" +
+      "tIdEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001" +
+      "\"\177\n\020MachineInfoProto\022\r\n\005brand\030\001 \001(\t\022\r\n\005m" +
+      "odel\030\002 \001(\t\022\020\n\010platform\030\003 \001(\t\022\023\n\013sdk_vers" +
+      "ion\030\004 \001(\t\022\016\n\006system\030\005 \001(\t\022\026\n\016wechat_vers" +
+      "ion\030\006 \001(\t\"H\n\021RecommendResponse\022\027\n\006result" +
+      "\030\001 \001(\0132\007.Result\022\032\n\005video\030\002 \003(\0132\013.VideoPr" +
+      "oto\"\265\001\n\nVideoProto\022\020\n\010video_id\030\001 \001(\003\022\021\n\t" +
+      "rov_score\030\002 \001(\001\022\021\n\tpush_from\030\003 \001(\t\022\017\n\007ab" +
+      "_code\030\004 \001(\t\022\022\n\nsort_score\030\005 \001(\001\022\020\n\010posit" +
+      "ion\030\006 \001(\005\022\021\n\tflow_pool\030\007 \001(\t\022\027\n\017is_in_fl" +
+      "ow_pool\030\010 \001(\005\022\014\n\004rand\030\t \001(\0012\212\001\n\020Recommen" +
+      "dService\022:\n\021HomepageRecommend\022\021.Recommen" +
+      "dRequest\032\022.RecommendResponse\022:\n\021Relevant" +
+      "Recommend\022\021.RecommendRequest\032\022.Recommend" +
+      "ResponseB7\n0com.tzld.piaoquan.recommend." +
+      "server.gen.recommendP\001\210\001\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -89,7 +89,7 @@ public final class Recommend {
     internal_static_RecommendRequest_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_RecommendRequest_descriptor,
-        new java.lang.String[] { "RequestId", "Mid", "Uid", "Size", "AppType", "CityCode", "ProvinceCode", "AbExpCode", "EventId", "VersionAuditStatus", "RecommendTraceId", "VideoId", "City", "Province", "MachineInfo", });
+        new java.lang.String[] { "RequestId", "Mid", "Uid", "Size", "AppType", "CityCode", "ProvinceCode", "AbExpCode", "EventId", "VersionAuditStatus", "RecommendTraceId", "VideoId", "City", "Province", "MachineInfo", "NewExpGroup", });
     internal_static_RecommendRequest_EventIdEntry_descriptor =
       internal_static_RecommendRequest_descriptor.getNestedTypes().get(0);
     internal_static_RecommendRequest_EventIdEntry_fieldAccessorTable = new

+ 138 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequest.java

@@ -25,6 +25,7 @@ private static final long serialVersionUID = 0L;
     recommendTraceId_ = "";
     city_ = "";
     province_ = "";
+    newExpGroup_ = "";
   }
 
   @java.lang.Override
@@ -161,6 +162,12 @@ private static final long serialVersionUID = 0L;
 
             break;
           }
+          case 130: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            newExpGroup_ = s;
+            break;
+          }
           default: {
             if (!parseUnknownField(
                 input, unknownFields, extensionRegistry, tag)) {
@@ -710,6 +717,44 @@ private static final long serialVersionUID = 0L;
     return getMachineInfo();
   }
 
+  public static final int NEW_EXP_GROUP_FIELD_NUMBER = 16;
+  private volatile java.lang.Object newExpGroup_;
+  /**
+   * <code>string new_exp_group = 16;</code>
+   * @return The newExpGroup.
+   */
+  @java.lang.Override
+  public java.lang.String getNewExpGroup() {
+    java.lang.Object ref = newExpGroup_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      newExpGroup_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string new_exp_group = 16;</code>
+   * @return The bytes for newExpGroup.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getNewExpGroupBytes() {
+    java.lang.Object ref = newExpGroup_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      newExpGroup_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
   private byte memoizedIsInitialized = -1;
   @java.lang.Override
   public final boolean isInitialized() {
@@ -772,6 +817,9 @@ private static final long serialVersionUID = 0L;
     if (machineInfo_ != null) {
       output.writeMessage(15, getMachineInfo());
     }
+    if (!getNewExpGroupBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 16, newExpGroup_);
+    }
     unknownFields.writeTo(output);
   }
 
@@ -843,6 +891,9 @@ private static final long serialVersionUID = 0L;
       size += com.google.protobuf.CodedOutputStream
         .computeMessageSize(15, getMachineInfo());
     }
+    if (!getNewExpGroupBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(16, newExpGroup_);
+    }
     size += unknownFields.getSerializedSize();
     memoizedSize = size;
     return size;
@@ -891,6 +942,8 @@ private static final long serialVersionUID = 0L;
       if (!getMachineInfo()
           .equals(other.getMachineInfo())) return false;
     }
+    if (!getNewExpGroup()
+        .equals(other.getNewExpGroup())) return false;
     if (!unknownFields.equals(other.unknownFields)) return false;
     return true;
   }
@@ -939,6 +992,8 @@ private static final long serialVersionUID = 0L;
       hash = (37 * hash) + MACHINE_INFO_FIELD_NUMBER;
       hash = (53 * hash) + getMachineInfo().hashCode();
     }
+    hash = (37 * hash) + NEW_EXP_GROUP_FIELD_NUMBER;
+    hash = (53 * hash) + getNewExpGroup().hashCode();
     hash = (29 * hash) + unknownFields.hashCode();
     memoizedHashCode = hash;
     return hash;
@@ -1127,6 +1182,8 @@ private static final long serialVersionUID = 0L;
         machineInfo_ = null;
         machineInfoBuilder_ = null;
       }
+      newExpGroup_ = "";
+
       return this;
     }
 
@@ -1178,6 +1235,7 @@ private static final long serialVersionUID = 0L;
       } else {
         result.machineInfo_ = machineInfoBuilder_.build();
       }
+      result.newExpGroup_ = newExpGroup_;
       onBuilt();
       return result;
     }
@@ -1285,6 +1343,10 @@ private static final long serialVersionUID = 0L;
       if (other.hasMachineInfo()) {
         mergeMachineInfo(other.getMachineInfo());
       }
+      if (!other.getNewExpGroup().isEmpty()) {
+        newExpGroup_ = other.newExpGroup_;
+        onChanged();
+      }
       this.mergeUnknownFields(other.unknownFields);
       onChanged();
       return this;
@@ -2439,6 +2501,82 @@ private static final long serialVersionUID = 0L;
       }
       return machineInfoBuilder_;
     }
+
+    private java.lang.Object newExpGroup_ = "";
+    /**
+     * <code>string new_exp_group = 16;</code>
+     * @return The newExpGroup.
+     */
+    public java.lang.String getNewExpGroup() {
+      java.lang.Object ref = newExpGroup_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        newExpGroup_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string new_exp_group = 16;</code>
+     * @return The bytes for newExpGroup.
+     */
+    public com.google.protobuf.ByteString
+        getNewExpGroupBytes() {
+      java.lang.Object ref = newExpGroup_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        newExpGroup_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string new_exp_group = 16;</code>
+     * @param value The newExpGroup to set.
+     * @return This builder for chaining.
+     */
+    public Builder setNewExpGroup(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      newExpGroup_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string new_exp_group = 16;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearNewExpGroup() {
+      
+      newExpGroup_ = getDefaultInstance().getNewExpGroup();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string new_exp_group = 16;</code>
+     * @param value The bytes for newExpGroup to set.
+     * @return This builder for chaining.
+     */
+    public Builder setNewExpGroupBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      newExpGroup_ = value;
+      onChanged();
+      return this;
+    }
     @java.lang.Override
     public final Builder setUnknownFields(
         final com.google.protobuf.UnknownFieldSet unknownFields) {

+ 12 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequestOrBuilder.java

@@ -212,4 +212,16 @@ public interface RecommendRequestOrBuilder extends
    * <code>.MachineInfoProto machine_info = 15;</code>
    */
   com.tzld.piaoquan.recommend.server.gen.recommend.MachineInfoProtoOrBuilder getMachineInfoOrBuilder();
+
+  /**
+   * <code>string new_exp_group = 16;</code>
+   * @return The newExpGroup.
+   */
+  java.lang.String getNewExpGroup();
+  /**
+   * <code>string new_exp_group = 16;</code>
+   * @return The bytes for newExpGroup.
+   */
+  com.google.protobuf.ByteString
+      getNewExpGroupBytes();
 }

+ 1 - 0
recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/recommend.proto

@@ -24,6 +24,7 @@ message RecommendRequest {
   string city = 13;
   string province = 14;
   MachineInfoProto machine_info = 15;
+  string new_exp_group = 16;
 }
 
 message MachineInfoProto {

+ 1 - 1
recommend-server-service/pom.xml

@@ -142,7 +142,7 @@
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>
             <artifactId>recommend-server-client</artifactId>
-            <version>1.0.1</version>
+            <version>1.0.2</version>
         </dependency>
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>

+ 4 - 1
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java

@@ -21,7 +21,7 @@ public class RecommendParam {
     private String abCode;
     private String ruleKey;
     private String dataKey;
-    
+
     // hardcode   兼容旧服务的518实验
     private String hDataKey;
     private String hRuleKey;
@@ -48,4 +48,7 @@ public class RecommendParam {
     private String city;
     private Set<String> abExpCodes;
 
+    // 层 - 实验
+    private Map<String, String> expIdMap;
+
 }

+ 6 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java

@@ -3,6 +3,7 @@ package com.tzld.piaoquan.recommend.server.service;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.google.common.base.Stopwatch;
 import com.google.common.base.Strings;
+import com.google.common.reflect.TypeToken;
 import com.tzld.piaoquan.recommend.server.common.enums.AppTypeEnum;
 import com.tzld.piaoquan.recommend.server.gen.common.Result;
 import com.tzld.piaoquan.recommend.server.gen.recommend.MachineInfoProto;
@@ -344,6 +345,9 @@ public class RecommendService {
             param.setMachineInfo(machineInfo);
         }
 
+        param.setExpIdMap(JSONUtils.fromJson(request.getNewExpGroup(), new TypeToken<Map<String, String>>() {
+        }, Collections.emptyMap()));
+
 
         return param;
     }
@@ -413,6 +417,7 @@ public class RecommendService {
         recallParam.setAbExpCodes(param.getAbExpCodes());
 
         recallParam.setProvince(param.getProvince());
+        recallParam.setExpIdMap(param.getExpIdMap());
 
 
         return recallParam;
@@ -433,6 +438,7 @@ public class RecommendService {
         rankParam.setCity(param.getCity());
         rankParam.setMachineInfo(param.getMachineInfo());
         rankParam.setAbExpCodes(param.getAbExpCodes());
+        rankParam.setExpIdMap(param.getExpIdMap());
 
         return rankParam;
     }

+ 4 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankParam.java

@@ -4,6 +4,7 @@ import com.tzld.piaoquan.recommend.server.model.MachineInfo;
 import com.tzld.piaoquan.recommend.server.service.recall.RecallResult;
 import lombok.Data;
 
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -25,4 +26,7 @@ public class RankParam {
     private MachineInfo machineInfo;
     private Set<String> abExpCodes;
 
+    // 层 - 实验
+    private Map<String, String> expIdMap;
+
 }

+ 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());

+ 23 - 13
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorBoost.java

@@ -1,6 +1,7 @@
 package com.tzld.piaoquan.recommend.server.service.rank.processor;
 
 import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.util.ProbabilityCalculator;
 import org.apache.commons.collections4.CollectionUtils;
 
 import java.math.BigDecimal;
@@ -19,26 +20,35 @@ public class RankProcessorBoost {
         if (CollectionUtils.isEmpty(rovList) || rulesMap == null || rulesMap.isEmpty()) {
             return;
         }
-        Map<String, Double> densityRules = new HashMap<>();
+        Map<String, Double> boostMap = new HashMap<>(rulesMap.size());
         for (Map.Entry<String, Map<String, String>> entry : rulesMap.entrySet()) {
             String key = entry.getKey();
-            Map<String, String> value = entry.getValue();
-            if (value.containsKey("boost")) {
-                densityRules.put(key, Double.valueOf(value.get("boost")));
-            }
-        }
+            Map<String, String> rule = entry.getValue();
+            String boostRate = rule.get("boost");
+            String boostDate = rule.get("boost_date");
 
+            // 使用 calculateCurrentProbability 方法计算当前概率
+            double currentProbability = ProbabilityCalculator.calculateCurrentProbability(boostRate, boostDate);
+            boostMap.put(key, currentProbability);
+        }
 
-        for (Map.Entry<String, Double> entry : densityRules.entrySet()) {
-            rovList.stream().filter(video -> video.getTags().contains(entry.getKey()))
-                    .forEach(video -> video.setSortScore(
-                            BigDecimal.valueOf(video.getSortScore())
-                                    .multiply(BigDecimal.valueOf(entry.getValue()))
-                                    .doubleValue()));
+        for (Map.Entry<String, Double> entry : boostMap.entrySet()) {
+            if (entry.getValue() <= 0) {
+                continue;
+            }
+            try {
+                Double value = entry.getValue();
+                // 给每个tag的视频提权(乘 value)
+                rovList.stream().filter(video -> video.getTags().contains(entry.getKey()))
+                        .forEach(video -> video.setSortScore(
+                                BigDecimal.valueOf(video.getSortScore())
+                                        .multiply(BigDecimal.valueOf(value))
+                                        .doubleValue()));
+            } catch (Exception ignored) {
+            }
         }
         rovList.sort((o1, o2) -> Double.compare(o2.getSortScore(), o1.getSortScore()));
 
     }
 
-
 }

+ 41 - 24
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorInsert.java

@@ -2,12 +2,12 @@ package com.tzld.piaoquan.recommend.server.service.rank.processor;
 
 import com.tzld.piaoquan.recommend.server.model.Video;
 import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
+import com.tzld.piaoquan.recommend.server.util.DateUtils;
 import com.tzld.piaoquan.recommend.server.util.MathUtil;
 import com.tzld.piaoquan.recommend.server.util.WeightRandom;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 
-import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -24,34 +24,51 @@ public class RankProcessorInsert {
         if (CollectionUtils.isEmpty(rovList) || rulesMap == null || rulesMap.isEmpty()) {
             return;
         }
-        String insertRules = null, tagName = null;
+        String tagName = null, insertWeight = null;
         for (Map.Entry<String, Map<String, String>> entry : rulesMap.entrySet()) {
             Map<String, String> value = entry.getValue();
 
-            if ("小年".equals(entry.getKey())){
-                String provinceCn = param.getProvince();
-                if (provinceCn == null){
-                    provinceCn = "中国";
-                }else{
-                    provinceCn = provinceCn.replaceAll("省$", "");
-                }
-                boolean ifNorth = NORTHERN_PROVINCES.contains(provinceCn);
-                Calendar calendar = Calendar.getInstance();
-                String date = new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
-                if (ifNorth && date.compareTo("20240202")>0){
-                    continue;
+//            if ("小年".equals(entry.getKey())){
+//                String provinceCn = param.getProvince();
+//                if (provinceCn == null){
+//                    provinceCn = "中国";
+//                }else{
+//                    provinceCn = provinceCn.replaceAll("省$", "");
+//                }
+//                boolean ifNorth = NORTHERN_PROVINCES.contains(provinceCn);
+//                Calendar calendar = Calendar.getInstance();
+//                String date = new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
+//                if (ifNorth && date.compareTo("20240202")>0){
+//                    continue;
+//                }
+//            }
+
+            String insertDates = value.get("insert_date");
+            String insertRules = value.get("insert");
+            if (StringUtils.isBlank(insertDates) || StringUtils.isBlank(insertRules)) {
+                continue;
+            }
+            String[] insertDateArr = insertDates.split(",");
+            String[] insertWeights = insertRules.split(";");
+            if (insertDateArr.length != insertWeights.length) {
+                continue;
+            }
+            for (int i = 0; i < insertDateArr.length; i++) {
+                String insertDate = insertDateArr[i];
+                // 判断是否在允许强插的时间范围内
+                boolean ifTimeRangeInNow = DateUtils.ifTimeRangeInNow(insertDate);
+                if (ifTimeRangeInNow) {
+                    tagName = entry.getKey();
+                    insertWeight = insertWeights[i];
+                    break;
                 }
             }
-
-            if (value.containsKey("insert")) {
-                insertRules = value.get("insert");
-                tagName = entry.getKey();
+            // 如果已经筛选出强插的tag以及对应权重,就不再继续遍历
+            if (StringUtils.isNotBlank(tagName) && StringUtils.isNotBlank(insertWeight)) {
                 break;
             }
         }
-        if (StringUtils.isBlank(insertRules) || StringUtils.isBlank(tagName)) {
-            return;
-        }
+
         final String finalTagName = tagName;
 
         // 判断是否前几个已经有该tag的视频了
@@ -65,7 +82,7 @@ public class RankProcessorInsert {
         // 获取需要插入的视频
         Video insertTagVideo = null;
         int tagVideoIndex = -1;
-        for (int i = 0; i < rovList.size(); i++) {
+        for (int i = param.getSize(); i < rovList.size(); i++) {
             if (rovList.get(i).getTags().contains(finalTagName)) {
                 insertTagVideo = rovList.get(i);
                 tagVideoIndex = i;
@@ -77,8 +94,8 @@ public class RankProcessorInsert {
         }
 
         // 获取插入的权重
-        String[] insertWeight = insertRules.split(",");
-        List<Double> insertWeightList = Arrays.stream(insertWeight)
+        String[] insertWeightArr = insertWeight.split(",");
+        List<Double> insertWeightList = Arrays.stream(insertWeightArr)
                 .map(Double::valueOf).collect(Collectors.toList());
 
         if (CollectionUtils.size(insertWeightList) != 5) {

+ 28 - 65
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorTagFilter.java

@@ -1,98 +1,61 @@
 package com.tzld.piaoquan.recommend.server.service.rank.processor;
+
 import com.tzld.piaoquan.recommend.server.model.Video;
-import org.apache.commons.lang3.tuple.Pair;
+import com.tzld.piaoquan.recommend.server.util.ProbabilityCalculator;
 
-import java.text.SimpleDateFormat;
 import java.util.*;
 public class RankProcessorTagFilter {
 
-    public static void processor(List<Video> rov, List<Video> flow, Map<String, Map<String, String>> rule) {
+    public static void processor(List<Video> rov, List<Video> flow, Map<String, Map<String, String>> rules) {
+
+        Set<String> filterTags = new HashSet<>();
+        Random random = new Random();
 
-        Map<String, Double> tag2Rate = new HashMap<>();
-        Map<String, List<Pair<String, String>>> tag2Dates = new HashMap<>();
-        for (Map.Entry<String, Map<String, String>> entry : rule.entrySet()){
+        // 遍历每一个规则条目
+        for (Map.Entry<String, Map<String, String>> entry : rules.entrySet()) {
             String key = entry.getKey();
-            Map<String, String> value = entry.getValue();
-            if (value.containsKey("filter_rate")){
-                tag2Rate.put(key, Double.valueOf(value.get("filter_rate")));
-            }
-            if (value.containsKey("filter_date")){
-                List<Pair<String, String>> tmpList = new ArrayList<>();
-                for (String tmp : value.get("filter_date").split(",")){
-                    String start = tmp.split("-")[0];
-                    String end = tmp.split("-")[1];
-                    tmpList.add(Pair.of(start, end));
+            Map<String, String> rule = entry.getValue();
+            String filterRate = rule.get("filter_rate");
+            String filterDate = rule.get("filter_date");
+
+            // 使用 calculateCurrentProbability 方法计算当前概率
+            double currentProbability = ProbabilityCalculator.calculateCurrentProbability(filterRate, filterDate);
+
+            // 生成随机浮点数并与 filter_rate 比较
+            if (currentProbability > 0) { // 确保有有效的概率
+                double randomValue = random.nextDouble();
+                if (randomValue < currentProbability) {
+                    filterTags.add(key);
                 }
-                tag2Dates.put(key, tmpList);
             }
         }
 
-        // 通过过滤概率获取本轮过滤tag集合
-        Set<String> filterTags = new HashSet<>();
-        for (Map.Entry<String, Double> entry : tag2Rate.entrySet()) {
-            String key = entry.getKey();
-            Double value = entry.getValue();
-            if (Math.random() <= value){
-                filterTags.add(key);
-            }
+        if (filterTags.isEmpty()) {
+            return;
         }
 
-        // 获取系统时间
-        Calendar calendar = Calendar.getInstance();
-        String dateHour = new SimpleDateFormat("yyyyMMddHH").format(calendar.getTime());
-
         //执行过滤
         Iterator<Video> iterator = rov.iterator();
         while (iterator.hasNext()) {
             Video video = iterator.next();
             List<String> tags = video.getTags();
-            boolean filter = false;
-            for (String tag : tags){
-                if (!filterTags.contains(tag)){
-                    continue;
-                }
-                boolean flag = ifFiter(tag2Dates, tag, dateHour);
-                if (flag){
-                    filter = true;
-                    break;
+            for (String tag : tags) {
+                if (filterTags.contains(tag)) {
+                    iterator.remove();
                 }
             }
-            if (filter){
-                iterator.remove();
-            }
         }
 
         iterator = flow.iterator();
         while (iterator.hasNext()) {
             Video video = iterator.next();
             List<String> tags = video.getTags();
-            boolean filter = false;
-            for (String tag : tags){
-                if (!filterTags.contains(tag)){
-                    continue;
-                }
-                boolean flag = ifFiter(tag2Dates, tag, dateHour);
-                if (flag){
-                    filter = true;
-                    break;
+            for (String tag : tags) {
+                if (filterTags.contains(tag)) {
+                    iterator.remove();
                 }
             }
-            if (filter){
-                iterator.remove();
-            }
-        }
-    }
-
-    public static boolean ifFiter(Map<String, List<Pair<String, String>>> tag2Dates, String tag, String dateHour){
-        if (!tag2Dates.containsKey(tag) || tag2Dates.get(tag).isEmpty()){
-            return false;
-        }
-        for (Pair<String, String> d: tag2Dates.get(tag)){
-            if (dateHour.compareTo(d.getLeft()) >= 0 && dateHour.compareTo(d.getRight()) < 0){
-                return true;
-            }
         }
-        return false;
     }
 
 }

+ 5 - 4
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4Density.java

@@ -6,12 +6,11 @@ import com.tzld.piaoquan.recommend.server.model.Video;
 import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
 import com.tzld.piaoquan.recommend.server.service.rank.RankResult;
 import com.tzld.piaoquan.recommend.server.service.rank.RankService;
-import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorFeature;
+import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorItemTags;
 import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorBoost;
 import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorDensity;
 import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorInsert;
 import com.tzld.piaoquan.recommend.server.service.rank.processor.RankProcessorTagFilter;
-import com.tzld.piaoquan.recommend.server.service.rank.extractor.RankExtractorItemTags;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.RandomUtils;
@@ -29,13 +28,15 @@ import java.util.stream.Collectors;
 @Service
 @Slf4j
 public class RankStrategy4Density extends RankService {
-    @ApolloJsonValue("${RankStrategy4DensityFilter:}")
+    @ApolloJsonValue("${RankStrategy4DensityFilterV2:}")
     private Map<String,Map<String, Map<String, String>>> filterRules = new HashMap<>();
+
+
     @Override
     public RankResult mergeAndSort(RankParam param, List<Video> rovVideos, List<Video> flowVideos) {
 
          //1 兜底策略,rov池子不足时,用冷启池填补。直接返回。
-        if (CollectionUtils.isEmpty(rovVideos)) {
+        if (CollectionUtils.isEmpty(rovVideos) || filterRules == null || filterRules.isEmpty()) {
             if (param.getSize() < flowVideos.size()) {
                 return new RankResult(flowVideos.subList(0, param.getSize()));
             } else {

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

@@ -49,7 +49,7 @@ import java.util.stream.Collectors;
 public class RankStrategy4RegionMergeModelV3 extends RankService {
     @ApolloJsonValue("${rank.score.merge.weight:}")
     private Map<String, Double> mergeWeight;
-    @ApolloJsonValue("${RankStrategy4DensityFilter:}")
+    @ApolloJsonValue("${RankStrategy4DensityFilterV2:}")
     private Map<String,Map<String, Map<String, String>>> filterRules = new HashMap<>();
     final private String CLASS_NAME = this.getClass().getSimpleName();
     public void duplicate(Set<Long> setVideo, List<Video> videos){

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

@@ -43,7 +43,7 @@ import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 public class RankStrategy4RegionMergeModelV6 extends RankService {
     @ApolloJsonValue("${rank.score.merge.weight:}")
     private Map<String, Double> mergeWeight;
-    @ApolloJsonValue("${RankStrategy4DensityFilter:}")
+    @ApolloJsonValue("${RankStrategy4DensityFilterV2:}")
     private Map<String,Map<String, Map<String, String>>> filterRules = new HashMap<>();
     final private String CLASS_NAME = this.getClass().getSimpleName();
     public void duplicate(Set<Long> setVideo, List<Video> videos){

+ 2 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallParam.java

@@ -33,5 +33,7 @@ public class RecallParam {
     private Map<Integer, List<String>> appRegionFiltered;
     private List<Long> videosWithRisk;
     private Set<String> abExpCodes;
+    // 层 - 实验
+    private Map<String, String> expIdMap;
 
 }

+ 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() {

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

@@ -0,0 +1,195 @@
+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);
+    }
+
+    @Override
+    public List<Pair<Long, Double>> recall(Map<String, String> params) {
+        // 节假日、时效性,判断
+        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");
+        if (StringUtils.isBlank(yearlyFestivalTimeRange)) {
+            return new ArrayList<>();
+        }
+        JSONObject jsonObject = JSONObject.parseObject(yearlyFestivalTimeRange);
+        for (String festival : jsonObject.keySet()) {
+            try {
+                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");
+        if (StringUtils.isBlank(dailyFestivalTimeRange)) {
+            return new ArrayList<>();
+        }
+        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;
+    }
+
+
+}

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

@@ -1,5 +1,7 @@
 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;
@@ -10,129 +12,10 @@ 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 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);
     }
@@ -146,14 +29,11 @@ public class FestivalRecallScore extends AbstractScorer4Recall {
             ,"辽宁","吉林","黑龙江","山东","河南","陕西","甘肃","宁夏","新疆"
     ));
 
-
-
     @Override
     public List<Pair<Long, Double>> recall(Map<String, String> params) {
         // 1 获取省份,判断南北 小年
-        String key = params.getOrDefault("region_province", "中国");
-        boolean ifNorth = NORTHERN_PROVINCES.contains(key);
-
+//        String key = params.getOrDefault("region_province", "中国");
+//        boolean ifNorth = NORTHERN_PROVINCES.contains(key);
 
         // 节假日、时效性,判断
         Model4RecallKeyValue model = (Model4RecallKeyValue) this.getModel();
@@ -162,63 +42,47 @@ public class FestivalRecallScore extends AbstractScorer4Recall {
         }
         LocalDateTime now = LocalDateTime.now();
         // 节日祝福-每年
-        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 = "小年";
-            }
 
-            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);
-            }
+        String yearlyFestivalTimeRange = params.get("yearly_festival_time_range");
+        if (StringUtils.isBlank(yearlyFestivalTimeRange)) {
+            return new ArrayList<>();
         }
-        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()) {
+        JSONObject jsonObject = JSONObject.parseObject(yearlyFestivalTimeRange);
+        List<List<Pair<Long, Double>>> yearResultList = new ArrayList<>();
+        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;
                 }
-                festivalLists = festivalLists.stream().map(pair -> Pair.of(pair.getLeft(), 0.0))
-                        .limit(Math.min(50, festivalLists.size()))
-                        .collect(Collectors.toList());
-                dayResult.addAll(festivalLists);
+                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;
+                    }
+                    yearResultList.add(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 ListMerger.mergeLists(yearResultList);
     }
 
     public Pair<LocalDateTime, LocalDateTime> getStartTimeAndEndTime(String timeRangeList) {

+ 28 - 2
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/DateUtils.java

@@ -1,6 +1,8 @@
 package com.tzld.piaoquan.recommend.server.util;
 
 import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Calendar;
 import java.util.Date;
 
@@ -28,10 +30,34 @@ public final class DateUtils {
         return dateFormat.format(previousDate);
     }
 
-    public static void main(String[] args){
+
+    public static boolean ifTimeRangeInNow(String timeRange) {
+        try {
+
+            String[] split = timeRange.split("-");
+            if (split.length != 2) {
+                return false;
+            }
+            String startTime = split[0];
+            String endTime = split[1];
+            if (startTime.length() != 10 || endTime.length() != 10) {
+                return false;
+            }
+            LocalDateTime now = LocalDateTime.now();
+            LocalDateTime start = LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyyMMddHH"));
+            LocalDateTime end = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyyMMddHH"));
+            return now.equals(start) || (now.isAfter(start) && now.isBefore(end));
+        } catch (Exception e) {
+//            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    public static void main(String[] args) {
         Calendar calendar = Calendar.getInstance();
 
-        System.out.println((calendar.get(Calendar.DAY_OF_WEEK) + 6) % 7 );
+        System.out.println((calendar.get(Calendar.DAY_OF_WEEK) + 6) % 7);
         System.out.println(new SimpleDateFormat("yyyyMMdd").format(calendar.getTime()));
         System.out.println(new SimpleDateFormat("HH").format(calendar.getTime()));
 

+ 18 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/ListMerger.java

@@ -31,6 +31,24 @@ public class ListMerger {
         return result;
     }
 
+    public static <T> List<T> mergeLists(List<List<T>> lists) {
+        List<T> result = new ArrayList<>();
+        int maxSize = 0;
+        for (List<T> list : lists) {
+            maxSize = Math.max(maxSize, list.size());
+        }
+
+        for (int i = 0; i < maxSize; i++) {
+            for (List<T> list : lists) {
+                if (i < list.size()) {
+                    result.add(list.get(i));
+                }
+            }
+        }
+
+        return result;
+    }
+
     public static void main(String[] args) {
         // 示例
         List<Integer> list1 = Lists.newArrayList(1, 4, 7);

+ 79 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/ProbabilityCalculator.java

@@ -0,0 +1,79 @@
+package com.tzld.piaoquan.recommend.server.util;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author sunxy
+ */
+public class ProbabilityCalculator {
+
+    static class DateRange {
+        LocalDateTime start;
+        LocalDateTime end;
+
+        DateRange(LocalDateTime start, LocalDateTime end) {
+            this.start = start;
+            this.end = end;
+        }
+    }
+
+    static class RateRange {
+        double start;
+        double end;
+
+        RateRange(double start, double end) {
+            this.start = start;
+            this.end = end;
+        }
+    }
+
+    public static double calculateCurrentProbability(String filterRate, String filterDate) {
+        // 解析日期区间
+        String[] dateRanges = filterDate.split(",");
+        List<DateRange> parsedDateRanges = new ArrayList<>();
+        for (String range : dateRanges) {
+            String[] dates = range.split("-");
+            LocalDateTime start = LocalDateTime.parse(dates[0], DateTimeFormatter.ofPattern("yyyyMMddHH"));
+            LocalDateTime end = LocalDateTime.parse(dates[1], DateTimeFormatter.ofPattern("yyyyMMddHH"));
+            parsedDateRanges.add(new DateRange(start, end));
+        }
+
+        // 解析概率区间
+        String[] rateRanges = filterRate.split(",");
+        List<RateRange> parsedRateRanges = new ArrayList<>();
+        for (String range : rateRanges) {
+            String[] rates = range.split("-");
+            double start = Double.parseDouble(rates[0]);
+            double end = Double.parseDouble(rates[1]);
+            parsedRateRanges.add(new RateRange(start, end));
+        }
+
+        // 获取当前时间
+        LocalDateTime now = LocalDateTime.now();
+
+        // 确定当前时间属于哪个日期区间,并计算概率
+        for (int i = 0; i < parsedDateRanges.size(); i++) {
+            DateRange dateRange = parsedDateRanges.get(i);
+            if (now.isEqual(dateRange.start) || (now.isAfter(dateRange.start) && now.isBefore(dateRange.end))) {
+                RateRange rateRange = parsedRateRanges.get(i);
+                long totalMinutes = dateRange.end.atZone(java.time.ZoneId.systemDefault()).toEpochSecond() - dateRange.start.atZone(java.time.ZoneId.systemDefault()).toEpochSecond();
+                long elapsedMinutes = now.atZone(java.time.ZoneId.systemDefault()).toEpochSecond() - dateRange.start.atZone(java.time.ZoneId.systemDefault()).toEpochSecond();
+                double elapsedRatio = (double) elapsedMinutes / totalMinutes;
+                return rateRange.start + ((rateRange.end - rateRange.start) * elapsedRatio);
+            }
+        }
+
+        // 如果当前时间不在任何配置的日期区间内,返回-1表示无效
+        return -1;
+    }
+
+    public static void main(String[] args) {
+        double probability = calculateCurrentProbability("0.8-1.0,0.5-0.6", "2024020312-2024020400," +
+                "2024020400-2024020702");
+        System.out.println("Current Probability: " + probability);
+    }
+
+}

+ 1 - 2
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/web/RecommendController.java

@@ -12,8 +12,6 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.slf4j.MDC;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -23,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
  */
 @RestController
 @Slf4j
+@Deprecated
 public class RecommendController {
     @Autowired
     private RecommendService recommendService;

+ 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"
+  }
+}