Pārlūkot izejas kodu

Merge branch 'feature/dnn-rank-demo' of algorithm/recommend-server into master

zhaohaipeng 1 mēnesi atpakaļ
vecāks
revīzija
d5d8485c8f
31 mainītis faili ar 1215 papildinājumiem un 699 dzēšanām
  1. 1 1
      recommend-server-client/pom.xml
  2. 23 23
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/Recommend.java
  3. 138 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequest.java
  4. 12 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequestOrBuilder.java
  5. 1 0
      recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/recommend.proto
  6. 7 1
      recommend-server-service/pom.xml
  7. 1 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/RankItem.java
  8. 2 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java
  9. 15 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/Tuple4.java
  10. 26 5
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/FeatureService.java
  11. 7 59
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java
  12. 1 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/WarmUpService.java
  13. 9 9
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/flowpool/FlowPoolService.java
  14. 1 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankParam.java
  15. 1 11
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java
  16. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/processor/RankProcessorBoost.java
  17. 265 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelDNNDemo.java
  18. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV536.java
  19. 45 54
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV562.java
  20. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV566.java
  21. 2 2
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV568.java
  22. 183 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FGEncoder.java
  23. 55 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FGEncoderManager.java
  24. 159 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FeatureV6.java
  25. 1 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallParam.java
  26. 1 5
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java
  27. 0 77
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/AppTypeSpecialRecallStrategy.java
  28. 93 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/PAIScorer.java
  29. 145 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/model/PAIModel.java
  30. 15 2
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/FeatureUtils.java
  31. 3 446
      recommend-server-service/src/main/resources/feeds_score_config_xgb_ros_20250311.conf

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

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

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

@@ -61,7 +61,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\"\217\006\n\020RecommendRequest\022\022\n\nrequest" +
+      "on.proto\"\241\006\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_" +
@@ -79,27 +79,27 @@ public final class Recommend {
       "um\030\032 \001(\005\022\025\n\rrootSessionId\030\033 \001(\t\022)\n\nshare" +
       "_list\030\034 \003(\0132\025.VideoActionInfoProto\022\030\n\020re" +
       "quest_video_id\030\035 \001(\003\022\033\n\023current_page_sou" +
-      "rce\030\036 \001(\t\022\017\n\007openGId\030\037 \001(\t\032.\n\014EventIdEnt" +
-      "ry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\177\n\020Ma" +
-      "chineInfoProto\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\021RecommendResponse\022\027\n\006result\030\001 \001(\013" +
-      "2\007.Result\022\032\n\005video\030\002 \003(\0132\013.VideoProto\"\336\001" +
-      "\n\nVideoProto\022\020\n\010video_id\030\001 \001(\003\022\021\n\trov_sc" +
-      "ore\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\010position\030\006 " +
-      "\001(\005\022\021\n\tflow_pool\030\007 \001(\t\022\027\n\017is_in_flow_poo" +
-      "l\030\010 \001(\005\022\014\n\004rand\030\t \001(\001\022\'\n\017push_from_index" +
-      "\030\n \003(\0132\016.PushFromIndex\"1\n\rPushFromIndex\022" +
-      "\021\n\tpush_from\030\001 \001(\t\022\r\n\005index\030\002 \003(\t\"4\n\024Vid" +
-      "eoActionInfoProto\022\020\n\010video_id\030\001 \001(\003\022\n\n\002t" +
-      "s\030\002 \001(\0032\212\001\n\020RecommendService\022:\n\021Homepage" +
-      "Recommend\022\021.RecommendRequest\032\022.Recommend" +
-      "Response\022:\n\021RelevantRecommend\022\021.Recommen" +
-      "dRequest\032\022.RecommendResponseB7\n0com.tzld" +
-      ".piaoquan.recommend.server.gen.recommend" +
-      "P\001\210\001\001b\006proto3"
+      "rce\030\036 \001(\t\022\017\n\007openGId\030\037 \001(\t\022\020\n\010union_id\030 " +
+      " \001(\t\032.\n\014EventIdEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005val" +
+      "ue\030\002 \001(\t:\0028\001\"\177\n\020MachineInfoProto\022\r\n\005bran" +
+      "d\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\021RecommendRespon" +
+      "se\022\027\n\006result\030\001 \001(\0132\007.Result\022\032\n\005video\030\002 \003" +
+      "(\0132\013.VideoProto\"\336\001\n\nVideoProto\022\020\n\010video_" +
+      "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_score\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(\001\022" +
+      "\'\n\017push_from_index\030\n \003(\0132\016.PushFromIndex" +
+      "\"1\n\rPushFromIndex\022\021\n\tpush_from\030\001 \001(\t\022\r\n\005" +
+      "index\030\002 \003(\t\"4\n\024VideoActionInfoProto\022\020\n\010v" +
+      "ideo_id\030\001 \001(\003\022\n\n\002ts\030\002 \001(\0032\212\001\n\020RecommendS" +
+      "ervice\022:\n\021HomepageRecommend\022\021.RecommendR" +
+      "equest\032\022.RecommendResponse\022:\n\021RelevantRe" +
+      "commend\022\021.RecommendRequest\032\022.RecommendRe" +
+      "sponseB7\n0com.tzld.piaoquan.recommend.se" +
+      "rver.gen.recommendP\001\210\001\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -112,7 +112,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", "NewExpGroup", "SessionId", "SubSessionId", "PageSource", "CategoryId", "HotSceneType", "ClientIp", "VersionCode", "RootSourceId", "UserShareDepth", "PageNum", "RootSessionId", "ShareList", "RequestVideoId", "CurrentPageSource", "OpenGId", });
+        new java.lang.String[] { "RequestId", "Mid", "Uid", "Size", "AppType", "CityCode", "ProvinceCode", "AbExpCode", "EventId", "VersionAuditStatus", "RecommendTraceId", "VideoId", "City", "Province", "MachineInfo", "NewExpGroup", "SessionId", "SubSessionId", "PageSource", "CategoryId", "HotSceneType", "ClientIp", "VersionCode", "RootSourceId", "UserShareDepth", "PageNum", "RootSessionId", "ShareList", "RequestVideoId", "CurrentPageSource", "OpenGId", "UnionId", });
     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

@@ -36,6 +36,7 @@ private static final long serialVersionUID = 0L;
     shareList_ = java.util.Collections.emptyList();
     currentPageSource_ = "";
     openGId_ = "";
+    unionId_ = "";
   }
 
   @java.lang.Override
@@ -266,6 +267,12 @@ private static final long serialVersionUID = 0L;
             openGId_ = s;
             break;
           }
+          case 258: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            unionId_ = s;
+            break;
+          }
           default: {
             if (!parseUnknownField(
                 input, unknownFields, extensionRegistry, tag)) {
@@ -1297,6 +1304,44 @@ private static final long serialVersionUID = 0L;
     }
   }
 
+  public static final int UNION_ID_FIELD_NUMBER = 32;
+  private volatile java.lang.Object unionId_;
+  /**
+   * <code>string union_id = 32;</code>
+   * @return The unionId.
+   */
+  @java.lang.Override
+  public java.lang.String getUnionId() {
+    java.lang.Object ref = unionId_;
+    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();
+      unionId_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string union_id = 32;</code>
+   * @return The bytes for unionId.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getUnionIdBytes() {
+    java.lang.Object ref = unionId_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      unionId_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
   private byte memoizedIsInitialized = -1;
   @java.lang.Override
   public final boolean isInitialized() {
@@ -1407,6 +1452,9 @@ private static final long serialVersionUID = 0L;
     if (!getOpenGIdBytes().isEmpty()) {
       com.google.protobuf.GeneratedMessageV3.writeString(output, 31, openGId_);
     }
+    if (!getUnionIdBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 32, unionId_);
+    }
     unknownFields.writeTo(output);
   }
 
@@ -1532,6 +1580,9 @@ private static final long serialVersionUID = 0L;
     if (!getOpenGIdBytes().isEmpty()) {
       size += com.google.protobuf.GeneratedMessageV3.computeStringSize(31, openGId_);
     }
+    if (!getUnionIdBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(32, unionId_);
+    }
     size += unknownFields.getSerializedSize();
     memoizedSize = size;
     return size;
@@ -1612,6 +1663,8 @@ private static final long serialVersionUID = 0L;
         .equals(other.getCurrentPageSource())) return false;
     if (!getOpenGId()
         .equals(other.getOpenGId())) return false;
+    if (!getUnionId()
+        .equals(other.getUnionId())) return false;
     if (!unknownFields.equals(other.unknownFields)) return false;
     return true;
   }
@@ -1696,6 +1749,8 @@ private static final long serialVersionUID = 0L;
     hash = (53 * hash) + getCurrentPageSource().hashCode();
     hash = (37 * hash) + OPENGID_FIELD_NUMBER;
     hash = (53 * hash) + getOpenGId().hashCode();
+    hash = (37 * hash) + UNION_ID_FIELD_NUMBER;
+    hash = (53 * hash) + getUnionId().hashCode();
     hash = (29 * hash) + unknownFields.hashCode();
     memoizedHashCode = hash;
     return hash;
@@ -1921,6 +1976,8 @@ private static final long serialVersionUID = 0L;
 
       openGId_ = "";
 
+      unionId_ = "";
+
       return this;
     }
 
@@ -1996,6 +2053,7 @@ private static final long serialVersionUID = 0L;
       result.requestVideoId_ = requestVideoId_;
       result.currentPageSource_ = currentPageSource_;
       result.openGId_ = openGId_;
+      result.unionId_ = unionId_;
       onBuilt();
       return result;
     }
@@ -2184,6 +2242,10 @@ private static final long serialVersionUID = 0L;
         openGId_ = other.openGId_;
         onChanged();
       }
+      if (!other.getUnionId().isEmpty()) {
+        unionId_ = other.unionId_;
+        onChanged();
+      }
       this.mergeUnknownFields(other.unknownFields);
       onChanged();
       return this;
@@ -4505,6 +4567,82 @@ private static final long serialVersionUID = 0L;
       onChanged();
       return this;
     }
+
+    private java.lang.Object unionId_ = "";
+    /**
+     * <code>string union_id = 32;</code>
+     * @return The unionId.
+     */
+    public java.lang.String getUnionId() {
+      java.lang.Object ref = unionId_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        unionId_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string union_id = 32;</code>
+     * @return The bytes for unionId.
+     */
+    public com.google.protobuf.ByteString
+        getUnionIdBytes() {
+      java.lang.Object ref = unionId_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        unionId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string union_id = 32;</code>
+     * @param value The unionId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setUnionId(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      unionId_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string union_id = 32;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearUnionId() {
+      
+      unionId_ = getDefaultInstance().getUnionId();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string union_id = 32;</code>
+     * @param value The bytes for unionId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setUnionIdBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      unionId_ = 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

@@ -390,4 +390,16 @@ public interface RecommendRequestOrBuilder extends
    */
   com.google.protobuf.ByteString
       getOpenGIdBytes();
+
+  /**
+   * <code>string union_id = 32;</code>
+   * @return The unionId.
+   */
+  java.lang.String getUnionId();
+  /**
+   * <code>string union_id = 32;</code>
+   * @return The bytes for unionId.
+   */
+  com.google.protobuf.ByteString
+      getUnionIdBytes();
 }

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

@@ -40,6 +40,7 @@ message RecommendRequest {
   int64 request_video_id = 29;
   string current_page_source = 30;
   string openGId = 31;
+  string union_id = 32;
 }
 
 message MachineInfoProto {

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

@@ -175,7 +175,7 @@
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>
             <artifactId>recommend-server-client</artifactId>
-            <version>1.1.12</version>
+            <version>1.1.13</version>
         </dependency>
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>
@@ -274,6 +274,12 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-openfeign</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>com.aliyun.openservices.eas</groupId>
+            <artifactId>eas-sdk</artifactId>
+            <version>2.0.29</version>
+        </dependency>
     </dependencies>
 
 

+ 1 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/RankItem.java

@@ -19,6 +19,7 @@ public class RankItem implements Comparable<RankItem> {
     // 所有特征,包括视频、用户等等
     public Map<String, Float> allFeatureMap = new HashMap<>();
     public Map<String, Double> featureMapDouble = new HashMap<>();
+    public Map<String, String> featureMapString = new HashMap<>();
     public String id;
     public Map<String, Double> scoresMap = new HashMap<>();
     public Map<String, String> itemBasicFeature = new HashMap<>();

+ 2 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java

@@ -62,5 +62,7 @@ public class RecommendParam {
 
     private Map<String, String> creativeInfoFeature;
     private String openGId;
+
+    private String unionId;
 }
 

+ 15 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/Tuple4.java

@@ -0,0 +1,15 @@
+package com.tzld.piaoquan.recommend.server.model;
+
+import lombok.Data;
+
+@Data
+public class Tuple4<T1, T2, T3, T4> {
+
+    private T1 v1;
+
+    private T2 v2;
+
+    private T3 v3;
+
+    private T4 v4;
+}

+ 26 - 5
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/FeatureService.java

@@ -59,6 +59,15 @@ public class FeatureService {
         return feature.getVideoFeature();
     }
 
+    public Map<String, Map<String, String>> getUnionIdFeature(String unionId) {
+        if (StringUtils.isBlank(unionId)) {
+            return new HashMap<>();
+        }
+        List<FeatureKeyProto> protos = new ArrayList<>();
+        protos.add(genWithUnionId("alg_user_network_seq_feature", unionId));
+        return this.getFeatureByProto(protos).getUserFeature();
+    }
+
     /**
      * @return k1:视频、k2:表、k3:特征、v:特征值
      */
@@ -125,12 +134,12 @@ public class FeatureService {
                 String merge_cate1 = baseInfo.getOrDefault("merge_first_level_cate", "unknown").trim();
                 protos.add(genWithKeyMap("alg_merge_cate1_recommend_exp_feature_20250212", vid, ImmutableMap.of("merge_cate1", merge_cate1)));
                 // 特殊情况
-                //protos.add(genWithKeyMap("mid_merge_cate1_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate1", merge_cate1)));
+                // protos.add(genWithKeyMap("mid_merge_cate1_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate1", merge_cate1)));
 
                 String merge_cate2 = baseInfo.getOrDefault("merge_second_level_cate", "unknown").trim();
                 protos.add(genWithKeyMap("alg_merge_cate2_recommend_exp_feature_20250212", vid, ImmutableMap.of("merge_cate2", merge_cate2)));
                 // 特殊情况
-                //protos.add(genWithKeyMap("mid_merge_cate2_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate2", merge_cate2)));
+                // protos.add(genWithKeyMap("mid_merge_cate2_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate2", merge_cate2)));
 
                 String channel = baseInfo.getOrDefault("channel", "unknown").trim();
                 protos.add(genWithKeyMap("alg_channel_recommend_exp_feature_20250212", vid, ImmutableMap.of("channel", channel)));
@@ -156,7 +165,7 @@ public class FeatureService {
 
         // ********************* new mid ******************
         protos.add(genWithMid("mid_global_feature_20250212", mid));
-        //protos.add(genWithMid("mid_u2u_friend_index_feature_20250212", mid));
+        // protos.add(genWithMid("mid_u2u_friend_index_feature_20250212", mid));
         protos.add(genWithMid("alg_recsys_feature_user_share_return_stat", mergeMid));
 
         return getFeatureByProto(protos);
@@ -242,6 +251,10 @@ public class FeatureService {
         protos.add(genWithMid("mid_global_feature_20250212", mid));
         protos.add(genWithMid("alg_recsys_feature_user_share_return_stat", mergeMid));
 
+        if (StringUtils.isNotBlank(param.getUnionId())) {
+            protos.add(genWithUnionId("alg_user_network_seq_feature", param.getUnionId()));
+        }
+
         return getFeatureByProto(protos);
     }
 
@@ -269,8 +282,8 @@ public class FeatureService {
                 protos.add(this.genWithKeyMap("alg_merge_cate2_recommend_exp_feature_20250212", vid, ImmutableMap.of("merge_cate2", featureMap.getOrDefault("merge_second_level_cate", "unknown").trim())));
                 protos.add(this.genWithKeyMap("alg_video_unionid_recommend_exp_feature_20250212", vid, ImmutableMap.of("video_unionid", featureMap.getOrDefault("title_time_w_h_unionid", "unknown"))));
 
-                //protos.add(this.genWithKeyMap("mid_merge_cate1_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate1", featureMap.getOrDefault("merge_first_level_cate", "unknown").trim())));
-                //protos.add(this.genWithKeyMap("mid_merge_cate2_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate2", featureMap.getOrDefault("merge_second_level_cate", "unknown").trim())));
+                // protos.add(this.genWithKeyMap("mid_merge_cate1_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate1", featureMap.getOrDefault("merge_first_level_cate", "unknown").trim())));
+                // protos.add(this.genWithKeyMap("mid_merge_cate2_feature_20250212", vid, ImmutableMap.of("mid", mid, "merge_cate2", featureMap.getOrDefault("merge_second_level_cate", "unknown").trim())));
 
             }
         }
@@ -458,6 +471,14 @@ public class FeatureService {
                 .build();
     }
 
+    private FeatureKeyProto genWithUnionId(String table, String unionId) {
+        return FeatureKeyProto.newBuilder()
+                .setUniqueKey(String.format(userUkFormat, table))
+                .setTableName(table)
+                .putFieldValue("union_id", unionId)
+                .build();
+    }
+
     private FeatureKeyProto genWithKeyMap(String table, String uniqKey, Map<String, String> map) {
         FeatureKeyProto.Builder builder = FeatureKeyProto.newBuilder()
                 .setUniqueKey(String.format(kvUkFormat, table, uniqKey))

+ 7 - 59
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java

@@ -103,9 +103,6 @@ public class RecommendService {
     @ApolloJsonValue("${log.upload.field.switch:{}}")
     private Map<String, String> logUploadFieldSwitch;
 
-    @ApolloJsonValue("${special.apptype.set:[]}")
-    private Set<Integer> specialAppTypeSet;
-
     public static final String channelGroupPrefix = "alg_recsys_user_channel_group";
     /**
      * wx_user_info 表信息
@@ -176,9 +173,6 @@ public class RecommendService {
                 return specialMidRecommend(request);
             }
             Stopwatch stopwatch = Stopwatch.createStarted();
-            if (CollectionUtils.isNotEmpty(specialAppTypeSet) && specialAppTypeSet.contains(request.getAppType())) {
-                return specialAppTypeRecommend(request);
-            }
 
             if (StringUtils.isNotBlank(request.getMid())
                     && redisTemplate.opsForSet().isMember("special:mid", request.getMid())) {
@@ -189,8 +183,8 @@ public class RecommendService {
             RecommendParam param = genRecommendParam(request, recommendType);
             long genRecommendParamTime = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
             timerLogMapTL.get().put("genRecommendParamTime", genRecommendParamTime);
-            log.info("genRecommendParam={},genRecommendParam cost={}", JSONUtils.toJson(param),
-                    genRecommendParamTime);
+            // log.info("genRecommendParam={},genRecommendParam cost={}", JSONUtils.toJson(param),
+            //         genRecommendParamTime);
             List<Video> videos = videoRecommend(param);
             stopwatch.reset().start();
             updateCache(request, param, videos);
@@ -319,7 +313,7 @@ public class RecommendService {
     }
 
     public RecommendResponse specialMidRecommend(RecommendRequest request) {
-        log.info("hit special mid recommend request={}", JSONUtils.toJson(request));
+        // log.info("hit special mid recommend request={}", JSONUtils.toJson(request));
         if (request == null) {
             return RecommendResponse.newBuilder()
                     .setResult(Result.newBuilder().setCode(1).setMessage("success"))
@@ -371,56 +365,6 @@ public class RecommendService {
                 .build();
     }
 
-    public RecommendResponse specialAppTypeRecommend(RecommendRequest request) {
-        log.info("hit special apptype recommend request={}", JSONUtils.toJson(request));
-        if (request == null) {
-            return RecommendResponse.newBuilder()
-                    .setResult(Result.newBuilder().setCode(1).setMessage("success"))
-                    .build();
-        }
-
-        RecallParam recallParam = new RecallParam();
-        recallParam.setAppType(request.getAppType());
-        recallParam.setMid(request.getMid());
-        recallParam.setAppTypeSpecialRecommend(true);
-        recallParam.setProvince(request.getProvince());
-        recallParam.setCityCode(request.getCityCode());
-        recallParam.setSize(request.getSize());
-
-        RecallResult recallResult = recallService.recall(recallParam);
-
-        RankParam rankParam = new RankParam();
-        rankParam.setRecallResult(recallResult);
-        rankParam.setSize(request.getSize());
-        rankParam.setAppTypeSpecialRecommend(true);
-
-        RankResult rankResult = rankRouter.rank(rankParam);
-
-        if (Objects.isNull(rankResult) || CollectionUtils.isEmpty(rankResult.getVideos())) {
-            return RecommendResponse.newBuilder()
-                    .setResult(Result.newBuilder().setCode(1).setMessage("success"))
-                    .build();
-        }
-
-        // 只返回size条数据
-        List<Video> videos= rankResult.getVideos().subList(0, Math.min(recallParam.getSize(), rankResult.getVideos().size()));
-
-        if (CollectionUtils.isNotEmpty(videos)) {
-            Video lastVideo = videos.get(videos.size() - 1);
-            redisTemplate.opsForValue().set(lastVideo.getLastVideoKey(), String.valueOf(lastVideo.getVideoId()),
-                    1, TimeUnit.DAYS);
-        }
-
-        return RecommendResponse.newBuilder()
-                .setResult(Result.newBuilder().setCode(1).setMessage("success"))
-                .addAllVideo(CommonCollectionUtils.toList(videos, v -> VideoProto.newBuilder()
-                        .setPushFrom(Strings.nullToEmpty(v.getPushFrom()))
-                        .setVideoId(v.getVideoId())
-                        .setRovScore(v.getRovScore())
-                        .build()))
-                .build();
-    }
-
     public RecommendParam genRecommendParam(RecommendRequest request, int recommendType) {
         RecommendParam param = new RecommendParam();
         param.setTopK(3);
@@ -517,6 +461,7 @@ public class RecommendService {
         param.setRequestVideoId(request.getRequestVideoId());
         param.setCurrentPageSource(request.getCurrentPageSource());
         param.setOpenGId(request.getOpenGId());
+        param.setUnionId(request.getUnionId());
 
         Map<String, String> creativeInfoFeature = this.getCreativeInfoFeature(request.getRootSourceId(), channelName, request.getUserShareDepth());
         param.setCreativeInfoFeature(creativeInfoFeature);
@@ -678,6 +623,8 @@ public class RecommendService {
         recallParam.setCurrentPageSource(param.getCurrentPageSource());
         recallParam.setCreativeInfoFeature(param.getCreativeInfoFeature());
         recallParam.setOpenGId(param.getOpenGId());
+        recallParam.setUnionId(param.getUnionId());
+
         return recallParam;
     }
 
@@ -711,6 +658,7 @@ public class RecommendService {
         rankParam.setCurrentPageSource(param.getCurrentPageSource());
         rankParam.setCreativeInfoFeature(param.getCreativeInfoFeature());
         rankParam.setOpenGId(param.getOpenGId());
+        rankParam.setUnionId(param.getUnionId());
         return rankParam;
     }
 

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

@@ -36,5 +36,6 @@ public class WarmUpService {
         com.tzld.piaoquan.recommend.server.service.score.ScorerUtils.warmUp();
         wxVideoStatusRepository.count();
         SimilarityUtils.init();
+
     }
 }

+ 9 - 9
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/flowpool/FlowPoolService.java

@@ -175,7 +175,7 @@ public class FlowPoolService {
             for (Map.Entry<String, Double> entry : douHotLevelWeight.entrySet()) {
                 // 从流量池缓存中移除达到分发次数限制的视频ID
                 String itemKey = String.format(RedisKeyConstants.DouHot.ITEM_REDIS_KEY_FORMAT, RecallUtils.douHotProvinceConvert(province), entry.getKey());
-                log.info("[DouHot view distribute count remove cache] key: {}, item: {}", itemKey, needRemoveVideoIds);
+                // log.info("[DouHot view distribute count remove cache] key: {}, item: {}", itemKey, needRemoveVideoIds);
                 redisTemplate.opsForZSet().remove(itemKey, needRemoveVideoIds.toArray());
             }
         });
@@ -185,20 +185,20 @@ public class FlowPoolService {
 
         // 获取流量池中 全部热点宝视频
         List<FlowPoolVideoInfo> allDouHotVideo = this.findAllDouHotVideoFromFlowPool();
-        log.info("[DouHot video size]: {}", allDouHotVideo.size());
+        // log.info("[DouHot video size]: {}", allDouHotVideo.size());
 
         // 获取省份与视频列表的映射,省份 -> [video]
         Map<String, Map<String, List<FlowPoolVideoInfo>>> levelAndProvinceAndVideoMap = this.findAllVideoAndProvinceMapByAttribute(allDouHotVideo);
-        for (Map.Entry<String, Map<String, List<FlowPoolVideoInfo>>> levelEntry : levelAndProvinceAndVideoMap.entrySet()) {
+        /*for (Map.Entry<String, Map<String, List<FlowPoolVideoInfo>>> levelEntry : levelAndProvinceAndVideoMap.entrySet()) {
             levelAndProvinceAndVideoMap.forEach((key, value) -> log.info("[DouHot province video size]. level: {}, province: {}, video size: {}", levelEntry.getKey(), key, value.size()));
-        }
+        }*/
 
         // 获取某个省份下所有视频的分数, 省份 -> video -> score
         Map<String, Map<Long, Double>> videoInProvinceScore = this.findVideoInProvinceScore(allDouHotVideo);
 
         // 获取视频的可分发数,videoId-flowPool -> viewCnt
         Map<String, Integer> videoDistributeCount = this.findDouHotVideoDistributeCount(allDouHotVideo);
-        log.info("[DouHot view distribute count size]: {}", videoDistributeCount.size());
+        // log.info("[DouHot view distribute count size]: {}", videoDistributeCount.size());
 
         this.douHotVideoWriteRedis(levelAndProvinceAndVideoMap, videoInProvinceScore, videoDistributeCount);
     }
@@ -287,7 +287,7 @@ public class FlowPoolService {
             paramJson.put("pageSize", 1000);
             paramJson.put("pageNum", pageNum++);
 
-            log.info("[get DouHot flow pool video] paramJson:{}", paramJson);
+            // log.info("[get DouHot flow pool video] paramJson:{}", paramJson);
             CommonResponse<List<FlowPoolVideoInfo>> response = flowPoolFeign.getFlowPoolVideo(paramJson);
             if (0 != response.getCode()) {
                 log.error("[get DouHot flow pool video request error] responseJson: {}", response);
@@ -295,7 +295,7 @@ public class FlowPoolService {
             }
 
             if (CollectionUtils.isEmpty(response.getData())) {
-                log.error("[get DouHot flow pool video data is empty] responseJson: {}", response);
+                // log.error("[get DouHot flow pool video data is empty] responseJson: {}", response);
                 break;
             }
             result.addAll(response.getData());
@@ -337,7 +337,7 @@ public class FlowPoolService {
                                                 .collect(Collectors.toMap(i -> RecallUtils.douHotProvinceConvert(i.getName()), DouHotVideoProvince::getTgi, (o1, o2) -> o1)))
                         )
                 );
-        vidAndProvinceListMap.forEach((key, value) -> log.info("[DouHot vid and province mapping]: vid: {}, province: {}", key, JSON.toJSONString(value)));
+        // vidAndProvinceListMap.forEach((key, value) -> log.info("[DouHot vid and province mapping]: vid: {}, province: {}", key, JSON.toJSONString(value)));
         Map<Long, Map<String, Double>> resultMap = new HashMap<>(videoIdAndVidMap.size());
         for (Map.Entry<Long, String> entry : videoIdAndVidMap.entrySet()) {
             Long videoId = entry.getKey();
@@ -429,7 +429,7 @@ public class FlowPoolService {
                 List<FlowPoolVideoInfo> flowPoolVideoInfos = entry.getValue();
 
                 String redisKey = String.format(RedisKeyConstants.DouHot.ITEM_REDIS_KEY_FORMAT, province, level);
-                log.info("[DouHot item redis key]: redisKey: {}, video size: {}", redisKey, flowPoolVideoInfos.size());
+                // log.info("[DouHot item redis key]: redisKey: {}, video size: {}", redisKey, flowPoolVideoInfos.size());
                 redisTemplate.delete(redisKey);
 
                 Map<Long, Double> videoScoreInProvince = provinceAllVideoScore.getOrDefault(province, new HashMap<>());

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

@@ -50,4 +50,5 @@ public class RankParam {
     private Map<String, String> creativeInfoFeature;
     private Map<String, Map<String, String>> behaviorVideos;
     private String openGId;
+    private String unionId;
 }

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

@@ -38,16 +38,6 @@ public abstract class RankService {
             return null;
         }
 
-        if (param.isAppTypeSpecialRecommend()) {
-            Optional<RecallResult.RecallData> data = param.getRecallResult().getData().stream()
-                    .filter(d -> d.getPushFrom().equals(AppTypeSpecialRecallStrategy.PUSH_FROM))
-                    .findFirst();
-            if (data.isPresent() && CollectionUtils.isNotEmpty(data.get().getVideos())) {
-                return new RankResult(data.get().getVideos());
-            }
-            return null;
-        }
-
         if (2 == param.getRecommendType()) {
             tagDuplicateVideos(param);
             List<Video> rovRecallRank = mergeAndRankRovRecall(param);
@@ -271,7 +261,7 @@ public abstract class RankService {
             return false;
         }
         if (specialAppVid != null && specialAppVid.getOrDefault("app", new ArrayList<>()).contains((long) appId)) {
-            log.info("This request hits a special logic in matchSpecialApp with appId={}", appId);
+            // log.info("This request hits a special logic in matchSpecialApp with appId={}", appId);
             return true;
         }
         return false;

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

@@ -125,7 +125,7 @@ public class RankProcessorBoost {
                 long diffDay = ChronoUnit.DAYS.between(festiveDate, now);
                 boolean flag = (diffDay == 0 && nowHour >= 10) || (diffDay >= 1 && diffDay <= 2);
                 if (flag) {
-                    log.info("[FestiveVideoReduce] video: {}, festiveName: {}, festiveDate: {}, reduceCoefficient: {}", video.getVideoId(), festiveName, festiveDateStr, reduceCoefficient);
+                    // log.info("[FestiveVideoReduce] video: {}, festiveName: {}, festiveDate: {}, reduceCoefficient: {}", video.getVideoId(), festiveName, festiveDateStr, reduceCoefficient);
                     double originScore = video.getScore();
                     video.setScore(originScore * reduceCoefficient);
                     video.setSortScore(originScore * reduceCoefficient);

+ 265 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelDNNDemo.java

@@ -0,0 +1,265 @@
+// package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+//
+// import com.alibaba.fastjson.JSON;
+// import com.aliyun.openservices.eas.predict.http.HttpConfig;
+// import com.aliyun.openservices.eas.predict.http.PredictClient;
+// import com.aliyun.openservices.eas.predict.request.TFRequest;
+// import com.aliyun.openservices.eas.predict.response.TFResponse;
+// import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+// import com.tzld.piaoquan.recommend.server.common.base.RankItem;
+// import com.tzld.piaoquan.recommend.server.model.Video;
+// import com.tzld.piaoquan.recommend.server.service.FeatureService;
+// import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
+// import com.tzld.piaoquan.recommend.server.service.rank.bo.UserShareReturnProfile;
+// import com.tzld.piaoquan.recommend.server.service.rank.tansform.FeatureFGEncoder;
+// import com.tzld.piaoquan.recommend.server.service.rank.tansform.FeatureV6;
+// import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
+// import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
+// import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
+// import com.tzld.piaoquan.recommend.server.util.JSONUtils;
+// import com.tzld.piaoquan.recommend.server.util.RecallUtils;
+// import lombok.extern.slf4j.Slf4j;
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.stereotype.Service;
+//
+// import javax.annotation.PostConstruct;
+// import java.util.*;
+//
+// /**
+//  * DNN 模型排序 Demo
+//  *
+//  * 流程:
+//  *   1. 特征提取: 复用 FeatureV6(跟 FM/XGB 完全一样)
+//  *   2. FG 编码: FeatureFGEncoder 按 fg_config.json 顺序编码为 chr(2) 字符串
+//  *   3. 模型打分: 调用 EAS 服务(TODO: 接入 EAS SDK)
+//  *
+//  * 特征配置: resources/fg/fg_config.json(975 特征,跟离线训练一致)
+//  */
+// @Service
+// @Slf4j
+// public class RankStrategy4RegionMergeModelDNNDemo extends RankStrategy4RegionMergeModelBasic {
+//
+//     @ApolloJsonValue("${rank.score.merge.weightv569:}")
+//     private Map<String, Double> mergeWeight;
+//
+//     @Autowired
+//     private FeatureService featureService;
+//
+//     private FeatureFGEncoder fgEncoder;
+//
+//     private PredictClient predictClient;
+//
+//     @PostConstruct
+//     public void init() {
+//         fgEncoder = new FeatureFGEncoder("fg/fg_config.json");
+//         log.info("DNN Demo 初始化完成: {} 个特征", fgEncoder.getFeatureCount());
+//
+//         predictClient = new PredictClient(new HttpConfig());
+//         predictClient.setModelName("recsys_dnn_v1_20260327");
+//         predictClient.setToken("MmEwYzVlZGFiOTM4YWM3ZTE5ZDMzNTgzY2Q5YjZlYjVjODE5ZjIzYQ==");
+//         predictClient.setEndpoint("1894469520484605.cn-hangzhou.pai-eas.aliyuncs.com");
+//
+//     }
+//
+//     @Override
+//     public List<Video> mergeAndRankRovRecall(RankParam param) {
+//         Map<String, Double> mergeWeight = this.mergeWeight != null ? this.mergeWeight : new HashMap<>(0);
+//
+//         //-------------------融-------------------
+//         //-------------------合-------------------
+//         //-------------------逻-------------------
+//         //-------------------辑-------------------
+//
+//         long currentMs = System.currentTimeMillis();
+//         Set<Long> setVideo = new HashSet<>();
+//         setVideo.add(param.getHeadVid());
+//         List<Video> rovRecallRank = new ArrayList<>();
+//         // -------------------5路特殊旧召回------------------
+//         RecallUtils.extractOldSpecialRecall(mergeWeight.getOrDefault("oldSpecialN", (double) param.getSize()).intValue(), param, setVideo, rovRecallRank);
+//         //-------------------return相似召回------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("v6", 5.0).intValue(), param, ReturnVideoRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         //-------------------新地域召回------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("v1", 5.0).intValue(), param, RegionRealtimeRecallStrategyV1.PUSH_FORM, setVideo, rovRecallRank);
+//         //-------------------scene cf rovn------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("sceneCFRovn", 5.0).intValue(), param, SceneCFRovnRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         //-------------------scene cf rosn------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("sceneCFRosn", 5.0).intValue(), param, SceneCFRosnRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         // -------------------user cate1------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("cate1RecallN", 5.0).intValue(), param, UserCate1RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         // -------------------user cate2------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("cate2RecallN", 5.0).intValue(), param, UserCate2RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         // -------------------head province cate1------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("headCate1RecallN", 3.0).intValue(), param, HeadProvinceCate1RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         // -------------------head province cate2------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("headCate2RecallN", 3.0).intValue(), param, HeadProvinceCate2RecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         //-------------------head cate2 of rovn------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("headCate2Rov", 5.0).intValue(), param, HeadCate2RovRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+//         //-------------------city rovn------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("cityRov", 5.0).intValue(), param, CityRovnRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+//         //-------------------priori province rovn------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("prioriProvinceRov", 3.0).intValue(), param, PrioriProvinceRovnRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+//         //-------------------priori province str------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("prioriProvinceStr", 1.0).intValue(), param, PrioriProvinceStrRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+//         //-------------------priori province ros------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("prioriProvinceRos", 1.0).intValue(), param, PrioriProvinceRosRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+//         //-------------------return1 cate2 ros------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("return1Cate2Ros", 5.0).intValue(), param, Return1Cate2RosRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//         //-------------------return1 cate2 str------------------
+//         RecallUtils.extractRecall(mergeWeight.getOrDefault("return1Cate2Str", 5.0).intValue(), param, Return1Cate2StrRecallStrategy.PUSH_FORM, setVideo, rovRecallRank);
+//
+//         // 记录召回源中的视频
+//         this.rankBeforePostProcessor(rovRecallRank);
+//
+//         // ============ 特征提取 ============
+//         Map<String, String> headVideoInfo = param.getHeadInfo();
+//         List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
+//         Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo("", vids);
+//
+//         FeatureService.Feature feature = featureService.getFeatureV4(param, headVideoInfo, videoBaseInfoMap, vids);
+//         Map<String, Map<String, String>> featureOriginUser = feature.getUserFeature();
+//         Map<String, Map<String, Map<String, String>>> featureOriginVideo = feature.getVideoFeature();
+//
+//         Map<String, Map<String, String[]>> c7Map = FeatureV6.parseUCFScore(featureOriginUser.getOrDefault("alg_mid_feature_sharecf", new HashMap<>()));
+//         Map<String, Map<String, String[]>> c8Map = FeatureV6.parseUCFScore(featureOriginUser.getOrDefault("alg_mid_feature_returncf", new HashMap<>()));
+//         UserShareReturnProfile userProfile = parseUserProfile(featureOriginUser);
+//         Map<String, String> creativeInfo = param.getCreativeInfoFeature();
+//         Map<String, Map<String, String>> historyVideoMap = param.getBehaviorVideos();
+//         Map<String, String> baseInfo = featureOriginUser.getOrDefault("mid_base_info", new HashMap<>());
+//
+//         // ============ 用户级特征(所有视频共享)============
+//         Map<String, Double> userNumericFeatures = new HashMap<>();
+//         Map<String, String> userStringFeatures = new HashMap<>();
+//
+//         // 上下文特征
+//         String appType = Optional.of(param.getAppType()).map(String::valueOf).orElse("0");
+//         String hotSceneType = Optional.ofNullable(param.getHotSceneType()).map(String::valueOf).orElse("other");
+//         FeatureV6.getContextFeature(currentMs, appType, hotSceneType, userNumericFeatures);
+//         userStringFeatures.put("ctx_app", appType);
+//         userStringFeatures.put("ctx_hot", hotSceneType);
+//         userStringFeatures.put("ctx_week", String.valueOf(Calendar.getInstance().get(Calendar.DAY_OF_WEEK)));
+//         userStringFeatures.put("ctx_hour", String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY)));
+//
+//         // 用户特征
+//         FeatureV6.getUserFeature(featureOriginUser, userNumericFeatures);
+//         FeatureV6.getUserProfileFeature(userProfile, baseInfo, userNumericFeatures);
+//         userStringFeatures.put("mid", param.getMid());
+//         userStringFeatures.put("user_province", baseInfo.getOrDefault("province", ""));
+//         userStringFeatures.put("user_city", baseInfo.getOrDefault("city", ""));
+//         userStringFeatures.put("user_brand", baseInfo.getOrDefault("brand", ""));
+//         userStringFeatures.put("user_model", baseInfo.getOrDefault("model", ""));
+//         userStringFeatures.put("user_system", baseInfo.getOrDefault("system", ""));
+//         userStringFeatures.put("user_channel", baseInfo.getOrDefault("user_channel", ""));
+//         userStringFeatures.put("user_level", baseInfo.getOrDefault("user_level", ""));
+//
+//         // 创意特征
+//         FeatureV6.getCreativeBaseFeature("e1", creativeInfo, userNumericFeatures);
+//         userStringFeatures.put("e1_ghid", creativeInfo.getOrDefault("ghid", ""));
+//         userStringFeatures.put("e1_name", creativeInfo.getOrDefault("name", ""));
+//
+//         // 头部视频特征
+//         FeatureV6.getVideoBaseFeature("h", currentMs, headVideoInfo, userNumericFeatures);
+//         putVideoStringFeatures("h", headVideoInfo, userStringFeatures);
+//
+//         // ============ 逐视频特征 + FG 编码 + 打分 ============
+//         // 批量收集 FG 字符串,后续可批量调 EAS
+//         List<TFRequest> tfRequests= new ArrayList<>(rovRecallRank.size());
+//         List<String> fgEncodes = new ArrayList<>(rovRecallRank.size());
+//
+//         List<RankItem> rankItems = CommonCollectionUtils.toList(rovRecallRank, RankItem::new);
+//
+//         for (RankItem rankItem : rankItems) {
+//             Video video = rankItem.getVideo();
+//
+//             String vid = String.valueOf(video.getVideoId());
+//             Map<String, String> rankInfo = videoBaseInfoMap
+//                     .getOrDefault(vid, new HashMap<>())
+//                     .getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+//
+//             // 复制用户级特征
+//             Map<String, Double> numericFeatures = new HashMap<>(userNumericFeatures);
+//             Map<String, String> stringFeatures = new HashMap<>(userStringFeatures);
+//
+//             // 当前视频特征
+//             FeatureV6.getVideoBaseFeature("r", currentMs, rankInfo, numericFeatures);
+//             FeatureV6.getVideoFeature(vid, featureOriginVideo, numericFeatures);
+//             putVideoStringFeatures("r", rankInfo, stringFeatures);
+//             stringFeatures.put("r_vid_source", rankInfo.getOrDefault("vid_source", ""));
+//
+//             // CF 特征
+//             FeatureV6.getUserTagsCrossVideoFeature("c5", rankInfo, featureOriginUser.get("alg_mid_feature_return_tags"), numericFeatures);
+//             FeatureV6.getUserTagsCrossVideoFeature("c6", rankInfo, featureOriginUser.get("alg_mid_feature_share_tags"), numericFeatures);
+//             FeatureV6.getUserCFFeature("c7", vid, c7Map, numericFeatures);
+//             FeatureV6.getUserCFFeature("c8", vid, c8Map, numericFeatures);
+//
+//             // 交叉特征
+//             FeatureV6.getHeadRankVideoCrossFeature(headVideoInfo, rankInfo, numericFeatures);
+//             FeatureV6.getCreativeCrossFeature("e1", creativeInfo, rankInfo, numericFeatures);
+//             FeatureV6.getProfileVideoCrossFeature(currentMs, userProfile, rankInfo, historyVideoMap, numericFeatures);
+//
+//             rankItem.setFeatureMapDouble(numericFeatures);
+//             rankItem.setFeatureMapString(stringFeatures);
+//
+//             tfRequests.add(fgEncoder.tfRequests(numericFeatures, stringFeatures));
+//         }
+//
+//         // ============ 调用 EAS 打分(TODO)============
+//         // List<Double> scores = easClient.predict(fgFeaturesList);
+//         // 临时: 用随机分数
+//
+//         for (int i = 0; i < rovRecallRank.size(); i++) {
+//             Video video = rovRecallRank.get(i);
+//
+//             try {
+//                 TFRequest tfRequest = tfRequests.get(i);
+//                 TFResponse tfPredict = predictClient.predict(tfRequest);
+//                 System.out.println(tfPredict);
+//             } catch (Exception e) {
+//                 log.error("dnn predict error videoId: {}", video.getVideoId(), e);
+//             }
+//         }
+//
+//         for (int i = 0; i < rovRecallRank.size(); i++) {
+//             Video video = rovRecallRank.get(i);
+//             double score = Math.random();  // TODO: 替换为 EAS 返回的分数
+//             video.setScore(score);
+//             video.setSortScore(score);
+//         }
+//
+//         rovRecallRank.sort((a, b) -> Double.compare(b.getSortScore(), a.getSortScore()));
+//         return rovRecallRank;
+//     }
+//
+//     /**
+//      * 视频 ID 类特征放入 stringFeatures
+//      */
+//     private void putVideoStringFeatures(String prefix, Map<String, String> videoInfo, Map<String, String> stringFeatures) {
+//         stringFeatures.put(prefix + "_resolution", videoInfo.getOrDefault("resolution", ""));
+//         stringFeatures.put(prefix + "_time_type", videoInfo.getOrDefault("time_type", ""));
+//         stringFeatures.put(prefix + "_cate2", videoInfo.getOrDefault("merge_second_level_cate", ""));
+//         stringFeatures.put(prefix + "_cate1_list", videoInfo.getOrDefault("merge_first_level_cate", ""));
+//         stringFeatures.put(prefix + "_festive_label1", videoInfo.getOrDefault("festive_label1", ""));
+//         stringFeatures.put(prefix + "_channel", videoInfo.getOrDefault("channel", ""));
+//         stringFeatures.put(prefix + "_vid_source", videoInfo.getOrDefault("vid_source", ""));
+//         stringFeatures.put(prefix + "_uid", videoInfo.getOrDefault("uid", ""));
+//         stringFeatures.put(prefix + "_keywords", videoInfo.getOrDefault("keywords", ""));
+//         stringFeatures.put(prefix + "_merge_first_level_cate", videoInfo.getOrDefault("merge_first_level_cate", ""));
+//         stringFeatures.put(prefix + "_merge_second_level_cate", videoInfo.getOrDefault("merge_second_level_cate", ""));
+//     }
+//
+//     private UserShareReturnProfile parseUserProfile(Map<String, Map<String, String>> userOriginInfo) {
+//         if (null != userOriginInfo) {
+//             Map<String, String> c9 = userOriginInfo.get("alg_recsys_feature_user_share_return_stat");
+//             if (null != c9 && !c9.isEmpty()) {
+//                 String c9Str = JSONUtils.toJson(c9);
+//                 if (!c9Str.isEmpty()) {
+//                     try {
+//                         return JSON.parseObject(c9Str, UserShareReturnProfile.class);
+//                     } catch (Exception e) {
+//                         log.error("parseObject user profile error! value=[{}]", c9Str, e);
+//                     }
+//                 }
+//             }
+//         }
+//         return null;
+//     }
+// }

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

@@ -217,7 +217,7 @@ public class RankStrategy4RegionMergeModelV536 extends RankStrategy4RegionMergeM
             item.getScoresMap().put("dnRovn24hW", dnRovn24hW);
             item.getScoresMap().put("dnRovn24h", dnRovn24h);
 
-            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore * dnRovnScore;
+            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore + dnRovnScore;
 
             Video video = item.getVideo();
             video.setScore(score);

+ 45 - 54
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV562.java

@@ -15,6 +15,7 @@ import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
 import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
 import com.tzld.piaoquan.recommend.server.util.*;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -23,6 +24,8 @@ import org.springframework.stereotype.Service;
 import java.util.*;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @Service
 @Slf4j
@@ -91,8 +94,21 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
         // 1. 批量获取特征  省份参数要对齐  headvid  要传递过来!
         // k1:视频、k2:表、k3:特征、v:特征值
         Map<String, String> headVideoInfo = param.getHeadInfo();
+
+        // 用户的序列特征
+        Map<String, Map<String, String>> unionIdFeature = featureService.getUnionIdFeature(param.getUnionId());
+        Map<String, String> userNetworkSeqFeature = unionIdFeature.getOrDefault("alg_user_network_seq_feature", new HashMap<>());
+        List<String> actVidSeq = FeatureUtils.extractVidsFromUserNetworkSeqFeature(userNetworkSeqFeature, "a_v_s");
+        List<String> netVidSeq = FeatureUtils.extractVidsFromUserNetworkSeqFeature(userNetworkSeqFeature, "n_v_s");
+
         List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
-        Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo("", vids);
+
+        List<String> allVids = Stream.of(actVidSeq, netVidSeq, vids)
+                .flatMap(Collection::stream)
+                .distinct()
+                .collect(Collectors.toList());
+
+        Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo("", allVids);
         Map<String, Map<String, Map<String, String>>> videoBCData = featureService.getVideoStatistics(vids);
 
         FeatureService.Feature feature = featureService.getFeatureV4(param, headVideoInfo, videoBaseInfoMap, vids);
@@ -106,15 +122,20 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
         Map<String, Map<String, String>> userBehaviorVideoMap = param.getBehaviorVideos();
         Map<String, String> creativeInfo = param.getCreativeInfoFeature();
 
+        Map<String, String> featureMapToString = new HashMap<>();
+        FeatureV6.parseStringFeatureMap(featureMapToString, param);
+        FeatureV6.putVideoStringFeatures("h", headVideoInfo, featureMapToString);
+
         // 3. 特征处理
         List<RankItem> rankItems = CommonCollectionUtils.toList(rovRecallRank, RankItem::new);
         Map<String, Float> userFeatureMap = getUserFeature(currentMs, param, creativeInfo, headVideoInfo, userProfile, featureOriginUser);
         batchGetVideoFeature(currentMs, userProfile, creativeInfo, headVideoInfo, videoBaseInfoMap,
-                newC7Map, newC8Map, featureOriginUser, userBehaviorVideoMap, featureOriginVideo, rankItems);
+                newC7Map, newC8Map, featureOriginUser, userBehaviorVideoMap, featureOriginVideo, featureMapToString, userFeatureMap, rankItems);
+
 
         // 4. 排序模型计算
         Map<String, Float> sceneFeatureMap = new HashMap<>(0);
-        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_xgb_ros_20250311.conf").scoring(sceneFeatureMap, userFeatureMap, userFeatureMap, rankItems);
+        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_xgb_ros_20250311.conf").scoring(sceneFeatureMap, userFeatureMap, rankItems);
 
         // 5. 排序公式特征
         double xgbRovNegRate = mergeWeight.getOrDefault("xgbRovNegRate", 0.059);
@@ -158,8 +179,9 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
             double hasReturnRovScore = Double.parseDouble(vid2MapFeature.getOrDefault(item.getVideoId() + "", new HashMap<>()).getOrDefault("rov", "0"));
             item.getScoresMap().put("hasReturnRovScore", hasReturnRovScore);
 
-            double norXGBScore = item.getScoresMap().getOrDefault("NorXGBScore", 0d);
-            double newNorXGBScore = norPowerCalibration(xgbNorPowerWeight, xgbNorPowerExp, norXGBScore);
+            double norDNNScore = item.getScoresMap().getOrDefault("NorDNNScore", 0d);
+            double newNorDNNScore = norPowerCalibration(xgbNorPowerWeight, xgbNorPowerExp, norDNNScore);
+            item.getScoresMap().put("newNorDNNScore", newNorDNNScore);
             item.getScoresMap().put("rosAdd", rosAdd);
             item.getScoresMap().put("rosW", rosW);
 
@@ -217,7 +239,7 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
             item.getScoresMap().put("dnRovn24hW", dnRovn24hW);
             item.getScoresMap().put("dnRovn24h", dnRovn24h);
 
-            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore * dnRovnScore;
+            score = fmRov * (rosAdd + rosW * newNorDNNScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore + dnRovnScore;
 
             Video video = item.getVideo();
             video.setScore(score);
@@ -251,7 +273,7 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
             if (MapUtils.isNotEmpty(contextInfo)) {
                 video.getMetaFeatureMap().put("context", contextInfo);
             }
-            if (Objects.nonNull(video.getRankVideoInfoMap()) && video.getRankVideoInfoMap().containsKey(video.getVideoId())){
+            if (Objects.nonNull(video.getRankVideoInfoMap()) && video.getRankVideoInfoMap().containsKey(video.getVideoId())) {
                 video.getRankVideoInfoMap().get(video.getVideoId()).setScore(score);
                 video.getRankVideoInfoMap().get(video.getVideoId()).setScoresMap(video.getScoresMap());
             }
@@ -338,15 +360,28 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
                                       Map<String, Map<String, String>> userOriginInfo,
                                       Map<String, Map<String, String>> historyVideoMap,
                                       Map<String, Map<String, Map<String, String>>> videoOriginInfo,
+                                      Map<String, String> featureMapToString,
+                                      Map<String, Float> userFeatureMap,
                                       List<RankItem> rankItems) {
-        if (null != rankItems && !rankItems.isEmpty()) {
+        if (CollectionUtils.isNotEmpty(rankItems)) {
             List<Future<Integer>> futures = new ArrayList<>();
             for (RankItem item : rankItems) {
                 String vid = item.getVideoId() + "";
                 Map<String, String> rankInfo = videoBaseInfoMap.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
                 Future<Integer> future = ThreadPoolFactory.defaultPool().submit(() -> {
-                    item.featureMap = getVideoFeature(currentMs, vid, userProfile, creativeInfo, headInfo, rankInfo, c7Map, c8Map, userOriginInfo, historyVideoMap, videoOriginInfo);
-                    item.norFeatureMap = item.featureMap;
+                    Map<String, Float> featureMap = new HashMap<>(userFeatureMap);
+                    Map<String, Float> videoFeature = getVideoFeature(currentMs, vid, userProfile, creativeInfo, headInfo, rankInfo, c7Map, c8Map, userOriginInfo, historyVideoMap, videoOriginInfo);
+                    featureMap.putAll(videoFeature);
+                    item.featureMap = featureMap;
+
+                    Map<String, String> userNetworkSeqFeature = userOriginInfo.getOrDefault("alg_user_network_seq_feature", new HashMap<>());
+
+                    Map<String, String> featureMapString = new HashMap<>(featureMapToString);
+                    FeatureV6.putVideoStringFeatures("r", rankInfo, featureMapString);
+                    featureMapString.put("r@vid", "r_vid_" + vid);
+                    FeatureV6.putProfileVideoCrossStringFeature(currentMs, userProfile, historyVideoMap, featureMapString);
+                    FeatureV6.putUserNetworkSeqFeature(featureMapString, userNetworkSeqFeature, videoBaseInfoMap);
+                    item.featureMapString = featureMapString;
                     return 1;
                 });
                 futures.add(future);
@@ -418,48 +453,4 @@ public class RankStrategy4RegionMergeModelV562 extends RankStrategy4RegionMergeM
         }
         return newScore;
     }
-
-    private Map<String, Double> findSimCateScore(String headCate2, int length) {
-        if (StringUtils.isBlank(headCate2)) {
-            return new HashMap<>();
-        }
-
-        String redisKey = String.format("alg_recsys_good_cate_pair_list:%s", headCate2);
-        String cate2Value = redisTemplate.opsForValue().get(redisKey);
-        if (StringUtils.isEmpty(cate2Value)) {
-            return new HashMap<>();
-        }
-
-        return this.parsePair(cate2Value, length);
-    }
-
-    private Map<String, Double> parsePair(String value, int length) {
-        if (StringUtils.isBlank(value)) {
-            return new HashMap<>();
-        }
-
-        String[] split = value.split("\t");
-        if (split.length != 2) {
-            return new HashMap<>();
-        }
-
-        String[] valueList = split[0].trim().split(",");
-        String[] scoreList = split[1].trim().split(",");
-        if (valueList.length != scoreList.length) {
-            return new HashMap<>();
-        }
-
-        int minLength = Math.min(length, valueList.length);
-        Map<String, Double> resultMap = new HashMap<>();
-        for (int i = 0; i < minLength; i++) {
-            resultMap.put(valueList[i].trim(), Double.parseDouble(scoreList[i].trim()));
-        }
-
-        return resultMap;
-    }
-
-    private String findVideoMergeCate2(Map<String, Map<String, Map<String, String>>> featureOriginVideo, String vid) {
-        Map<String, String> videoInfo = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
-        return videoInfo.get("merge_second_level_cate");
-    }
 }

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

@@ -217,7 +217,7 @@ public class RankStrategy4RegionMergeModelV566 extends RankStrategy4RegionMergeM
             item.getScoresMap().put("dnRovn24hW", dnRovn24hW);
             item.getScoresMap().put("dnRovn24h", dnRovn24h);
 
-            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore * dnRovnScore;
+            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore + dnRovnScore;
 
             Video video = item.getVideo();
             video.setScore(score);

+ 2 - 2
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV568.java

@@ -220,7 +220,7 @@ public class RankStrategy4RegionMergeModelV568 extends RankStrategy4RegionMergeM
             item.getScoresMap().put("dnRovn24hW", dnRovn24hW);
             item.getScoresMap().put("dnRovn24h", dnRovn24h);
 
-            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore * dnRovnScore;
+            score = fmRov * (rosAdd + rosW * newNorXGBScore) * (vorAdd + vorW * vor) + c1RovnScore + b0StrScore + b0RorScore + cnRovnScore + dnRovnScore;
 
             Video video = item.getVideo();
             video.setScore(score);
@@ -255,7 +255,7 @@ public class RankStrategy4RegionMergeModelV568 extends RankStrategy4RegionMergeM
             if (MapUtils.isNotEmpty(contextInfo)) {
                 video.getMetaFeatureMap().put("context", contextInfo);
             }
-            if (Objects.nonNull(video.getRankVideoInfoMap()) && video.getRankVideoInfoMap().containsKey(video.getVideoId())){
+            if (Objects.nonNull(video.getRankVideoInfoMap()) && video.getRankVideoInfoMap().containsKey(video.getVideoId())) {
                 video.getRankVideoInfoMap().get(video.getVideoId()).setScore(score);
                 video.getRankVideoInfoMap().get(video.getVideoId()).setScoresMap(video.getScoresMap());
             }

+ 183 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FGEncoder.java

@@ -0,0 +1,183 @@
+package com.tzld.piaoquan.recommend.server.service.rank.tansform;
+
+import com.aliyun.openservices.eas.predict.request.TFDataType;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+/**
+ * FG 编码器:按 fg_config.json 定义的特征顺序,将 FeatureV6 的输出编码为 EasyRec FG 格式字符串。
+ * <p>
+ * 使用方式:
+ * 1. 初始化时加载 fg_config.json(从 classpath 或文件路径)
+ * 2. 调用 encode() 传入 FeatureV6 计算好的特征 Map + 上下文信息
+ * 3. 返回 chr(2) 分隔的 features 字符串,可直接发给 EAS bypass 模式
+ * <p>
+ * 特征映射规则(fg_config name → FeatureV6 key):
+ * - 统计特征: b0_12h_exp → b0_12h@exp(下划线→@)
+ * - log压缩:  b0_12h_ros_l → b0_12h@ros_#(_l → _#)
+ * - ID特征:   ctx_app → 直接从 stringFeatures 取值
+ * - need_prefix=true 的 ID 特征: 输出 "name_value" 格式
+ */
+public class FGEncoder {
+
+    private static final Logger log = LoggerFactory.getLogger(FGEncoder.class);
+
+    private final List<FeatureDef> featureDefs;
+
+    // ── 特征定义 ─────────────────────────────────
+
+    public static class FeatureDef {
+        public String feature_name;
+        public String feature_key;
+        public String value_type;
+        public String default_value;
+
+        public TFDataType typeCoverToTFDataType() {
+            if ("Double".equalsIgnoreCase(value_type)) {
+                return TFDataType.DT_DOUBLE;
+            } else if ("Long".equalsIgnoreCase(value_type)) {
+                return TFDataType.DT_INT64;
+            } else {
+                return TFDataType.DT_STRING;
+            }
+        }
+    }
+
+    // ── 初始化 ─────────────────────────────────
+
+    /**
+     * 从 classpath 加载 fg_config.json
+     */
+    public FGEncoder(String fgConfigJsonPath) {
+        try (InputStream is = getClass().getClassLoader().getResourceAsStream(fgConfigJsonPath)) {
+            if (is == null) {
+                throw new RuntimeException("fg_config not found: " + fgConfigJsonPath);
+            }
+
+            this.featureDefs = this.loadConfig(is);
+        } catch (Exception e) {
+            throw new RuntimeException("加载 fg_config 失败: " + fgConfigJsonPath, e);
+        }
+    }
+
+    public FGEncoder(InputStream inputStream) {
+        this.featureDefs = loadConfig(inputStream);
+    }
+
+    private List<FeatureDef> loadConfig(InputStream inputStream) {
+        Gson gson = new Gson();
+        InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
+
+        // 格式: {"features": [...], "reserves": [...]}
+        Map<String, Object> config = gson.fromJson(reader, new TypeToken<Map<String, Object>>() {
+        }.getType());
+        String featuresJson = gson.toJson(config.get("features"));
+        List<FeatureDef> defs = gson.fromJson(featuresJson, new TypeToken<List<FeatureDef>>() {
+        }.getType());
+
+        log.info("FeatureFGEncoder 初始化: {} 个特征", defs.size());
+        return defs;
+    }
+
+
+    // ── fg_name → FeatureV6 key 映射 ─────────────
+
+    /**
+     * 将 fg_config 的 feature_name 转换为 FeatureV6 Map 里的 key。
+     * <p>
+     * 规则:
+     * b0_12h_exp       → b0_12h@exp        (prefix_period_metric → prefix_period@metric)
+     * b0_12h_ros_l     → b0_12h@ros_#      (_l 后缀 → _#)
+     * b0_12h_ros_n_l   → b0_12h@ros_n_#
+     * c9_s_pv          → c9@s_pv
+     * ctx_app           → null (不走 Map,从 stringFeatures 取)
+     * h_total_time      → null (不走 Map,从 stringFeatures 取)
+     */
+    public String fgNameToV6Key(String fgName) {
+        // 统计特征前缀列表
+        Set<String> statPrefixes = new HashSet<>(Arrays.asList(
+                "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9",
+                "b10", "b11", "b13", "b14", "b15", "c1"
+        ));
+
+        // c9 前缀
+        if (fgName.startsWith("c9_")) {
+            return "c9@" + fgName.substring(3);
+        }
+
+        // 统计特征: 找 prefix_period_metric 模式
+        for (String prefix : statPrefixes) {
+            if (!fgName.startsWith(prefix + "_")) continue;
+            String rest = fgName.substring(prefix.length() + 1);  // "12h_exp" or "12h_ros_l"
+
+            // 找 period(第一个 _ 之前的部分,如 "12h", "1h", "168h")
+            int periodEnd = rest.indexOf('_');
+            if (periodEnd < 0) continue;
+            String period = rest.substring(0, periodEnd);
+            String metric = rest.substring(periodEnd + 1);  // "exp", "ros_l", "ros_minus_l"
+
+            // _l 后缀 → _#
+            if (metric.endsWith("_l")) {
+                metric = metric.substring(0, metric.length() - 2) + "_#";
+            }
+
+            return prefix + "_" + period + "@" + metric;
+        }
+
+        // d1/d2/d3 CF 特征
+        if (fgName.startsWith("d1_") || fgName.startsWith("d2_") || fgName.startsWith("d3_")) {
+            String prefix = fgName.substring(0, 2);
+            String metric = fgName.substring(3);
+            return prefix + "@" + metric;
+        }
+
+        // 视频属性特征: h_total_time → h@total_time, r_bit_rate → r@bit_rate
+        if (fgName.startsWith("h_") || fgName.startsWith("r_")) {
+            return fgName.substring(0, 1) + "@" + fgName.substring(2);
+        }
+
+        // 上下文数值特征: ctx_hour_val → hour
+        if ("ctx_hour_val".equals(fgName)) {
+            return "hour";
+        }
+
+        // e1 创意特征: e1_xxx → e1@xxx
+        if (fgName.startsWith("e1_")) {
+            return "e1@" + fgName.substring(3);
+        }
+
+        // 其他 → 不走 numeric Map,从 stringFeatures 取
+        return null;
+    }
+
+    // ── 辅助方法 ─────────────────────────────────
+
+    /**
+     * 获取特征数量
+     */
+    public int getFeatureCount() {
+        return featureDefs.size();
+    }
+
+    /**
+     * 获取特征名列表(用于调试/对齐)
+     */
+    public List<String> getFeatureNames() {
+        List<String> names = new ArrayList<>(featureDefs.size());
+        for (FeatureDef def : featureDefs) {
+            names.add(def.feature_name);
+        }
+        return names;
+    }
+
+    public List<FeatureDef> getFeatureDefs() {
+        return featureDefs;
+    }
+}

+ 55 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FGEncoderManager.java

@@ -0,0 +1,55 @@
+package com.tzld.piaoquan.recommend.server.service.rank.tansform;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.common.auth.CredentialsProvider;
+import com.aliyun.oss.common.auth.DefaultCredentialProvider;
+import com.ctrip.framework.apollo.Config;
+import com.ctrip.framework.apollo.ConfigService;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Getter
+public class FGEncoderManager {
+
+    private static final FGEncoderManager instance = new FGEncoderManager();
+    private final Map<String, FGEncoder> featureFGEncoderMap = new HashMap<>();
+
+    private final OSS client;
+    private final String bucketName;
+
+    private FGEncoderManager() {
+        // config load
+        Config config = ConfigService.getAppConfig();
+        String endpoint = config.getProperty("model.oss.internal.endpoint", "");
+        String accessKeyId = config.getProperty("model.oss.accessKeyId", "");
+        String accessKetSecret = config.getProperty("model.oss.accessKetSecret", "");
+        // oss client
+        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKetSecret);
+        this.client = new OSSClientBuilder().build(endpoint, credentialsProvider);
+        this.bucketName = config.getProperty("model.oss.bucketName", "");
+
+        this.registerAllFGEncoder();
+    }
+
+    public static FGEncoderManager getInstance() {
+        return instance;
+    }
+
+    public void registerAllFGEncoder() {
+        this.registerFGEncoder("zhaohaipeng/pai/config/fg/feature_list_20260403.json");
+    }
+
+    public void registerFGEncoder(final String fgConfigJsonPath) {
+        FGEncoder fgEncoder = new FGEncoder(client.getObject(this.bucketName, fgConfigJsonPath).getObjectContent());
+        this.featureFGEncoderMap.put(fgConfigJsonPath, fgEncoder);
+    }
+
+    public FGEncoder getFGEncoder(final String fgConfigJsonPath) {
+        return this.featureFGEncoderMap.get(fgConfigJsonPath);
+    }
+}

+ 159 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FeatureV6.java

@@ -1,5 +1,7 @@
 package com.tzld.piaoquan.recommend.server.service.rank.tansform;
 
+import com.tzld.piaoquan.recommend.server.model.MachineInfo;
+import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserSRBO;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserShareReturnProfile;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.VideoAttrSRBO;
@@ -7,6 +9,8 @@ import com.tzld.piaoquan.recommend.server.service.rank.extractor.ExtractorUtils;
 import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
 import com.tzld.piaoquan.recommend.server.util.SimilarityUtils;
 import com.tzld.piaoquan.recommend.similarity.word2vec.Segment;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
 
 import java.util.*;
 
@@ -43,6 +47,7 @@ public class FeatureV6 {
     private static final Set<String> appSet = new HashSet<>(Arrays.asList("0", "2", "4"));
     private static final Set<String> hotSceneSet = new HashSet<>(Arrays.asList("1008", "1007", "1058", "1074", "1010"));
     private static final Map<String, String> histotyVideoAttrMAP = new HashMap<>();
+    public static final String GS_STR = "\u001D";
 
     static {
         histotyVideoAttrMAP.put("merge_first_level_cate", "cate1");
@@ -600,4 +605,158 @@ public class FeatureV6 {
             }
         }
     }
+
+    /**
+     * 提取 c9 序列特征的 String 原始值(week/hour/cate1/cate2),供 DNN 模型使用。
+     * 离线 FG 编码直接取原始值(如 week="3"),在线也需要对齐。
+     */
+    public static void putProfileVideoCrossStringFeature(long currentMs, UserShareReturnProfile profile,
+                                                         Map<String, Map<String, String>> hVideoMap,
+                                                         Map<String, String> featureMapString) {
+        if (null == profile) {
+            return;
+        }
+        putRSCrossStringFeature(false, "c9_mss", currentMs, seqMaxN, profile.getM_s_s(), hVideoMap, featureMapString);
+        putRSCrossStringFeature(false, "c9_mrs", currentMs, seqMaxN, profile.getM_r_s(), hVideoMap, featureMapString);
+        putRSCrossStringFeature(true, "c9_lss", currentMs, seqLastN, profile.getL_s_s(), hVideoMap, featureMapString);
+        putRSCrossStringFeature(false, "c9_lrs", currentMs, seqLastN, profile.getL_r_s(), hVideoMap, featureMapString);
+        putRSCrossStringFeature(true, "c9_lr1s", currentMs, seqLastN, profile.getL_r1_s(), hVideoMap, featureMapString);
+    }
+
+    private static void putRSCrossStringFeature(boolean hasCate, String prefix, long currentMs, int maxN,
+                                                 List<UserSRBO> list, Map<String, Map<String, String>> hVideoMap,
+                                                 Map<String, String> featureMapString) {
+        if (null == list || list.isEmpty()) {
+            return;
+        }
+        for (int i = 0; i < list.size() && i < maxN; i++) {
+            UserSRBO u = list.get(i);
+            if (null == u) continue;
+            long id = u.getId();
+            long ts = u.getTs();
+            if (id <= 0) continue;
+
+            String baseKey = String.format("%s@%d", prefix, i + 1);
+
+            // week & hour
+            if (ts > 0) {
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTimeInMillis(ts * 1000);
+                featureMapString.put(baseKey + "_week", String.valueOf(calendar.get(Calendar.DAY_OF_WEEK)));
+                featureMapString.put(baseKey + "_hour", String.valueOf(calendar.get(Calendar.HOUR_OF_DAY) + 1));
+            }
+
+            // cate1 & cate2
+            if (hasCate && null != hVideoMap) {
+                String vid = id + "";
+                Map<String, String> hVideo = hVideoMap.getOrDefault(vid, new HashMap<>());
+                String cate1 = hVideo.getOrDefault("merge_first_level_cate", "").trim();
+                String cate2 = hVideo.getOrDefault("merge_second_level_cate", "").trim();
+                featureMapString.put(baseKey + "_cate1", (!cate1.isEmpty() && !cate1.equals("unknown")) ? cate1 : "");
+                featureMapString.put(baseKey + "_cate2", (!cate2.isEmpty() && !cate2.equals("unknown")) ? cate2 : "");
+            }
+        }
+    }
+
+    public static void putVideoStringFeatures(String prefix, Map<String, String> videoInfo, Map<String, String> featureMapToString) {
+        featureMapToString.put(prefix + "@resolution", videoInfo.getOrDefault("resolution", ""));
+        featureMapToString.put(prefix + "@time_type", videoInfo.getOrDefault("time_type", ""));
+        featureMapToString.put(prefix + "@cate2", videoInfo.getOrDefault("merge_second_level_cate", ""));
+        featureMapToString.put(prefix + "@cate1_list", videoInfo.getOrDefault("merge_first_level_cate", ""));
+        featureMapToString.put(prefix + "@festive_label1", videoInfo.getOrDefault("festive_label1", ""));
+        featureMapToString.put(prefix + "@channel", videoInfo.getOrDefault("channel", ""));
+        featureMapToString.put(prefix + "@vid_source", videoInfo.getOrDefault("vid_source", ""));
+        featureMapToString.put(prefix + "@uid", videoInfo.getOrDefault("uid", ""));
+        featureMapToString.put(prefix + "@keywords", videoInfo.getOrDefault("keywords", ""));
+        featureMapToString.put(prefix + "@merge_first_level_cate", videoInfo.getOrDefault("merge_first_level_cate", ""));
+        featureMapToString.put(prefix + "@merge_second_level_cate", videoInfo.getOrDefault("merge_second_level_cate", ""));
+    }
+
+    public static void putUserNetworkSeqFeature(Map<String, String> featureMapString, Map<String, String> userNetworkSeqFeatureMap, Map<String, Map<String, Map<String, String>>> videoBaseInfoMap) {
+        featureMapString.put("act_vid_seq", userNetworkSeqFeatureMap.getOrDefault("a_v_s", ""));
+        featureMapString.put("act_type_seq", userNetworkSeqFeatureMap.getOrDefault("a_t_s", ""));
+
+
+        featureMapString.put("net_vid_seq", userNetworkSeqFeatureMap.getOrDefault("n_v_s", ""));
+        featureMapString.put("net_union_id_seq", userNetworkSeqFeatureMap.getOrDefault("n_u_i_s", ""));
+
+
+        List<String> actVidSeq = FeatureUtils.extractVidsFromUserNetworkSeqFeature(userNetworkSeqFeatureMap, "a_v_s");
+        List<String> actCate1Seq = new ArrayList<>(actVidSeq.size());
+        List<String> actCate2Seq = new ArrayList<>(actVidSeq.size());
+        for (String vid : actVidSeq) {
+            Map<String, String> videoBaseInfo = videoBaseInfoMap.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+            actCate1Seq.add(videoBaseInfo.getOrDefault("merge_first_level_cate", "unknown"));
+            actCate2Seq.add(videoBaseInfo.getOrDefault("merge_second_level_cate", "unknown"));
+        }
+        featureMapString.put("act_cate1_seq", String.join(GS_STR, actCate1Seq));
+        featureMapString.put("act_cate2_seq", String.join(GS_STR, actCate2Seq));
+
+        List<String> netVidSeq = FeatureUtils.extractVidsFromUserNetworkSeqFeature(userNetworkSeqFeatureMap, "n_v_s");
+        List<String> netCate1Seq = new ArrayList<>(netVidSeq.size());
+        List<String> netCate2Seq = new ArrayList<>(netVidSeq.size());
+        for (String vid : netVidSeq) {
+            Map<String, String> videoBaseInfo = videoBaseInfoMap.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+            netCate1Seq.add(videoBaseInfo.getOrDefault("merge_first_level_cate", "unknown"));
+            netCate2Seq.add(videoBaseInfo.getOrDefault("merge_second_level_cate", "unknown"));
+        }
+        featureMapString.put("net_cate1_seq", String.join(GS_STR, netCate1Seq));
+        featureMapString.put("net_cate2_seq", String.join(GS_STR, netCate2Seq));
+    }
+
+
+    public static void parseStringFeatureMap(Map<String, String> featureMapToString, RankParam param) {
+        String hotSceneType = Optional.ofNullable(param.getHotSceneType()).map(String::valueOf).orElse("other");
+        String province = Optional.ofNullable(param.getProvince()).orElse("");
+        String city = Optional.ofNullable(param.getCity()).orElse("");
+        String brand = Optional.ofNullable(param.getMachineInfo()).map(MachineInfo::getBrand).orElse("");
+        String model = Optional.ofNullable(param.getMachineInfo()).map(MachineInfo::getModel).orElse("");
+        String system = Optional.ofNullable(param.getMachineInfo()).map(MachineInfo::getSystem).orElse("");
+        String channel = Optional.ofNullable(param.getChannelName()).orElse("");
+        String userLevel = "";
+        if (FeatureUtils.firstLevel(param.getUserShareDepth())) {
+            userLevel = "1st";
+        }
+
+        String appTypeStr = String.valueOf(param.getAppType());
+        if (appSet.contains(appTypeStr)) {
+            featureMapToString.put("ctx_app", appTypeStr);
+        } else {
+            featureMapToString.put("ctx_app", "other");
+        }
+
+        if (hotSceneSet.contains(hotSceneType)) {
+            featureMapToString.put("ctx_hot", hotSceneType);
+        } else {
+            featureMapToString.put("ctx_hot", "other");
+        }
+
+        featureMapToString.put("ctx_week", String.valueOf(Calendar.getInstance().get(Calendar.DAY_OF_WEEK)));
+        featureMapToString.put("ctx_hour", String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY)));
+        featureMapToString.put("ctx_hour_val", String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY)));
+        featureMapToString.put("mid", param.getMid());
+        featureMapToString.put("user_province", province);
+        featureMapToString.put("user_city", city);
+        featureMapToString.put("user_brand", brand);
+        featureMapToString.put("user_model", model);
+        featureMapToString.put("user_system", system);
+        featureMapToString.put("user_channel", channel);
+        featureMapToString.put("user_level", userLevel);
+
+        Map<String, String> creativeInfo = param.getCreativeInfoFeature();
+        if (MapUtils.isNotEmpty(creativeInfo)) {
+            featureMapToString.put("e1_ghid", creativeInfo.getOrDefault("ghid", ""));
+            featureMapToString.put("e1_name", creativeInfo.getOrDefault("name", ""));
+        }
+
+        featureMapToString.put("union_id", "union_id_" + Optional.ofNullable(param.getUnionId()).orElse(""));
+        featureMapToString.put("headvideoid", "headvideoid_" + Optional.ofNullable(param.getHeadVid()).map(Object::toString).orElse("-1024"));
+
+        String pageSource = param.getCurrentPageSource();
+        if (StringUtils.endsWith(pageSource, "pages/user-videos-share")) {
+            featureMapToString.put("page_is_return", "1");
+        } else {
+            featureMapToString.put("page_is_return", "0");
+        }
+    }
 }

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

@@ -26,7 +26,6 @@ public class RecallParam {
     private Long videoId;
     private String uid;
     private boolean specialRecommend;
-    private boolean appTypeSpecialRecommend;
     private Set<String> abExpCodes;
     private Integer categoryId;
 
@@ -51,6 +50,7 @@ public class RecallParam {
     private Map<String, String> creativeInfoFeature;
     private Map<String, Map<String, String>> behaviorVideos;
     private String openGId;
+    private String unionId;
 
     private Map<String, String> userSocialRecallInfo;
 }

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

@@ -89,10 +89,6 @@ public class RecallService implements ApplicationContextAware {
 
     private List<RecallStrategy> getRecallStrategy(RecallParam param) {
         List<RecallStrategy> strategies = new ArrayList<>();
-        if (param.isAppTypeSpecialRecommend()){
-            strategies.add(strategyMap.get(AppTypeSpecialRecallStrategy.class.getSimpleName()));
-            return strategies;
-        }
 
         if (2 == param.getRecommendType()) {
             strategies.add(strategyMap.get(HotReturnUvRecallStrategy.class.getSimpleName()));
@@ -186,7 +182,7 @@ public class RecallService implements ApplicationContextAware {
             return false;
         }
         if (specialAppVid != null && specialAppVid.getOrDefault("app", new ArrayList<>()).contains((long) appId)) {
-            log.info("This request hits a special logic in matchSpecialApp with appId={}", appId);
+            // log.info("This request hits a special logic in matchSpecialApp with appId={}", appId);
             return true;
         }
         return false;

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

@@ -1,77 +0,0 @@
-package com.tzld.piaoquan.recommend.server.service.recall.strategy;
-
-import com.tzld.piaoquan.recommend.server.model.Video;
-import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
-import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang.math.NumberUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.ZSetOperations;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-
-@Slf4j
-@Service
-public class AppTypeSpecialRecallStrategy implements RecallStrategy {
-    @Autowired
-    @Qualifier("redisTemplate")
-    private RedisTemplate<String, String> redisTemplate;
-
-    public static final String LAST_VIDEO_KEY_FORMAT = "recall:apptype:last:special:%s:%s";
-    public static final String PUSH_FROM = "special_videos";
-    public static final String RECALL_KEY_FORMAT = "recall:apptype:specil:items:%s";
-
-    @Override
-    public List<Video> recall(RecallParam param) {
-
-        String lastVideoRedisKey = String.format(LAST_VIDEO_KEY_FORMAT, param.getAppType(), param.getVideoId());
-        String recallKey = String.format(RECALL_KEY_FORMAT, param.getAppType());
-        String value = redisTemplate.opsForValue().get(lastVideoRedisKey);
-        Long idx = 0L;
-        if (StringUtils.isNotBlank(value)) {
-            idx = redisTemplate.opsForZSet().reverseRank(recallKey, value);
-            if (idx == null) {
-                idx = 0L;
-            } else {
-                idx += 1;
-            }
-        }
-
-        int getSize = param.getSize() * 5;
-        int freq = 0;
-        List<Video> results = new ArrayList<>();
-        while (results.size() < param.getSize()) {
-            freq += 1;
-            if (freq > 2) {
-                break;
-            }
-            Set<ZSetOperations.TypedTuple<String>> data = redisTemplate.opsForZSet().reverseRangeWithScores(recallKey, idx, idx + getSize - 1);
-            if (CollectionUtils.isEmpty(data)) {
-                break;
-            }
-            idx += getSize;
-            data.forEach(t -> {
-                Video video = new Video();
-                video.setVideoId(NumberUtils.toLong(t.getValue(), 0L));
-                video.setRovScore(t.getScore());
-                video.setPushFrom(PUSH_FROM);
-                video.setLastVideoKey(lastVideoRedisKey);
-                results.add(video);
-            });
-        }
-        return results;
-    }
-
-    @Override
-    public String pushFrom() {
-        return PUSH_FROM;
-    }
-}

+ 93 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/PAIScorer.java

@@ -0,0 +1,93 @@
+package com.tzld.piaoquan.recommend.server.service.score;
+
+import com.google.common.collect.Lists;
+import com.tzld.piaoquan.recommend.feature.domain.video.base.UserFeature;
+import com.tzld.piaoquan.recommend.server.common.base.RankItem;
+import com.tzld.piaoquan.recommend.server.service.score.model.PAIModel;
+import org.apache.commons.collections4.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class PAIScorer extends AbstractScorer {
+
+    private static final int LOCAL_TIME_OUT = 300;
+    private final static Logger LOGGER = LoggerFactory.getLogger(PAIScorer.class);
+    private static final ExecutorService executorService = Executors.newFixedThreadPool(128);
+    private static final int BATCH_SIZE = 300;
+
+
+    public PAIScorer(ScorerConfigInfo scorerConfigInfo) {
+        super(scorerConfigInfo);
+    }
+
+    @Override
+    public List<RankItem> scoring(ScoreParam param, UserFeature userFeature, List<RankItem> rankItems) {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    public List<RankItem> scoring(Map<String, Float> sceneFeatureMap, Map<String, Float> userFeatureMap, List<RankItem> rankItems) {
+        if (CollectionUtils.isEmpty(rankItems)) {
+            return rankItems;
+        }
+        long startTime = System.currentTimeMillis();
+        List<RankItem> result = rankByJava(sceneFeatureMap, userFeatureMap, rankItems);
+
+        LOGGER.debug("pai ranker time java items size={}, time={} ",
+                result.size(), System.currentTimeMillis() - startTime);
+
+        return result;
+    }
+
+    private List<RankItem> rankByJava(Map<String, Float> sceneFeatureMap, Map<String, Float> userFeatureMap, List<RankItem> rankItems) {
+        List<List<RankItem>> partition = Lists.partition(rankItems, BATCH_SIZE);
+        List<Future<List<RankItem>>> futures = new ArrayList<>();
+        for (List<RankItem> items : partition) {
+            futures.add(executorService.submit(() -> {
+                try {
+                    batchCallScore(PAIModel.getModelInstance(), items);
+                } catch (Exception e) {
+                    LOGGER.error("batchCallScore error ", e);
+                }
+                return items;
+            }));
+        }
+
+        List<RankItem> result = new ArrayList<>(rankItems.size());
+        for (Future<List<RankItem>> future : futures) {
+            try {
+                result.addAll(future.get(LOCAL_TIME_OUT, TimeUnit.MILLISECONDS));
+            } catch (Exception e) {
+                LOGGER.info("executorService.submit error ", e);
+            }
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    public void batchCallScore(final PAIModel model, final List<RankItem> rankItems) {
+        try {
+            Map<String, List<Float>> scoreMap = model.score(rankItems);
+            List<Float> returnNUvScoreList = scoreMap.get("y_return_n_uv");
+            List<Float> isShareScoreList = scoreMap.get("probs_is_share");
+            for (int i = 0; i < rankItems.size(); i++) {
+                RankItem rankItem = rankItems.get(i);
+                Float ros = returnNUvScoreList.get(i);
+                Float str = isShareScoreList.get(i);
+                rankItem.setScoreRov(Double.valueOf(str));
+                rankItem.getScoresMap().put("NorDNNScore", Double.valueOf(ros));
+            }
+        } catch (Exception e) {
+            LOGGER.error("pai scorer batch call score error ", e);
+        }
+    }
+}

+ 145 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/score/model/PAIModel.java

@@ -0,0 +1,145 @@
+package com.tzld.piaoquan.recommend.server.service.score.model;
+
+import com.aliyun.openservices.eas.predict.http.HttpConfig;
+import com.aliyun.openservices.eas.predict.http.PredictClient;
+import com.aliyun.openservices.eas.predict.proto.PredictProtos;
+import com.aliyun.openservices.eas.predict.request.TFDataType;
+import com.aliyun.openservices.eas.predict.request.TFRequest;
+import com.aliyun.openservices.eas.predict.response.TFResponse;
+import com.tzld.piaoquan.recommend.server.common.base.RankItem;
+import com.tzld.piaoquan.recommend.server.model.Tuple4;
+import com.tzld.piaoquan.recommend.server.service.rank.tansform.FGEncoder;
+import com.tzld.piaoquan.recommend.server.service.rank.tansform.FGEncoderManager;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+public class PAIModel {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(PAIModel.class);
+
+    private final String fgConfigFilePath;
+    private final String easToken;
+    private final String easEndpoint;
+    private final String modelName;
+
+    private PredictClient predictClient;
+    private List<Tuple4<String, String, String, TFDataType>> featureKeys = new ArrayList<>();
+
+    private static volatile PAIModel MODEL;
+
+    private PAIModel() {
+        this.fgConfigFilePath = "zhaohaipeng/pai/config/fg/feature_list_20260403.json";
+        this.easToken = "MmEwYzVlZGFiOTM4YWM3ZTE5ZDMzNTgzY2Q5YjZlYjVjODE5ZjIzYQ==";
+        this.easEndpoint = "1894469520484605.cn-hangzhou.pai-eas.aliyuncs.com";
+        this.modelName = "recsys_dnn_v1_20260327";
+
+        this.parseFeatureKey();
+        this.initPredictClient();
+    }
+
+    public static PAIModel getModelInstance() {
+        if (MODEL == null) {
+            synchronized (PAIModel.class) {
+                if (MODEL == null) {
+                    MODEL = new PAIModel();
+                }
+            }
+        }
+        return MODEL;
+    }
+
+    private void parseFeatureKey() {
+        // 初始化fg key与特征生产时的key的映射
+        FGEncoder fgEncoder = FGEncoderManager.getInstance().getFGEncoder(fgConfigFilePath);
+        for (FGEncoder.FeatureDef featureDef : fgEncoder.getFeatureDefs()) {
+            Tuple4<String, String, String, TFDataType> featureKeyTuple = new Tuple4<>();
+
+            featureKeyTuple.setV1(featureDef.feature_key);
+            featureKeyTuple.setV2(featureDef.feature_name);
+            featureKeyTuple.setV3(featureDef.default_value);
+            featureKeyTuple.setV4(featureDef.typeCoverToTFDataType());
+            featureKeys.add(featureKeyTuple);
+        }
+    }
+
+    private void initPredictClient() {
+        predictClient = new PredictClient(new HttpConfig());
+        predictClient.setModelName(this.modelName);
+        predictClient.setToken(this.easToken);
+        predictClient.setEndpoint(this.easEndpoint);
+    }
+
+    public Map<String, List<Float>> score(List<RankItem> rankItems) {
+
+        List<String> scoreKeys = Arrays.asList("y_return_n_uv", "probs_is_share");
+        int size = rankItems.size();
+
+        try {
+
+            List<Map<String, Float>> featureMapList = new ArrayList<>(rankItems.size());
+            List<Map<String, String>> featureMapStringList = new ArrayList<>(rankItems.size());
+
+            for (RankItem rankItem : rankItems) {
+                featureMapList.add(Optional.ofNullable(rankItem.featureMap).orElse(new HashMap<>()));
+                featureMapStringList.add(Optional.ofNullable(rankItem.featureMapString).orElse(new HashMap<>()));
+            }
+
+            // 生成特征名与特征值数组的映射
+            Map<String, double[]> doubleFeatureArr = new HashMap<>();
+            Map<String, String[]> stringFeatureArr = new HashMap<>();
+            for (Tuple4<String, String, String, TFDataType> featureKeyTuple : featureKeys) {
+                TFDataType dataType = featureKeyTuple.getV4();
+                String featureName = featureKeyTuple.getV2();
+                String featureKey = featureKeyTuple.getV1();
+                String defaultValue = featureKeyTuple.getV3();
+
+                if (TFDataType.DT_STRING.equals(dataType)) {
+                    for (int i = 0; i < size; i++) {
+                        Map<String, String> featureMapString = featureMapStringList.get(i);
+                        String[] strArr = stringFeatureArr.computeIfAbsent(featureName, s -> new String[size]);
+                        String value = featureMapString.getOrDefault(featureKey, defaultValue);
+                        strArr[i] = value;
+                    }
+                } else {
+                    for (int i = 0; i < size; i++) {
+                        Map<String, Float> featureMap = featureMapList.get(i);
+                        double[] doubleArr = doubleFeatureArr.computeIfAbsent(featureName, s -> new double[size]);
+                        double value = featureMap.getOrDefault(featureKey, NumberUtils.toFloat(defaultValue, 0f));
+                        doubleArr[i] = value;
+                    }
+                }
+            }
+
+            TFRequest request = new TFRequest();
+            long[] shape = new long[]{size};
+            for (Tuple4<String, String, String, TFDataType> featureKey : featureKeys) {
+                String featureName = featureKey.getV2();
+                TFDataType dataType = featureKey.getV4();
+                if (TFDataType.DT_STRING.equals(dataType)) {
+                    request.addFeed(featureName, TFDataType.DT_STRING, shape, stringFeatureArr.get(featureName));
+                } else {
+                    request.addFeed(featureName, TFDataType.DT_DOUBLE, shape, doubleFeatureArr.get(featureName));
+                }
+            }
+            TFResponse response = predictClient.predict(request);
+            Map<String, PredictProtos.ArrayProto> outputsMap = response.getOutputsMap();
+            LOGGER.info("response keys: {}", outputsMap.keySet());
+            Map<String, List<Float>> resultMap = new HashMap<>();
+            for (String scoreKey : scoreKeys) {
+                resultMap.put(scoreKey, response.getFloatVals(scoreKey));
+            }
+            return resultMap;
+        } catch (Exception e) {
+            LOGGER.error("pai eas error ", e);
+            Map<String, List<Float>> resultMap = new HashMap<>();
+            for (String scoreKey : scoreKeys) {
+                resultMap.put(scoreKey, Collections.nCopies(size, 0.0f));
+            }
+            return resultMap;
+        }
+    }
+
+}

+ 15 - 2
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/FeatureUtils.java

@@ -1,11 +1,12 @@
 package com.tzld.piaoquan.recommend.server.util;
 
+import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 public class FeatureUtils {
     public static final String cate1Attr = "cate1_list";
@@ -169,4 +170,16 @@ public class FeatureUtils {
     private static boolean isLetter(char c) {
         return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
     }
+
+    public static List<String> extractVidsFromUserNetworkSeqFeature(Map<String, String> userNetworkSeqFeature, String key) {
+        if (MapUtils.isEmpty(userNetworkSeqFeature) || StringUtils.isBlank(key)) {
+            return new ArrayList<>();
+        }
+        if (!userNetworkSeqFeature.containsKey(key)) {
+            return new ArrayList<>();
+        }
+        String groupSeparator = "\u001D";
+        return Arrays.stream(userNetworkSeqFeature.get(key).split(groupSeparator))
+                .collect(Collectors.toList());
+    }
 }

+ 3 - 446
recommend-server-service/src/main/resources/feeds_score_config_xgb_ros_20250311.conf

@@ -1,449 +1,6 @@
 scorer-config = {
-  rov-score-config = {
-     scorer-name = "com.tzld.piaoquan.recommend.server.service.score.VlogRovFMScorer"
-     scorer-priority = 96
-     model-path = "zhangbo/model_fm_for_recsys_v1_str.txt"
-  }
-  nor-score-config = {
-    scorer-name = "com.tzld.piaoquan.recommend.server.service.score.NorXGBRegressionScorer"
-    scorer-priority = 97
-    model-path = "zhangbo/model_xgb_for_recsys_v9_nor.tar.gz"
-    param = {
-      localDir = "xgboost/recsys_v9_nor"
-      features = [
-      "b0_12h@return_1_uv",
-      "b0_12h@ros1_#",
-      "b0_12h@ros_#",
-      "b0_12h@ros_minus1_#",
-      "b0_12h@ros_minus_#",
-      "b0_12h@ros_n1_#",
-      "b0_12h@ros_n_#",
-      "b0_12h@ros_one",
-      "b0_12h@rovn1_#",
-      "b0_12h@rovn_#",
-      "b0_1h@return_1_uv",
-      "b0_1h@ros1_#",
-      "b0_1h@ros_#",
-      "b0_1h@ros_minus1_#",
-      "b0_1h@ros_minus_#",
-      "b0_1h@ros_n1_#",
-      "b0_1h@ros_n_#",
-      "b0_1h@ros_one",
-      "b0_1h@rovn1_#",
-      "b0_1h@rovn_#",
-      "b0_3h@return_1_uv",
-      "b0_3h@ros1_#",
-      "b0_3h@ros_#",
-      "b0_3h@ros_minus1_#",
-      "b0_3h@ros_minus_#",
-      "b0_3h@ros_n1_#",
-      "b0_3h@ros_n_#",
-      "b0_3h@ros_one",
-      "b0_3h@rovn1_#",
-      "b0_3h@rovn_#",
-      "b0_6h@return_1_uv",
-      "b0_6h@ros1_#",
-      "b0_6h@ros_#",
-      "b0_6h@ros_minus1_#",
-      "b0_6h@ros_minus_#",
-      "b0_6h@ros_n1_#",
-      "b0_6h@ros_n_#",
-      "b0_6h@ros_one",
-      "b0_6h@rovn1_#",
-      "b0_6h@rovn_#",
-      "b10_12h@is_share",
-      "b10_12h@return_n_uv",
-      "b10_12h@ros_#",
-      "b10_12h@ros_minus_#",
-      "b10_12h@rovn_#",
-      "b10_12h@str",
-      "b10_12h@str_plus",
-      "b10_1h@is_share",
-      "b10_1h@return_n_uv",
-      "b10_1h@ros_#",
-      "b10_1h@ros_minus_#",
-      "b10_1h@rovn_#",
-      "b10_1h@str",
-      "b10_1h@str_plus",
-      "b11_12h@is_share",
-      "b11_12h@return_n_uv",
-      "b11_12h@ros_#",
-      "b11_12h@ros_minus_#",
-      "b11_12h@rovn_#",
-      "b11_12h@str",
-      "b11_12h@str_plus",
-      "b13_1h@exp",
-      "b13_1h@is_share",
-      "b13_1h@ros_#",
-      "b13_1h@ros_minus_#",
-      "b13_1h@ros_n_#",
-      "b13_1h@ros_one",
-      "b13_1h@rovn_#",
-      "b13_1h@share_cnt",
-      "b13_1h@str",
-      "b13_1h@str_plus",
-      "b13_24h@exp",
-      "b13_24h@is_share",
-      "b13_24h@ros_#",
-      "b13_24h@ros_minus_#",
-      "b13_24h@ros_n_#",
-      "b13_24h@ros_one",
-      "b13_24h@rovn_#",
-      "b13_24h@share_cnt",
-      "b13_24h@str",
-      "b13_24h@str_plus",
-      "b13_3h@exp",
-      "b13_3h@is_share",
-      "b13_3h@ros_#",
-      "b13_3h@ros_minus_#",
-      "b13_3h@ros_n_#",
-      "b13_3h@ros_one",
-      "b13_3h@rovn_#",
-      "b13_3h@share_cnt",
-      "b13_3h@str",
-      "b13_3h@str_plus",
-      "b13_72h@exp",
-      "b13_72h@is_share",
-      "b13_72h@ros_#",
-      "b13_72h@ros_minus_#",
-      "b13_72h@ros_n_#",
-      "b13_72h@ros_one",
-      "b13_72h@rovn_#",
-      "b13_72h@share_cnt",
-      "b13_72h@str",
-      "b13_72h@str_plus",
-      "b1_1h@ros_#",
-      "b1_1h@ros_minus_#",
-      "b1_1h@ros_n_#",
-      "b1_1h@ros_one",
-      "b1_1h@rovn_#",
-      "b1_24h@ros_#",
-      "b1_24h@ros_minus_#",
-      "b1_24h@ros_n_#",
-      "b1_24h@ros_one",
-      "b1_24h@rovn_#",
-      "b1_3h@ros_#",
-      "b1_3h@ros_minus_#",
-      "b1_3h@ros_n_#",
-      "b1_3h@ros_one",
-      "b1_3h@rovn_#",
-      "b1_72h@ros_#",
-      "b1_72h@ros_minus_#",
-      "b1_72h@ros_n_#",
-      "b1_72h@ros_one",
-      "b1_72h@rovn_#",
-      "b2_24h@return_n_uv",
-      "b2_24h@ros_#",
-      "b2_24h@ros_minus_#",
-      "b2_24h@ros_n_#",
-      "b2_24h@ros_one",
-      "b2_24h@rovn_#",
-      "b2_3h@return_n_uv",
-      "b2_3h@ros_#",
-      "b2_3h@ros_minus_#",
-      "b2_3h@ros_n_#",
-      "b2_3h@ros_one",
-      "b2_3h@rovn_#",
-      "b3_24h@is_share",
-      "b3_24h@return_n_uv",
-      "b3_24h@ros_#",
-      "b3_24h@ros_minus_#",
-      "b3_24h@ros_n_#",
-      "b3_24h@ros_one",
-      "b3_24h@rovn_#",
-      "b3_24h@str",
-      "b3_24h@str_plus",
-      "b3_72h@is_share",
-      "b3_72h@return_n_uv",
-      "b3_72h@ros_#",
-      "b3_72h@ros_minus_#",
-      "b3_72h@ros_n_#",
-      "b3_72h@ros_one",
-      "b3_72h@rovn_#",
-      "b3_72h@str",
-      "b3_72h@str_plus",
-      "b4_12h@is_share",
-      "b4_12h@return_n_uv",
-      "b4_12h@ros_#",
-      "b4_12h@ros_minus_#",
-      "b4_12h@ros_n_#",
-      "b4_12h@ros_one",
-      "b4_12h@rovn_#",
-      "b4_3h@is_share",
-      "b4_3h@return_n_uv",
-      "b4_3h@ros_#",
-      "b4_3h@ros_minus_#",
-      "b4_3h@ros_n_#",
-      "b4_3h@ros_one",
-      "b4_3h@rovn_#",
-      "b5_12h@exp",
-      "b5_12h@is_share",
-      "b5_12h@return_n_uv",
-      "b5_12h@ros_#",
-      "b5_12h@ros_minus_#",
-      "b5_12h@ros_n_#",
-      "b5_12h@ros_one",
-      "b5_12h@rovn_#",
-      "b5_12h@share_cnt",
-      "b5_12h@str",
-      "b5_12h@str_plus",
-      "b5_1h@exp",
-      "b5_1h@is_share",
-      "b5_1h@return_n_uv",
-      "b5_1h@ros_#",
-      "b5_1h@ros_minus_#",
-      "b5_1h@ros_n_#",
-      "b5_1h@ros_one",
-      "b5_1h@rovn_#",
-      "b5_1h@share_cnt",
-      "b5_1h@str",
-      "b5_1h@str_plus",
-      "b5_24h@exp",
-      "b5_24h@is_share",
-      "b5_24h@return_n_uv",
-      "b5_24h@ros_#",
-      "b5_24h@ros_minus_#",
-      "b5_24h@ros_n_#",
-      "b5_24h@ros_one",
-      "b5_24h@rovn_#",
-      "b5_24h@share_cnt",
-      "b5_24h@str",
-      "b5_24h@str_plus",
-      "b5_3h@exp",
-      "b5_3h@is_share",
-      "b5_3h@return_n_uv",
-      "b5_3h@ros_#",
-      "b5_3h@ros_minus_#",
-      "b5_3h@ros_n_#",
-      "b5_3h@ros_one",
-      "b5_3h@rovn_#",
-      "b5_3h@share_cnt",
-      "b5_3h@str",
-      "b5_3h@str_plus",
-      "b5_6h@exp",
-      "b5_6h@is_share",
-      "b5_6h@return_n_uv",
-      "b5_6h@ros_#",
-      "b5_6h@ros_minus_#",
-      "b5_6h@ros_n_#",
-      "b5_6h@ros_one",
-      "b5_6h@rovn_#",
-      "b5_6h@share_cnt",
-      "b5_6h@str",
-      "b5_6h@str_plus",
-      "b5_72h@exp",
-      "b5_72h@is_share",
-      "b5_72h@return_n_uv",
-      "b5_72h@ros_#",
-      "b5_72h@ros_minus_#",
-      "b5_72h@ros_n_#",
-      "b5_72h@ros_one",
-      "b5_72h@rovn_#",
-      "b5_72h@share_cnt",
-      "b5_72h@str",
-      "b5_72h@str_plus",
-      "b6_1h@is_share",
-      "b6_1h@return_n_uv",
-      "b6_1h@ros_#",
-      "b6_1h@ros_minus_#",
-      "b6_1h@ros_n_#",
-      "b6_1h@ros_one",
-      "b6_1h@rovn_#",
-      "b6_1h@str",
-      "b6_1h@str_plus",
-      "b6_24h@is_share",
-      "b6_24h@return_n_uv",
-      "b6_24h@ros_#",
-      "b6_24h@ros_minus_#",
-      "b6_24h@ros_n_#",
-      "b6_24h@ros_one",
-      "b6_24h@rovn_#",
-      "b6_24h@str",
-      "b6_24h@str_plus",
-      "b7_1h@is_share",
-      "b7_1h@return_n_uv",
-      "b7_1h@ros_#",
-      "b7_1h@ros_minus_#",
-      "b7_1h@ros_n_#",
-      "b7_1h@ros_one",
-      "b7_1h@rovn_#",
-      "b7_1h@str",
-      "b7_1h@str_plus",
-      "b7_24h@is_share",
-      "b7_24h@return_n_uv",
-      "b7_24h@ros_#",
-      "b7_24h@ros_minus_#",
-      "b7_24h@ros_n_#",
-      "b7_24h@ros_one",
-      "b7_24h@rovn_#",
-      "b7_24h@str",
-      "b7_24h@str_plus",
-      "b7_3h@is_share",
-      "b7_3h@return_n_uv",
-      "b7_3h@ros_#",
-      "b7_3h@ros_minus_#",
-      "b7_3h@ros_n_#",
-      "b7_3h@ros_one",
-      "b7_3h@rovn_#",
-      "b7_3h@str",
-      "b7_3h@str_plus",
-      "b7_72h@is_share",
-      "b7_72h@return_n_uv",
-      "b7_72h@ros_#",
-      "b7_72h@ros_minus_#",
-      "b7_72h@ros_n_#",
-      "b7_72h@ros_one",
-      "b7_72h@rovn_#",
-      "b7_72h@str",
-      "b7_72h@str_plus",
-      "b8_1h@is_share",
-      "b8_1h@return_n_uv",
-      "b8_1h@ros_#",
-      "b8_1h@ros_minus_#",
-      "b8_1h@rovn_#",
-      "b8_1h@str",
-      "b8_1h@str_plus",
-      "b8_24h@is_share",
-      "b8_24h@return_n_uv",
-      "b8_24h@ros_#",
-      "b8_24h@ros_minus_#",
-      "b8_24h@rovn_#",
-      "b8_24h@str",
-      "b8_24h@str_plus",
-      "b8_3h@is_share",
-      "b8_3h@return_n_uv",
-      "b8_3h@ros_#",
-      "b8_3h@ros_minus_#",
-      "b8_3h@rovn_#",
-      "b8_3h@str",
-      "b8_3h@str_plus",
-      "b9_1h@is_share",
-      "b9_1h@return_n_uv",
-      "b9_1h@ros_#",
-      "b9_1h@ros_minus_#",
-      "b9_1h@rovn_#",
-      "b9_1h@str",
-      "b9_1h@str_plus",
-      "b9_24h@is_share",
-      "b9_24h@return_n_uv",
-      "b9_24h@ros_#",
-      "b9_24h@ros_minus_#",
-      "b9_24h@rovn_#",
-      "b9_24h@str",
-      "b9_24h@str_plus",
-      "b9_3h@is_share",
-      "b9_3h@return_n_uv",
-      "b9_3h@ros_#",
-      "b9_3h@ros_minus_#",
-      "b9_3h@rovn_#",
-      "b9_3h@str",
-      "b9_3h@str_plus",
-      "c1_168h@is_share",
-      "c1_168h@return_n_uv",
-      "c1_168h@ros_#",
-      "c1_168h@ros_minus_#",
-      "c1_168h@ros_n_#",
-      "c1_168h@ros_one",
-      "c1_168h@rovn_#",
-      "c1_168h@str",
-      "c1_168h@str_plus",
-      "c1_72h@is_share",
-      "c1_72h@return_n_uv",
-      "c1_72h@ros_#",
-      "c1_72h@ros_minus_#",
-      "c1_72h@ros_n_#",
-      "c1_72h@ros_one",
-      "c1_72h@rovn_#",
-      "c1_72h@str",
-      "c1_72h@str_plus",
-      "c5_tags_1d@avgscore",
-      "c5_tags_1d@maxscore",
-      "c5_tags_3d@avgscore",
-      "c5_tags_3d@maxscore",
-      "c5_tags_7d@avgscore",
-      "c5_tags_7d@maxscore",
-      "c6_tags_1d@avgscore",
-      "c6_tags_1d@maxscore",
-      "c6_tags_3d@avgscore",
-      "c6_tags_3d@maxscore",
-      "c6_tags_7d@avgscore",
-      "c6_tags_7d@maxscore",
-      "c9@m_r_uv",
-      "c9@m_s_cnt",
-      "c9@r_pv",
-      "c9@r_uv",
-      "c9@ros",
-      "c9@ros_minus",
-      "c9@ros_one",
-      "c9@s_cnt",
-      "c9@s_pv",
-      "c9_c1s@mu",
-      "c9_c1s@ros",
-      "c9_c1s@ros_minus",
-      "c9_c1s@ros_one",
-      "c9_c1s@rp",
-      "c9_c1s@ru",
-      "c9_c1s@sp",
-      "c9_c2s@mu",
-      "c9_c2s@ros",
-      "c9_c2s@ros_minus",
-      "c9_c2s@ros_one",
-      "c9_c2s@rp",
-      "c9_c2s@ru",
-      "c9_c2s@sp",
-      "c9_l1s@mu",
-      "c9_l1s@ros",
-      "c9_l1s@ros_minus",
-      "c9_l1s@sp",
-      "c9_l2s@mu",
-      "c9_l2s@ros",
-      "c9_l2s@ros_minus",
-      "c9_l2s@sp",
-      "c9_lrs@1@title",
-      "c9_lrs@1@ts",
-      "c9_lrs@1@uv",
-      "c9_lrs@2@title",
-      "c9_lrs@2@ts",
-      "c9_lrs@2@uv",
-      "c9_lss@1@cnt",
-      "c9_lss@1@title",
-      "c9_lss@1@ts",
-      "c9_lss@2@cnt",
-      "c9_lss@2@title",
-      "c9_lss@2@ts",
-      "c9_mrs@1@title",
-      "c9_mrs@1@ts",
-      "c9_mrs@1@uv",
-      "c9_mrs@2@title",
-      "c9_mrs@2@ts",
-      "c9_mrs@2@uv",
-      "c9_mss@1@cnt",
-      "c9_mss@1@title",
-      "c9_mss@1@ts",
-      "c9_mss@2@cnt",
-      "c9_mss@2@title",
-      "c9_mss@2@ts",
-      "d1@ros_cf_rank",
-      "d1@ros_cf_score",
-      "d1@rov_cf_rank",
-      "d1@rov_cf_score",
-      "d2@rank",
-      "d2@score",
-      "d3@exp",
-      "d3@return_n",
-      "d3@rovn",
-      "h@bit_rate",
-      "h@total_time",
-      "h@ts",
-      "hour",
-      "hr_sim@cate2",
-      "hr_sim@cate2_list",
-      "hr_sim@keywords",
-      "hr_sim@title",
-      "r@bit_rate",
-      "r@total_time",
-      "r@ts"
-      ]
-    }
+  pai-eas-score-config = {
+     scorer-name = "com.tzld.piaoquan.recommend.server.service.score.PAIScorer"
+     scorer-priority = 100
   }
 }