浏览代码

Merge branch 'feature_20250704_zhaohaipeng_immerse_recommend' of algorithm/recommend-server into master

jiachanghui 6 天之前
父节点
当前提交
ae6920ff23
共有 20 个文件被更改,包括 634 次插入27 次删除
  1. 1 1
      recommend-server-client/pom.xml
  2. 24 23
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/Recommend.java
  3. 203 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequest.java
  4. 18 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequestOrBuilder.java
  5. 2 0
      recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/recommend.proto
  6. 1 1
      recommend-server-service/pom.xml
  7. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/RankItem.java
  8. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java
  9. 19 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java
  10. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankParam.java
  11. 6 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankRouter.java
  12. 7 2
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java
  13. 175 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RelevantModelV1.java
  14. 5 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/tansform/FeatureV6.java
  15. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallParam.java
  16. 4 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java
  17. 103 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/HotReturnUvRecallStrategy.java
  18. 18 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/CommonCollectionUtils.java
  19. 24 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/FeatureUtils.java
  20. 12 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/web/RecommendV2Controller.java

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

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

+ 24 - 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\"\307\005\n\020RecommendRequest\022\022\n\nrequest" +
+      "on.proto\"\376\005\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_" +
@@ -77,27 +77,28 @@ public final class Recommend {
       "\t\022\024\n\014version_code\030\027 \001(\005\022\026\n\016root_source_i" +
       "d\030\030 \001(\t\022\026\n\016userShareDepth\030\031 \001(\005\022\017\n\007pageN" +
       "um\030\032 \001(\005\022\025\n\rrootSessionId\030\033 \001(\t\022)\n\nshare" +
-      "_list\030\034 \003(\0132\025.VideoActionInfoProto\032.\n\014Ev" +
-      "entIdEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\002" +
-      "8\001\"\177\n\020MachineInfoProto\022\r\n\005brand\030\001 \001(\t\022\r\n" +
-      "\005model\030\002 \001(\t\022\020\n\010platform\030\003 \001(\t\022\023\n\013sdk_ve" +
-      "rsion\030\004 \001(\t\022\016\n\006system\030\005 \001(\t\022\026\n\016wechat_ve" +
-      "rsion\030\006 \001(\t\"H\n\021RecommendResponse\022\027\n\006resu" +
-      "lt\030\001 \001(\0132\007.Result\022\032\n\005video\030\002 \003(\0132\013.Video" +
-      "Proto\"\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\007" +
-      "ab_code\030\004 \001(\t\022\022\n\nsort_score\030\005 \001(\001\022\020\n\010pos" +
-      "ition\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_fr" +
-      "om_index\030\n \003(\0132\016.PushFromIndex\"1\n\rPushFr" +
-      "omIndex\022\021\n\tpush_from\030\001 \001(\t\022\r\n\005index\030\002 \003(" +
-      "\t\"4\n\024VideoActionInfoProto\022\020\n\010video_id\030\001 " +
-      "\001(\003\022\n\n\002ts\030\002 \001(\0032\212\001\n\020RecommendService\022:\n\021" +
-      "HomepageRecommend\022\021.RecommendRequest\032\022.R" +
-      "ecommendResponse\022:\n\021RelevantRecommend\022\021." +
-      "RecommendRequest\032\022.RecommendResponseB7\n0" +
-      "com.tzld.piaoquan.recommend.server.gen.r" +
-      "ecommendP\001\210\001\001b\006proto3"
+      "_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\032.\n\014EventIdEntry\022\013\n\003key\030\001 \001(\t\022\r" +
+      "\n\005value\030\002 \001(\t:\0028\001\"\177\n\020MachineInfoProto\022\r\n" +
+      "\005brand\030\001 \001(\t\022\r\n\005model\030\002 \001(\t\022\020\n\010platform\030" +
+      "\003 \001(\t\022\023\n\013sdk_version\030\004 \001(\t\022\016\n\006system\030\005 \001" +
+      "(\t\022\026\n\016wechat_version\030\006 \001(\t\"H\n\021RecommendR" +
+      "esponse\022\027\n\006result\030\001 \001(\0132\007.Result\022\032\n\005vide" +
+      "o\030\002 \003(\0132\013.VideoProto\"\336\001\n\nVideoProto\022\020\n\010v" +
+      "ideo_id\030\001 \001(\003\022\021\n\trov_score\030\002 \001(\001\022\021\n\tpush" +
+      "_from\030\003 \001(\t\022\017\n\007ab_code\030\004 \001(\t\022\022\n\nsort_sco" +
+      "re\030\005 \001(\001\022\020\n\010position\030\006 \001(\005\022\021\n\tflow_pool\030" +
+      "\007 \001(\t\022\027\n\017is_in_flow_pool\030\010 \001(\005\022\014\n\004rand\030\t" +
+      " \001(\001\022\'\n\017push_from_index\030\n \003(\0132\016.PushFrom" +
+      "Index\"1\n\rPushFromIndex\022\021\n\tpush_from\030\001 \001(" +
+      "\t\022\r\n\005index\030\002 \003(\t\"4\n\024VideoActionInfoProto" +
+      "\022\020\n\010video_id\030\001 \001(\003\022\n\n\002ts\030\002 \001(\0032\212\001\n\020Recom" +
+      "mendService\022:\n\021HomepageRecommend\022\021.Recom" +
+      "mendRequest\032\022.RecommendResponse\022:\n\021Relev" +
+      "antRecommend\022\021.RecommendRequest\032\022.Recomm" +
+      "endResponseB7\n0com.tzld.piaoquan.recomme" +
+      "nd.server.gen.recommendP\001\210\001\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -110,7 +111,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", });
+        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", });
     internal_static_RecommendRequest_EventIdEntry_descriptor =
       internal_static_RecommendRequest_descriptor.getNestedTypes().get(0);
     internal_static_RecommendRequest_EventIdEntry_fieldAccessorTable = new

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

@@ -34,6 +34,7 @@ private static final long serialVersionUID = 0L;
     rootSourceId_ = "";
     rootSessionId_ = "";
     shareList_ = java.util.Collections.emptyList();
+    currentPageSource_ = "";
   }
 
   @java.lang.Override
@@ -247,6 +248,17 @@ private static final long serialVersionUID = 0L;
                 input.readMessage(com.tzld.piaoquan.recommend.server.gen.recommend.VideoActionInfoProto.parser(), extensionRegistry));
             break;
           }
+          case 232: {
+
+            requestVideoId_ = input.readInt64();
+            break;
+          }
+          case 242: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            currentPageSource_ = s;
+            break;
+          }
           default: {
             if (!parseUnknownField(
                 input, unknownFields, extensionRegistry, tag)) {
@@ -1191,6 +1203,55 @@ private static final long serialVersionUID = 0L;
     return shareList_.get(index);
   }
 
+  public static final int REQUEST_VIDEO_ID_FIELD_NUMBER = 29;
+  private long requestVideoId_;
+  /**
+   * <code>int64 request_video_id = 29;</code>
+   * @return The requestVideoId.
+   */
+  @java.lang.Override
+  public long getRequestVideoId() {
+    return requestVideoId_;
+  }
+
+  public static final int CURRENT_PAGE_SOURCE_FIELD_NUMBER = 30;
+  private volatile java.lang.Object currentPageSource_;
+  /**
+   * <code>string current_page_source = 30;</code>
+   * @return The currentPageSource.
+   */
+  @java.lang.Override
+  public java.lang.String getCurrentPageSource() {
+    java.lang.Object ref = currentPageSource_;
+    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();
+      currentPageSource_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string current_page_source = 30;</code>
+   * @return The bytes for currentPageSource.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getCurrentPageSourceBytes() {
+    java.lang.Object ref = currentPageSource_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      currentPageSource_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
   private byte memoizedIsInitialized = -1;
   @java.lang.Override
   public final boolean isInitialized() {
@@ -1292,6 +1353,12 @@ private static final long serialVersionUID = 0L;
     for (int i = 0; i < shareList_.size(); i++) {
       output.writeMessage(28, shareList_.get(i));
     }
+    if (requestVideoId_ != 0L) {
+      output.writeInt64(29, requestVideoId_);
+    }
+    if (!getCurrentPageSourceBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 30, currentPageSource_);
+    }
     unknownFields.writeTo(output);
   }
 
@@ -1407,6 +1474,13 @@ private static final long serialVersionUID = 0L;
       size += com.google.protobuf.CodedOutputStream
         .computeMessageSize(28, shareList_.get(i));
     }
+    if (requestVideoId_ != 0L) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt64Size(29, requestVideoId_);
+    }
+    if (!getCurrentPageSourceBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(30, currentPageSource_);
+    }
     size += unknownFields.getSerializedSize();
     memoizedSize = size;
     return size;
@@ -1481,6 +1555,10 @@ private static final long serialVersionUID = 0L;
         .equals(other.getRootSessionId())) return false;
     if (!getShareListList()
         .equals(other.getShareListList())) return false;
+    if (getRequestVideoId()
+        != other.getRequestVideoId()) return false;
+    if (!getCurrentPageSource()
+        .equals(other.getCurrentPageSource())) return false;
     if (!unknownFields.equals(other.unknownFields)) return false;
     return true;
   }
@@ -1558,6 +1636,11 @@ private static final long serialVersionUID = 0L;
       hash = (37 * hash) + SHARE_LIST_FIELD_NUMBER;
       hash = (53 * hash) + getShareListList().hashCode();
     }
+    hash = (37 * hash) + REQUEST_VIDEO_ID_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        getRequestVideoId());
+    hash = (37 * hash) + CURRENT_PAGE_SOURCE_FIELD_NUMBER;
+    hash = (53 * hash) + getCurrentPageSource().hashCode();
     hash = (29 * hash) + unknownFields.hashCode();
     memoizedHashCode = hash;
     return hash;
@@ -1777,6 +1860,10 @@ private static final long serialVersionUID = 0L;
       } else {
         shareListBuilder_.clear();
       }
+      requestVideoId_ = 0L;
+
+      currentPageSource_ = "";
+
       return this;
     }
 
@@ -1849,6 +1936,8 @@ private static final long serialVersionUID = 0L;
       } else {
         result.shareList_ = shareListBuilder_.build();
       }
+      result.requestVideoId_ = requestVideoId_;
+      result.currentPageSource_ = currentPageSource_;
       onBuilt();
       return result;
     }
@@ -2026,6 +2115,13 @@ private static final long serialVersionUID = 0L;
           }
         }
       }
+      if (other.getRequestVideoId() != 0L) {
+        setRequestVideoId(other.getRequestVideoId());
+      }
+      if (!other.getCurrentPageSource().isEmpty()) {
+        currentPageSource_ = other.currentPageSource_;
+        onChanged();
+      }
       this.mergeUnknownFields(other.unknownFields);
       onChanged();
       return this;
@@ -4164,6 +4260,113 @@ private static final long serialVersionUID = 0L;
       }
       return shareListBuilder_;
     }
+
+    private long requestVideoId_ ;
+    /**
+     * <code>int64 request_video_id = 29;</code>
+     * @return The requestVideoId.
+     */
+    @java.lang.Override
+    public long getRequestVideoId() {
+      return requestVideoId_;
+    }
+    /**
+     * <code>int64 request_video_id = 29;</code>
+     * @param value The requestVideoId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setRequestVideoId(long value) {
+      
+      requestVideoId_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int64 request_video_id = 29;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearRequestVideoId() {
+      
+      requestVideoId_ = 0L;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object currentPageSource_ = "";
+    /**
+     * <code>string current_page_source = 30;</code>
+     * @return The currentPageSource.
+     */
+    public java.lang.String getCurrentPageSource() {
+      java.lang.Object ref = currentPageSource_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        currentPageSource_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string current_page_source = 30;</code>
+     * @return The bytes for currentPageSource.
+     */
+    public com.google.protobuf.ByteString
+        getCurrentPageSourceBytes() {
+      java.lang.Object ref = currentPageSource_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        currentPageSource_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string current_page_source = 30;</code>
+     * @param value The currentPageSource to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCurrentPageSource(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      currentPageSource_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string current_page_source = 30;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearCurrentPageSource() {
+      
+      currentPageSource_ = getDefaultInstance().getCurrentPageSource();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string current_page_source = 30;</code>
+     * @param value The bytes for currentPageSource to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCurrentPageSourceBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      currentPageSource_ = value;
+      onChanged();
+      return this;
+    }
     @java.lang.Override
     public final Builder setUnknownFields(
         final com.google.protobuf.UnknownFieldSet unknownFields) {

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

@@ -360,4 +360,22 @@ public interface RecommendRequestOrBuilder extends
    */
   com.tzld.piaoquan.recommend.server.gen.recommend.VideoActionInfoProtoOrBuilder getShareListOrBuilder(
       int index);
+
+  /**
+   * <code>int64 request_video_id = 29;</code>
+   * @return The requestVideoId.
+   */
+  long getRequestVideoId();
+
+  /**
+   * <code>string current_page_source = 30;</code>
+   * @return The currentPageSource.
+   */
+  java.lang.String getCurrentPageSource();
+  /**
+   * <code>string current_page_source = 30;</code>
+   * @return The bytes for currentPageSource.
+   */
+  com.google.protobuf.ByteString
+      getCurrentPageSourceBytes();
 }

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

@@ -37,6 +37,8 @@ message RecommendRequest {
   int32 pageNum = 26;
   string rootSessionId = 27;
   repeated VideoActionInfoProto share_list = 28;
+  int64 request_video_id = 29;
+  string current_page_source = 30;
 }
 
 message MachineInfoProto {

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

@@ -175,7 +175,7 @@
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>
             <artifactId>recommend-server-client</artifactId>
-            <version>1.1.10</version>
+            <version>1.1.11</version>
         </dependency>
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>

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

@@ -38,6 +38,9 @@ public class RankItem implements Comparable<RankItem> {
     // 记录召回信息
     private String queue;
 
+    // title
+    private String title;
+
     // 多样性过滤因子
     // 排序因子
     private Map<String, Double> rankItemCategories = Maps.newHashMap();

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

@@ -54,5 +54,8 @@ public class RecommendParam {
 
     private String rootSessionId;
     private List<UserSRBO> userRTShareList;
+    private int recommendType;
+    private Long requestVideoId;
+    private String currentPageSource;
 }
 

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

@@ -111,6 +111,10 @@ public class RecommendService {
         return recommend(request, 1);
     }
 
+    public RecommendResponse immerseRecommend(RecommendRequest request) {
+        return recommend(request, 2);
+    }
+
     public RecommendResponse recommend(RecommendRequest request, int recommendType) {
         try {
             timerLogMapTL.get().put("traceId", TraceUtils.currentTraceId());
@@ -235,6 +239,12 @@ public class RecommendService {
                             .count();
                 }
                 map.put("featureTableSize", String.valueOf(featureTableSize));
+                if (2 == param.getRecommendType()) {
+                    Map<String, String> extend = new HashMap<>();
+                    extend.put("reqVideo", String.valueOf(request.getRequestVideoId()));
+                    extend.put("currentPage", request.getCurrentPageSource());
+                    map.put("extend", JSONUtils.toJson(extend));
+                }
 
                 return map;
 
@@ -374,6 +384,9 @@ public class RecommendService {
         param.setPageNum(request.getPageNum());
         param.setRootSessionId(request.getRootSessionId());
         param.setUserRTShareList(getUserRTShareList(request.getShareListList()));
+        param.setRecommendType(recommendType);
+        param.setRequestVideoId(request.getRequestVideoId());
+        param.setCurrentPageSource(request.getCurrentPageSource());
         return param;
     }
 
@@ -456,6 +469,9 @@ public class RecommendService {
         recallParam.setUserShareDepth(param.getUserShareDepth());
         recallParam.setChannelName(param.getChannelName());
         recallParam.setRootSessionId(param.getRootSessionId());
+        recallParam.setRecommendType(param.getRecommendType());
+        recallParam.setRequestVideoId(param.getRequestVideoId());
+        recallParam.setCurrentPageSource(param.getCurrentPageSource());
         return recallParam;
     }
 
@@ -484,6 +500,9 @@ public class RecommendService {
         rankParam.setPageNum(param.getPageNum());
         rankParam.setChannelName(param.getChannelName());
         rankParam.setRootSessionId(param.getRootSessionId());
+        rankParam.setRecommendType(param.getRecommendType());
+        rankParam.setRequestVideoId(param.getRequestVideoId());
+        rankParam.setCurrentPageSource(param.getCurrentPageSource());
         return rankParam;
     }
 

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

@@ -43,4 +43,7 @@ public class RankParam {
 
     private String rootSessionId;
     private List<UserSRBO> userRTShareList;
+    private int recommendType;
+    private Long requestVideoId;
+    private String currentPageSource;
 }

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

@@ -18,6 +18,7 @@ public class RankRouter {
 
     private LinkedHashMap<String, RankService> strategyMap;
 
+    private static final String relevantRank = "relevant";
     private static final Map<String, Class<? extends RankService>> STRATEGY_CLASSES = new HashMap<>();
 
     static {
@@ -30,6 +31,7 @@ public class RankRouter {
         STRATEGY_CLASSES.put("567", RankStrategy4RegionMergeModelV567.class);
         STRATEGY_CLASSES.put("569", RankStrategy4RegionMergeModelV569.class);
         STRATEGY_CLASSES.put("568", RankStrategy4RegionMergeModelV568.class);
+        STRATEGY_CLASSES.put(relevantRank, RankStrategy4RelevantModelV1.class);
     }
 
     @Autowired
@@ -45,6 +47,10 @@ public class RankRouter {
     }
 
     public RankResult rank(RankParam param) {
+        if (2 == param.getRecommendType() && strategyMap.containsKey(relevantRank)) {
+            return strategyMap.get(relevantRank).rank(param);
+        }
+
         Set<String> abExpCodes = param.getAbExpCodes();
         if (CollectionUtils.isNotEmpty(abExpCodes)) {
             for (Map.Entry<String, RankService> entry : strategyMap.entrySet()) {

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

@@ -12,7 +12,6 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
@@ -38,6 +37,12 @@ public abstract class RankService {
             return null;
         }
 
+        if (2 == param.getRecommendType()) {
+            tagDuplicateVideos(param);
+            List<Video> rovRecallRank = mergeAndRankRovRecall(param);
+            return new RankResult(rovRecallRank);
+        }
+
         if (param.isSpecialRecommend()) {
             Optional<RecallResult.RecallData> data = param.getRecallResult().getData().stream()
                     .filter(d -> d.getPushFrom().equals(SpecialRecallStrategy.PUSH_FROM))
@@ -245,7 +250,7 @@ public abstract class RankService {
         }
     }
 
-    public abstract RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank,List<Video> douHotFlowPoolRank);
+    public abstract RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank, List<Video> douHotFlowPoolRank);
 
     private boolean matchSpecialApp(int appId) {
         Set<Integer> notSpecialApp = new HashSet<>(Arrays.asList(0, 4, 5));

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

@@ -0,0 +1,175 @@
+package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
+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.tansform.FeatureV6;
+import com.tzld.piaoquan.recommend.server.service.recall.strategy.HotReturnUvRecallStrategy;
+import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
+import com.tzld.piaoquan.recommend.server.util.FeatureBucketUtils;
+import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
+import com.tzld.piaoquan.recommend.server.util.RecallUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.MapUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+@Service
+@Slf4j
+public class RankStrategy4RelevantModelV1 extends RankStrategy4RegionMergeModelBasic {
+    @ApolloJsonValue("${relevant.params.v1:}")
+    private Map<String, Double> apolloParams;
+
+    @Autowired
+    private FeatureService featureService;
+
+    @Override
+    public List<Video> mergeAndRankRovRecall(RankParam param) {
+        Map<String, Double> apolloParams = this.apolloParams != null ? this.apolloParams : new HashMap<>(0);
+
+        // ------------------- 召回 -------------------
+        Set<Long> setVideo = new HashSet<>();
+        List<Video> rovRecallRank = new ArrayList<>();
+        // return uv
+        RecallUtils.extractRecall(apolloParams.getOrDefault("returnUv", 100d).intValue(), param, HotReturnUvRecallStrategy.PUSH_FROM, setVideo, rovRecallRank);
+
+        // ------------------- 排序 -------------------
+        Map<String, String> rtFeatureDumpsMap = dumpsRtFeature(param.getUserRTShareList());
+
+        // 1. 批量获取特征
+        List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
+        String requestId = String.valueOf(param.getRequestVideoId());
+        Map<String, Map<String, Map<String, String>>> videoBaseInfoMap = featureService.getVideoBaseInfo(requestId, vids);
+        Map<String, String> requestVideoInfo = videoBaseInfoMap.getOrDefault(requestId, new HashMap<>()).getOrDefault("alg_vid_feature_basic_info", new HashMap<>());
+        String requestTitle = FeatureUtils.extractContent(requestVideoInfo.get("title"));
+        if (requestTitle.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // 2. 特征处理
+        int batchSize = apolloParams.getOrDefault("batchSize", 10d).intValue();
+        long timeout = apolloParams.getOrDefault("timeout", 1000d).longValue();
+        List<RankItem> rankItems = CommonCollectionUtils.toList(rovRecallRank, RankItem::new);
+        parallelGetVideoFeature(requestVideoInfo, videoBaseInfoMap, rankItems, batchSize, timeout);
+        Map<String, Map<String, String>> vid2MapFeature = this.getVideoRedisFeature(vids, "feature_video_relevant:");
+
+        // 3. 排序公式特征
+        double minTitleSim = apolloParams.getOrDefault("minTitle", 0.2);
+        double maxTitleSim = apolloParams.getOrDefault("maxTitle", 0.85);
+        double titleWeight = apolloParams.getOrDefault("titleWeight", 0.5);
+        double kwWeight = apolloParams.getOrDefault("kwWeight", 0.2);
+        double cate1Weight = apolloParams.getOrDefault("cate1Weight", 0.1);
+        double cate2Weight = apolloParams.getOrDefault("cate2Weight", 0.1);
+        double rovnWeight = apolloParams.getOrDefault("rovnWeight", 0.1);
+        List<Video> result = new ArrayList<>();
+        for (RankItem item : rankItems) {
+            String title = item.getTitle();
+            if (null != title && title.equals(requestTitle)) {
+                continue;
+            }
+
+            double score;
+            Map<String, Float> featureMap = item.getFeatureMap() != null ? item.getFeatureMap() : new HashMap<>(0);
+            double titleSim = featureMap.getOrDefault("sim@title", 0f);
+            double kwSim = featureMap.getOrDefault("sim@keywords", 0f);
+            double cate1Sim = featureMap.getOrDefault("sim@merge_first_level_cate", 0f);
+            double cate2Sim = featureMap.getOrDefault("sim@merge_second_level_cate", 0f);
+            double rovn24h = Double.parseDouble(vid2MapFeature.getOrDefault(item.getVideoId() + "", new HashMap<>()).getOrDefault("rovn", "0"));
+            if (titleSim < minTitleSim || titleSim > maxTitleSim) {
+                continue;
+            }
+            item.getScoresMap().put("titleSim", titleSim);
+            item.getScoresMap().put("kwSim", kwSim);
+            item.getScoresMap().put("cate1Sim", cate1Sim);
+            item.getScoresMap().put("cate2Sim", cate2Sim);
+            item.getScoresMap().put("rovn", rovn24h);
+
+            score = titleWeight * titleSim
+                    + kwWeight * (kwSim + 0.05)
+                    + cate1Weight * (cate1Sim + 0.05)
+                    + cate2Weight * (cate2Sim + 0.05)
+                    + rovnWeight * rovn24h * 5;
+
+            Video video = item.getVideo();
+            video.setScore(score);
+            video.setSortScore(score);
+            video.setScoresMap(item.getScoresMap());
+            if (MapUtils.isNotEmpty(videoBaseInfoMap) && MapUtils.isNotEmpty(videoBaseInfoMap.get(item.getVideoId() + ""))) {
+                video.getMetaFeatureMap().putAll(videoBaseInfoMap.get(item.getVideoId() + ""));
+            }
+            if (MapUtils.isNotEmpty(requestVideoInfo)) {
+                video.getMetaFeatureMap().put("req_video", requestVideoInfo);
+            }
+            if (null != rtFeatureDumpsMap && !rtFeatureDumpsMap.isEmpty()) {
+                video.getMetaFeatureMap().put("rt", rtFeatureDumpsMap);
+            }
+            result.add(video);
+        }
+        result.sort(Comparator.comparingDouble(o -> -o.getSortScore()));
+        return result;
+    }
+
+    private Map<String, Float> getVideoFeature(Map<String, String> requestInfo, Map<String, String> rankInfo) {
+        Map<String, Double> featMap = new HashMap<>();
+        FeatureV6.getRequestRankVideoCrossFeature(requestInfo, rankInfo, featMap);
+        return FeatureBucketUtils.noBucketFeature(featMap);
+    }
+
+    private void batchGetVideoFeature(Map<String, String> requestInfo,
+                                      Map<String, Map<String, Map<String, String>>> videoBaseInfoMap,
+                                      List<RankItem> rankItems) {
+        if (null == rankItems || rankItems.isEmpty()) {
+            return;
+        }
+        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<>());
+            item.featureMap = getVideoFeature(requestInfo, rankInfo);
+            item.setTitle(FeatureUtils.extractContent(rankInfo.get("title")));
+        }
+    }
+
+    private void parallelGetVideoFeature(Map<String, String> requestInfo,
+                                         Map<String, Map<String, Map<String, String>>> videoBaseInfoMap,
+                                         List<RankItem> rankItems,
+                                         int batchSize,
+                                         long timeout) {
+        if (null == rankItems || rankItems.isEmpty()) {
+            return;
+        }
+        List<Future<Integer>> futures = new ArrayList<>();
+        LinkedList<List<RankItem>> batchList = CommonCollectionUtils.splitListToBatch(rankItems, batchSize);
+        for (List<RankItem> batch : batchList) {
+            Future<Integer> future = ThreadPoolFactory.defaultPool().submit(() -> {
+                batchGetVideoFeature(requestInfo, videoBaseInfoMap, batch);
+                return 1;
+            });
+            futures.add(future);
+        }
+
+        try {
+            for (Future<Integer> future : futures) {
+                future.get(timeout, TimeUnit.MILLISECONDS);
+            }
+        } catch (Exception e) {
+            log.error("get feature error", e);
+        }
+        // 超时后取消
+        for (Future<Integer> future : futures) {
+            try {
+                if (!future.isDone()) {
+                    future.cancel(true);
+                }
+            } catch (Exception e) {
+                log.error("cancel feature error", e);
+            }
+        }
+    }
+}

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

@@ -32,6 +32,7 @@ public class FeatureV6 {
     private static final List<String> videoCateAttrs = Arrays.asList(FeatureUtils.cate1Attr, FeatureUtils.cate2Attr, FeatureUtils.festive1Attr,
             FeatureUtils.channelAttr, FeatureUtils.sourceAttr, FeatureUtils.uidAttr, FeatureUtils.mergeCate1Attr, FeatureUtils.mergeCate2Attr);
     private static final List<String> videoSimAttrs = Arrays.asList("title", "cate2", "cate2_list", "keywords");
+    private static final List<String> reqVideoSimAttrs = Arrays.asList("title", "keywords", "merge_first_level_cate", "merge_second_level_cate");
     private static final List<String> hVideoSimAttrs = Arrays.asList("title");
     private static final List<String> cfList = Arrays.asList("share", "return");
     private static final List<String> userAttrList = Arrays.asList("province", "city", "model", "brand", "system", "user_channel", "user_level");
@@ -207,6 +208,10 @@ public class FeatureV6 {
         getTwoVideoCrossFeature("hr_sim", videoSimAttrs, headInfo, rankInfo, featMap);
     }
 
+    public static void getRequestRankVideoCrossFeature(Map<String, String> headInfo, Map<String, String> rankInfo, Map<String, Double> featMap) {
+        getTwoVideoCrossFeature("sim", reqVideoSimAttrs, headInfo, rankInfo, featMap);
+    }
+
     public static void getProfileVideoCrossFeature(long currentMs, UserShareReturnProfile profile, Map<String, String> rankVideo, Map<String, Map<String, String>> hVideoMap, Map<String, Double> featMap) {
         if (null == profile) {
             return;

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

@@ -43,4 +43,7 @@ public class RecallParam {
 
     private String rootSessionId;
     private List<UserSRBO> userRTShareList;
+    private int recommendType;
+    private Long requestVideoId;
+    private String currentPageSource;
 }

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

@@ -84,6 +84,10 @@ public class RecallService implements ApplicationContextAware {
 
     private List<RecallStrategy> getRecallStrategy(RecallParam param) {
         List<RecallStrategy> strategies = new ArrayList<>();
+        if (2 == param.getRecommendType()) {
+            strategies.add(strategyMap.get(HotReturnUvRecallStrategy.class.getSimpleName()));
+            return strategies;
+        }
         if (param.isSpecialRecommend()) {
             strategies.add(strategyMap.get(SpecialRecallStrategy.class.getSimpleName()));
             return strategies;

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

@@ -0,0 +1,103 @@
+package com.tzld.piaoquan.recommend.server.service.recall.strategy;
+
+import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
+import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class HotReturnUvRecallStrategy implements RecallStrategy {
+    private final String CLASS_NAME = this.getClass().getSimpleName();
+    @Autowired
+    private FilterService filterService;
+    @Autowired
+    @Qualifier("redisTemplate")
+    public RedisTemplate<String, String> redisTemplate;
+
+    public static final String PUSH_FROM = "hot_return_uv";
+    public static final String redisKey = "hot_return_uv_recall:all";
+
+    @Override
+    public String pushFrom() {
+        return PUSH_FROM;
+    }
+
+    @Override
+    public List<Video> recall(RecallParam param) {
+        List<Video> videosResult = new ArrayList<>();
+        try {
+            String redisValue = redisTemplate.opsForValue().get(redisKey);
+            if (null == redisValue || redisValue.isEmpty()) {
+                return videosResult;
+            }
+            Set<Long> invalidIds = new HashSet<>();
+            invalidIds.add(param.getVideoId());
+            invalidIds.add(param.getRequestVideoId());
+            Pair<List<Long>, Map<Long, Double>> pair = parsePair(redisValue, invalidIds, 200);
+            fillVideoResult(param, pair, videosResult);
+        } catch (Exception e) {
+            log.error("recall is wrong in {}, error={}", CLASS_NAME, e);
+        }
+        return videosResult;
+    }
+
+    private Pair<List<Long>, Map<Long, Double>> parsePair(String data, Set<Long> invalidIds, int size) {
+        List<Long> idsList = new ArrayList<>();
+        Map<Long, Double> scoresMap = new HashMap<>();
+        if (!StringUtils.isBlank(data)) {
+            String[] cells = data.split("\t");
+            if (2 == cells.length) {
+                List<Long> ids = Arrays.stream(cells[0].split(",")).map(Long::valueOf).collect(Collectors.toList());
+                List<Double> scores = Arrays.stream(cells[1].split(",")).map(Double::valueOf).collect(Collectors.toList());
+                if (!ids.isEmpty() && ids.size() == scores.size()) {
+                    int minSize = Math.min(size, ids.size());
+                    for (int i = 0; i < minSize; ++i) {
+                        long id = ids.get(i);
+                        double score = scores.get(i);
+                        if (!invalidIds.contains(id) && !scoresMap.containsKey(id)) {
+                            idsList.add(id);
+                            scoresMap.put(id, score);
+                        }
+                    }
+                }
+            }
+        }
+        return new MutablePair<>(idsList, scoresMap);
+    }
+
+    private void fillVideoResult(RecallParam param, Pair<List<Long>, Map<Long, Double>> pair, List<Video> videosResult) {
+        if (null != pair) {
+            List<Long> ids = pair.getLeft();
+            Map<Long, Double> scoresMap = pair.getRight();
+            if (null != ids && null != scoresMap && !ids.isEmpty()) {
+                FilterParam filterParam = FilterParamFactory.create(param, ids);
+                FilterResult filterResult = filterService.filter(filterParam);
+                if (null != filterResult && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
+                    filterResult.getVideoIds().forEach(vid -> {
+                        Video video = new Video();
+                        video.setVideoId(vid);
+                        video.setRovScore(scoresMap.getOrDefault(vid, 0D));
+                        video.setPushFrom(pushFrom());
+                        videosResult.add(video);
+                    });
+                }
+            }
+        }
+    }
+}

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

@@ -56,4 +56,22 @@ public class CommonCollectionUtils {
         }
         return col.contains(ele);
     }
+
+    public static <T> LinkedList<List<T>> splitListToBatch(List<T> TList, int batchSize) {
+        int index = 0;
+        List<T> subList = new ArrayList<>(batchSize);
+        LinkedList<List<T>> batchList = new LinkedList<>();
+        for (T t : TList) {
+            if (0 == index) {
+                batchList.add(subList);
+            }
+            subList.add(t);
+            index++;
+            if (index == batchSize) {
+                subList = new ArrayList<>(batchSize);
+                index = 0;
+            }
+        }
+        return batchList;
+    }
 }

+ 24 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/FeatureUtils.java

@@ -145,4 +145,28 @@ public class FeatureUtils {
         }
         return "";
     }
+
+    public static String extractContent(String data) {
+        StringBuilder result = new StringBuilder();
+        if (null != data) {
+            for (char c : data.toCharArray()) {
+                if (isChinese(c) || isDigit(c) || isLetter(c)) {
+                    result.append(c);
+                }
+            }
+        }
+        return result.toString();
+    }
+
+    private static boolean isChinese(char c) {
+        return c >= 0x4E00 && c <= 0x9FA5;
+    }
+
+    private static boolean isDigit(char c) {
+        return c >= '0' && c <= '9';
+    }
+
+    private static boolean isLetter(char c) {
+        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+    }
 }

+ 12 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/web/RecommendV2Controller.java

@@ -48,4 +48,16 @@ public class RecommendV2Controller {
         return result;
     }
 
+    @RequestMapping("/immerse/recommend/v2")
+    public String immerseRecommend(@RequestBody RecommendRequest httpRequest) {
+        MDC.put("appType", String.valueOf(httpRequest.getAppType()));
+        RecommendResponse response = recommendService.immerseRecommend(httpRequest);
+        String result = "";
+        try {
+            result = ProtobufUtils.toJson(response);
+        } catch (InvalidProtocolBufferException e) {
+            log.error("immerseRecommend ProtobufUtils.toJson", e);
+        }
+        return result;
+    }
 }