Procházet zdrojové kódy

ad feature to main

sunmingze před 1 rokem
rodič
revize
25b3be4651
37 změnil soubory, kde provedl 6307 přidání a 248 odebrání
  1. 1 1
      recommend-feature-client/pom.xml
  2. 2 2
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/client/FeatureClient.java
  3. 0 110
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/UserActionFeature.java
  4. 16 18
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/ItemFeature.java
  5. 13 13
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/RequestContext.java
  6. 1 1
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/RequestContextBytesFeature.java
  7. 180 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/UserActionFeature.java
  8. 1 1
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/UserBytesFeature.java
  9. 14 6
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/UserFeature.java
  10. 3 3
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/VideoBytesFeature.java
  11. 130 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/enums/VlogFeatureGroup.java
  12. 35 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/BytesGroup.java
  13. 191 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/BytesUtils.java
  14. 230 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/FeatureHash.java
  15. 66 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/LRBytesFeatureExtractorBase.java
  16. 156 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/VlogShareLRFeatureExtractor.java
  17. 2 2
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/feature/Feature.java
  18. 48 48
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/feature/GetUserFeatureRequest.java
  19. 6 6
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/feature/GetUserFeatureRequestOrBuilder.java
  20. 819 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/BaseFeature.java
  21. 45 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/BaseFeatureOrBuilder.java
  22. 104 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/CtrSamples.java
  23. 897 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/FeatureGroup.java
  24. 51 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/FeatureGroupOrBuilder.java
  25. 1022 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/GroupedFeature.java
  26. 54 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/GroupedFeatureOrBuilder.java
  27. 1094 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRSamples.java
  28. 63 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRSamplesOrBuilder.java
  29. 834 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRWeight.java
  30. 39 0
      recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRWeightOrBuilder.java
  31. 49 0
      recommend-feature-client/src/main/proto/com/tzld/piaoquan/recommend/feature/ctr_samples.proto
  32. 1 1
      recommend-feature-client/src/main/proto/com/tzld/piaoquan/recommend/feature/feature.proto
  33. 110 14
      recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/model/AdItemFeature.java
  34. 22 15
      recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/model/UserFeature.java
  35. 4 3
      recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/service/FeatureConverter.java
  36. 3 3
      recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/service/UserFeatureService.java
  37. 1 1
      recommend-feature-service/src/main/resources/application-dev.yml

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

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

+ 2 - 2
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/client/FeatureClient.java

@@ -17,9 +17,9 @@ public class FeatureClient {
     @GrpcClient("recommend-feature")
     private FeatureServiceGrpc.FeatureServiceBlockingStub client;
 
-    public UserFeatureProto getUserFeature(String uid) {
+    public UserFeatureProto getUserFeature(String mid) {
         GetUserFeatureRequest request = GetUserFeatureRequest.newBuilder()
-                .setUid(uid)
+                .setMid(mid)
                 .build();
         GetUserFeatureResponse response = client.getUserFeature(request);
         if (response == null || !response.hasResult()) {

+ 0 - 110
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/UserActionFeature.java

@@ -1,110 +0,0 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
-
-import lombok.Data;
-
-import java.lang.Math;
-
-@Data
-public class UserActionFeature {
-    private double exp_cnt;
-    private double click_cnt;
-    private double share_cnt;
-    private double return_cnt;
-
-    private double ctr;
-    private double str;
-    private double rov;
-    private double ros;
-
-    private double ceilLog(Double key) {
-        return Math.ceil(Math.log(key));
-    }
-
-    private double bucketRatioFeature(Double key) {
-        long bucket = Math.round(Math.log(key * 100));
-        if( bucket > 100)
-            bucket = 100;
-        return (double) bucket;
-    }
-
-
-    public void setExp_cnt(Object key){
-        if(key == null ) {
-            this.exp_cnt = 0.0;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.exp_cnt = ceilLog(Double.valueOf(formateKey));
-        }
-    }
-
-    public void setClick_cnt(Object key){
-        if(key == null ){
-            this.click_cnt = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.click_cnt = ceilLog(Double.valueOf(formateKey));
-        }
-    }
-    public void setShare_cnt(Object key){
-        if(key == null ){
-            this.share_cnt = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.share_cnt = ceilLog(Double.valueOf(formateKey));
-        }
-    }
-    public void setReturn_cnt(Object key){
-        if(key == null ){
-            this.return_cnt = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.return_cnt = ceilLog(Double.valueOf(formateKey));
-        }
-    }
-
-    public void setCtr(Object key){
-        if(key == null ){
-            this.ctr = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.ctr = bucketRatioFeature(Double.valueOf(formateKey));
-        }
-    }
-
-    public void setStr(Object key){
-        if(key == null ){
-            this.str = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.str = bucketRatioFeature(Double.valueOf(formateKey));
-        }
-    }
-
-    public void setRov(Object key){
-        if(key == null ){
-            this.rov = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.rov = bucketRatioFeature(Double.valueOf(formateKey));
-        }
-    }
-
-    public void setRos(Object key){
-        if(key == null ){
-            this.ros = 0.0 ;
-        } else {
-            String formateKey = key.toString().replace("\\N", "-1");
-            this.ros = bucketRatioFeature(Double.valueOf(formateKey));
-        }
-    }
-
-
-
-
-
-
-
-
-
-
-}

+ 16 - 18
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/ItemFeature.java → recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/ItemFeature.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -8,27 +8,26 @@ import lombok.NoArgsConstructor;
 @Getter
 @NoArgsConstructor
 public class ItemFeature {
-    private String videoId;
+    private String videoId = "0";
 
-    private String upId;
+    private String upId = "0";
 
-    private String tags;
+    private String tags = "0";
 
     /**
      * 有多个标题,暂时不会用到所以先不处理
      *
      * @since 2023-12-05
      */
-    private String title;
+    private String title = "0";
 
-    private String titleLength;
+    // private String titleLength = "0";
 
-    private String playLength;
+    private String playLength = "0";
 
-    private String totalTime;
-
-    private String daysSinceUpload;
+    private String totalTime = "0";
 
+    private String daysSinceUpload = "0";
 
     // 当天统计量信息
     private UserActionFeature day1_cnt_features;
@@ -93,13 +92,13 @@ public class ItemFeature {
 
     }
 
-    public void setTitleLength(String key) {
-        if (key == null) {
-            this.titleLength = "0";
-        } else {
-            this.titleLength = key;
-        }
-    }
+//    public void setTitleLength(String key) {
+//        if (key == null) {
+//            this.titleLength = "0";
+//        } else {
+//            this.titleLength = key;
+//        }
+//    }
 
 
     public void setDaysSinceUpload(String key) {
@@ -145,7 +144,6 @@ public class ItemFeature {
         feature.setPlayLength(null);
         feature.setTags(null);
         feature.setTitle(null);
-        feature.setTitleLength(null);
         feature.setTotalTime(null);
         feature.setUpId(null);
         feature.setVideoId(videoId);

+ 13 - 13
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/RequestContext.java → recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/RequestContext.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
 
 
 import lombok.Getter;
@@ -10,20 +10,20 @@ public class RequestContext {
 
     private String request_id;
     // 机型等信息
-    private String apptype;
-    private String machineinfo_brand;
-    private String machineinfo_model;
-    private String machineinfo_platform;
-    private String machineinfo_sdkversion;
-    private String machineinfo_system;
-    private String machineinfo_wechatversion;
+    private String apptype = "-1";
+    private String machineinfo_brand = "-1";
+    private String machineinfo_model = "-1";
+    private String machineinfo_platform = "-1";
+    private String machineinfo_sdkversion = "-1";
+    private String machineinfo_system = "-1";
+    private String machineinfo_wechatversion = "-1";
 
     // 时间等信息
-    private String day;
-    private String week;
-    private String hour;
-    private String region;
-    private String city;
+    private String day = "-1";
+    private String week = "-1";
+    private String hour = "-1";
+    private String region = "-1";
+    private String city = "-1";
 
     public void setApptype(String apptype) {
         this.apptype = apptype;

+ 1 - 1
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/RequestContextBytesFeature.java → recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/RequestContextBytesFeature.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
 
 
 import lombok.Data;

+ 180 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/UserActionFeature.java

@@ -0,0 +1,180 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
+
+import lombok.Data;
+
+import java.lang.Math;
+
+@Data
+public class UserActionFeature {
+    private double exp_cnt = 0d;
+    private double click_cnt = 0d;
+    private double share_cnt = 0d;
+    private double return_cnt = 0d;
+
+    private double ctr = 0d;
+    private double str = 0d;
+    private double rov = 0d;
+    private double ros = 0d;
+
+    private double ceilLog(Double key) {
+        return Math.ceil(Math.log(key + 1));
+    }
+
+    private double bucketRatioFeature(Double key) {
+        long bucket = Math.round(Math.log((key + 1) * 50));
+        if (bucket > 50)
+            bucket = 50;
+        return (double) bucket;
+    }
+
+
+    public void setExp_cnt(Object key) {
+        if (key == null) {
+            this.exp_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.exp_cnt = ceilLog(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setClick_cnt(Object key) {
+        if (key == null) {
+            this.click_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.click_cnt = ceilLog(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setShare_cnt(Object key) {
+        if (key == null) {
+            this.share_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.share_cnt = ceilLog(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setReturn_cnt(Object key) {
+        if (key == null) {
+            this.return_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.return_cnt = ceilLog(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setCtr(Object key) {
+        if (key == null) {
+            this.ctr = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.ctr = bucketRatioFeature(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setStr(Object key) {
+        if (key == null) {
+            this.str = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.str = bucketRatioFeature(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setRov(Object key) {
+        if (key == null) {
+            this.rov = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.rov = bucketRatioFeature(Double.valueOf(formateKey));
+        }
+    }
+
+    public void setRos(Object key) {
+        if (key == null) {
+            this.ros = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "-1");
+            this.ros = bucketRatioFeature(Double.valueOf(formateKey));
+        }
+    }
+
+
+    public void setOriginExp_cnt(Object key) {
+        if (key == null) {
+            this.exp_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.exp_cnt = Double.valueOf(formateKey);
+        }
+    }
+
+    public void setOriginClick_cnt(Object key) {
+        if (key == null) {
+            this.click_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.click_cnt = Double.valueOf(formateKey);
+        }
+    }
+
+    public void setOriginShare_cnt(Object key) {
+        if (key == null) {
+            this.share_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.share_cnt = Double.valueOf(formateKey);
+        }
+    }
+
+    // redis中保存原始值  server段统一处理
+    public void setOriginReturn_cnt(Object key) {
+        if (key == null) {
+            this.return_cnt = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.return_cnt = Double.valueOf(formateKey);
+        }
+    }
+
+    public void setOriginCtr(Object key) {
+        if (key == null) {
+            this.ctr = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.ctr = Double.valueOf(formateKey);
+        }
+    }
+
+
+    public void setOriginStr(Object key) {
+        if (key == null) {
+            this.str = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.str = Double.valueOf(formateKey);
+        }
+    }
+
+    public void setOriginRov(Object key) {
+        if (key == null) {
+            this.rov = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.rov = Double.valueOf(formateKey);
+        }
+    }
+
+
+    public void setOriginRos(Object key) {
+        if (key == null) {
+            this.ros = 0.0;
+        } else {
+            String formateKey = key.toString().replace("\\N", "0");
+            this.ros = Double.valueOf(formateKey);
+        }
+    }
+
+
+}

+ 1 - 1
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/UserBytesFeature.java → recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/UserBytesFeature.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
 
 import lombok.Data;
 

+ 14 - 6
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/UserFeature.java → recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/UserFeature.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -9,7 +9,8 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor
 public class UserFeature {
 
-    private String uid;
+    private String uid = "0";
+    private String mid = "0";
     // 当天统计量信息
     private UserActionFeature day1_cnt_features;
     // 3天内统计量
@@ -19,9 +20,9 @@ public class UserFeature {
     // 3个月统计量
     private UserActionFeature month3_cnt_features;
     // 用户行为周期
-    private String user_cycle_bucket_7days;
-    private String user_cycle_bucket_30days;
-    private String user_share_bucket_30days;
+    private String user_cycle_bucket_7days = "0";
+    private String user_cycle_bucket_30days = "0";
+    private String user_share_bucket_30days = "0";
 
     public void setUid(String key) {
         this.uid = key;
@@ -29,6 +30,13 @@ public class UserFeature {
             this.uid = "0";
     }
 
+    public void setMid(String key) {
+        this.uid = key;
+        if (key == null)
+            this.uid = "0";
+    }
+
+
 
     public void setDay1_cnt_features(UserActionFeature key) {
         this.day1_cnt_features = key;
@@ -75,7 +83,7 @@ public class UserFeature {
 
 
     public String getKey() {
-        return this.uid;
+        return this.mid;
     }
 
     public String getValue() {

+ 3 - 3
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/VideoBytesFeature.java → recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/base/VideoBytesFeature.java

@@ -1,4 +1,4 @@
-package com.tzld.piaoquan.recommend.feature.domain.video;
+package com.tzld.piaoquan.recommend.feature.domain.video.base;
 
 import lombok.Data;
 
@@ -11,7 +11,7 @@ public class VideoBytesFeature {
 
     private final byte[] upId;
 
-    private final byte[] titleLength;
+    // private final byte[] titleLength;
 
     private final byte[] playLength;
 
@@ -33,7 +33,7 @@ public class VideoBytesFeature {
         videoId = feature.getVideoId().getBytes();
         upId = feature.getUpId().getBytes();
 
-        titleLength = feature.getTitleLength().getBytes();
+        // titleLength = feature.getTitleLength().getBytes();
         playLength = feature.getPlayLength().getBytes();
         totolTime = feature.getTotalTime().getBytes();
         daysSinceUpload = feature.getDaysSinceUpload().getBytes();

+ 130 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/enums/VlogFeatureGroup.java

@@ -0,0 +1,130 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.enums;
+
+public enum VlogFeatureGroup {
+
+    // video
+    APPTYP,
+    VIDEOID,
+    MID,
+    UID,
+    MACHINEINFO_BRAND,
+    MACHINEINFO_MODEL,
+    MACHINEINFO_PLATFORM,
+    MACHINEINFO_SDKVERSION,
+    MACHINEINFO_SYSTEM,
+    MACHINEINFO_WECHATVERSION,
+    UP_ID,
+    PLAY_LEN,
+    TOTAL_TIME,
+    DAYS_SINCE_UPLOAD,
+    DAY,
+    WEEK,
+    HOUR,
+    REGION,
+    CITY,
+
+    USER_1DAY_EXP,
+    USER_1DAY_CLICK,
+    USER_1DAY_SHARE,
+    USER_1DAY_RETURN,
+    USER_1DAY_CTR,
+    USER_1DAY_STR,
+    USER_1DAY_ROV,
+    USER_1DAY_ROS,
+
+    USER_3DAY_EXP,
+    USER_3DAY_CLICK,
+    USER_3DAY_SHARE,
+    USER_3DAY_RETURN,
+    USER_3DAY_CTR,
+    USER_3DAY_STR,
+    USER_3DAY_ROV,
+    USER_3DAY_ROS,
+
+    USER_7DAY_EXP,
+    USER_7DAY_CLICK,
+    USER_7DAY_SHARE,
+    USER_7DAY_RETURN,
+    USER_7DAY_CTR,
+    USER_7DAY_STR,
+    USER_7DAY_ROV,
+    USER_7DAY_ROS,
+
+    USER_3MONTH_EXP,
+    USER_3MONTH_CLICK,
+    USER_3MONTH_SHARE,
+    USER_3MONTH_RETURN,
+    USER_3MONTH_CTR,
+    USER_3MONTH_STR,
+    USER_3MONTH_ROV,
+    USER_3MONTH_ROS,
+
+
+    ITEM_1DAY_EXP,
+    ITEM_1DAY_CLICK,
+    ITEM_1DAY_SHARE,
+    ITEM_1DAY_RETURN,
+    ITEM_1DAY_CTR,
+    ITEM_1DAY_STR,
+    ITEM_1DAY_ROV,
+    ITEM_1DAY_ROS,
+
+    ITEM_3DAY_EXP,
+    ITEM_3DAY_CLICK,
+    ITEM_3DAY_SHARE,
+    ITEM_3DAY_RETURN,
+    ITEM_3DAY_CTR,
+    ITEM_3DAY_STR,
+    ITEM_3DAY_ROV,
+    ITEM_3DAY_ROS,
+
+    ITEM_7DAY_EXP,
+    ITEM_7DAY_CLICK,
+    ITEM_7DAY_SHARE,
+    ITEM_7DAY_RETURN,
+    ITEM_7DAY_CTR,
+    ITEM_7DAY_STR,
+    ITEM_7DAY_ROV,
+    ITEM_7DAY_ROS,
+
+    ITEM_3MONTH_EXP,
+    ITEM_3MONTH_CLICK,
+    ITEM_3MONTH_SHARE,
+    ITEM_3MONTH_RETURN,
+    ITEM_3MONTH_CTR,
+    ITEM_3MONTH_STR,
+    ITEM_3MONTH_ROV,
+    ITEM_3MONTH_ROS,
+
+
+    USER_CYCLE_BUCKET_7DAY,
+    USER_CYCLE_BUCKET_30DAY,
+    USER_SHARE_BUCKET_30DAY,
+    ;
+
+
+    private final byte[] idBytes;
+    private final byte[] nameBytes;
+
+    VlogFeatureGroup() {
+        this.nameBytes = name().toLowerCase().getBytes();
+        this.idBytes = String.valueOf(ordinal()).getBytes();
+    }
+
+    public final int getId() {
+        return ordinal();
+    }
+
+    public final String getGroupName() {
+        return name().toLowerCase();
+    }
+
+    public final byte[] getGroupNameBytes() {
+        return getGroupName().getBytes();
+    }
+
+    public final byte[] getIdBytes() {
+        return idBytes;
+    }
+
+}

+ 35 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/BytesGroup.java

@@ -0,0 +1,35 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.feature;
+
+
+public class BytesGroup {
+    private int id;
+    private String name;
+    private byte[] nameBytes;
+    private byte[] buffer;
+
+    public BytesGroup(int id, String name, byte[] nameBytes) {
+        this.id = id;
+        this.name = name;
+        this.nameBytes = nameBytes;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public byte[] getNameBytes() {
+        return nameBytes;
+    }
+
+    public byte[] getBuffer() {
+        return buffer;
+    }
+
+    public void setBuffer(byte[] buffer) {
+        this.buffer = buffer;
+    }
+}

+ 191 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/BytesUtils.java

@@ -0,0 +1,191 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.feature;
+
+
+import com.tzld.piaoquan.recommend.feature.model.sample.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Extract features from user, item & context info. Returns 64-bit murmurhash of feature string as results.
+ */
+public class BytesUtils {
+    private static final byte[] SEPARATOR = "_".getBytes();
+    private static final byte[] FEATURE_SEPARATOR = "#".getBytes();
+    private static final int MAX_FEATURE_BYTES_LENGTH = 512;
+    private static final long SEED = 11L;
+    private BytesGroup[] groups;
+
+    /**
+     * 一个种特殊的List,在尝试写入null的时候回默默地扔掉.
+     * @param <E> List的元素类型.
+     */
+    public static class NullRejectingArrayList<E> extends ArrayList<E> {
+        public NullRejectingArrayList(int capacity) {
+            super(capacity);
+        }
+
+        public NullRejectingArrayList() {
+            super();
+        }
+
+        @Override
+        public boolean add(E e) {
+            return e != null && super.add(e);
+        }
+    }
+
+    public BytesUtils(BytesGroup[] groups) {
+        this.groups = groups;
+        for (BytesGroup g : groups) {
+            byte[] buffer = prepareBuffer(g.getName(), g.getNameBytes());
+            groups[g.getId()].setBuffer(buffer);
+        }
+    }
+
+    public byte[] prepareBuffer(String name, byte[] nameBytes) {
+
+        byte[] buffer = new byte[MAX_FEATURE_BYTES_LENGTH];
+        System.arraycopy(nameBytes, 0, buffer, 0, nameBytes.length);
+        System.arraycopy(FEATURE_SEPARATOR, 0, buffer, nameBytes.length, 1);
+        return buffer;
+    }
+
+    public BaseFeature baseFea(byte[] buffer, int length) {
+        long hash = FeatureHash.MurmurHash64(buffer, 0, length, SEED);
+
+        // debug中查看 String fea = new String(buffer, 0, length);
+        // 初始化protobuf并赋值
+        BaseFeature.Builder tmp = BaseFeature.newBuilder();
+        tmp.setIdentifier(hash);
+        return tmp.build();
+    }
+
+    public BaseFeature makeFea(int id, byte[] value) {
+        byte[] buffer = groups[id].getBuffer();
+        if (buffer == null || value == null) {
+            return null;
+        }
+
+        final int nameLength = groups[id].getNameBytes().length + 1;
+        final int length = nameLength + value.length;
+        System.arraycopy(value, 0, buffer, nameLength, value.length);
+        return baseFea(buffer, length);
+    }
+
+    public BaseFeature makeFea(int id, final byte[] p1, final byte[] p2) {
+        byte[] buffer = groups[id].getBuffer();
+        if (buffer == null || p1 == null || p2 == null) {
+            return null;
+        }
+
+        final int nameLength = groups[id].getNameBytes().length + 1;
+        final int length = nameLength + p1.length + 1 + p2.length;
+
+        System.arraycopy(p1, 0, buffer, nameLength, p1.length);
+        System.arraycopy(SEPARATOR, 0, buffer, nameLength + p1.length, 1);
+        System.arraycopy(p2, 0, buffer, nameLength + p1.length + 1, p2.length);
+        return baseFea(buffer, length);
+    }
+
+    public BaseFeature makeFea(int id, final byte[] p1, final byte[] p2, final byte[] p3) {
+        byte[] buffer = groups[id].getBuffer();
+        if (buffer == null || p1 == null || p2 == null || p3 == null) {
+            return null;
+        }
+
+        final int nameLength = groups[id].getNameBytes().length + 1;
+        final int length = nameLength + p1.length + 1 + p2.length + 1 + p3.length;
+        System.arraycopy(p1, 0, buffer, nameLength, p1.length);
+        System.arraycopy(SEPARATOR, 0, buffer, nameLength + p1.length, 1);
+        System.arraycopy(p2, 0, buffer, nameLength + p1.length + 1, p2.length);
+        System.arraycopy(SEPARATOR, 0, buffer, nameLength + p1.length + 1 + p2.length, 1);
+        System.arraycopy(p3, 0, buffer, nameLength + p1.length + 1 + p2.length + 1, p3.length);
+
+        return baseFea(buffer, length);
+    }
+
+    public BaseFeature makeFea(int id, final byte[] p1, final byte[] p2, final byte[] p3, final byte[] p4) {
+        byte[] buffer = groups[id].getBuffer();
+        if (buffer == null || p1 == null || p2 == null || p3 == null || p4 == null) {
+            return null;
+        }
+
+        final int nameLength = groups[id].getNameBytes().length + 1;
+        final int length = nameLength + p1.length + 1 + p2.length + 1 + p3.length + 1 + p4.length;
+        System.arraycopy(p1, 0, buffer, nameLength, p1.length);
+        System.arraycopy(SEPARATOR, 0, buffer, nameLength + p1.length, 1);
+        System.arraycopy(p2, 0, buffer, nameLength + p1.length + 1, p2.length);
+        System.arraycopy(SEPARATOR, 0, buffer, nameLength + p1.length + 1 + p2.length, 1);
+        System.arraycopy(p3, 0, buffer, nameLength + p1.length + 1 + p2.length + 1, p3.length);
+        System.arraycopy(SEPARATOR, 0, buffer, nameLength + p1.length + 1 + p2.length + 1 + p3.length, 1);
+        System.arraycopy(p4, 0, buffer, nameLength + p1.length + 1 + p2.length + 1 + p3.length + 1, p4.length);
+
+        return baseFea(buffer, length);
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[][] list) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(list.length);
+        for (byte[] t: list) {
+            result.add(makeFea(id, t));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[][] left, byte[] right) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(left.length);
+        for (byte[] l: left) {
+            result.add(makeFea(id, l, right));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[][] left, byte[] right1, byte[] right2) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(left.length);
+        for (byte[] l: left) {
+            result.add(makeFea(id, l, right1, right2));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[][] left, byte[] right1, byte[] right2, byte[] right3) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(left.length);
+        for (byte[] l: left) {
+            result.add(makeFea(id, l, right1, right2, right3));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[] left, byte[][] right) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(right.length);
+        for (byte[] r : right) {
+            result.add(makeFea(id, left, r));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[] left1, byte[] left2, byte[][] right) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(right.length);
+        for (byte[] r : right) {
+            result.add(makeFea(id, left1, left2, r));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[] left1, byte[] left2, byte[] left3, byte[][] right) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(right.length);
+        for (byte[] r : right) {
+            result.add(makeFea(id, left1, left2, left3, r));
+        }
+        return result;
+    }
+
+    public List<BaseFeature> makeFea(int id, byte[][] left, byte[][] right) {
+        List<BaseFeature> result = new NullRejectingArrayList<BaseFeature>(left.length * right.length);
+        for (byte[] l: left) {
+            for (byte[] r: right) {
+                result.add(makeFea(id, l, r));
+            }
+        }
+        return result;
+    }
+}

+ 230 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/FeatureHash.java

@@ -0,0 +1,230 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.feature;
+
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+public class FeatureHash {
+    public static Charset CharSetUTF8 = Charset.forName("UTF-8");
+
+    public static long getUInt32(byte a, byte b, byte c, byte d) {
+        return (d << 24 | (c & 0xFF) << 16 | (b & 0xFF) << 8 | (a & 0xFF));
+    }
+
+    public static long hash64(byte[] data) {
+        return MurmurHash64A(ByteBuffer.wrap(data), 0, data.length, 11L);
+    }
+
+    public static long MurmurHash64A(ByteBuffer buffer, int from, int len, long seed) {
+        final long m = 0xc6a4a7935bd1e995L;
+        final int r = 47;
+
+        long h = (seed) ^ (len * m);
+        int longLength = len / 8;
+
+        for (int i = 0; i < longLength; ++i) {
+            final int bytePos = from + i * 8;
+            long k = buffer.getLong(bytePos);
+
+            k *= m;
+            k ^= k >> r;
+            k *= m;
+            h ^= k;
+            h *= m;
+        }
+
+        final int remainingPos = len & ~7;
+        switch (len % 8) {
+            case 7: h ^= (long)(buffer.get(remainingPos + 6) & 0xFF) << 48;
+            case 6: h ^= (long)(buffer.get(remainingPos + 5) & 0xFF) << 40;
+            case 5: h ^= (long)(buffer.get(remainingPos + 4) & 0xFF) << 32;
+            case 4: h ^= (long)(buffer.get(remainingPos + 3) & 0xFF) << 24;
+            case 3: h ^= (long)(buffer.get(remainingPos + 2) & 0xFF) << 16;
+            case 2: h ^= (long)(buffer.get(remainingPos + 1) & 0xFF) << 8;
+            case 1:
+                h ^= (long)(buffer.get(remainingPos) & 0xFF);
+                h *= m;
+        }
+
+        h ^= h >>> r;
+        h *= m;
+        h ^= h >>> r;
+        return h;
+    }
+
+    public static long MurmurHash32(byte data[], int len, long seed) {
+        long m = 0x5bd1e995L;
+        int r = 24;
+
+        long h = seed ^ len;
+
+        int offset = 0;
+        while (len >= 4) {
+            long k = getUInt32(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
+
+            k *= m;
+            k &= 0xFFFFFFFFL;
+            k ^= k >> r;
+            k *= m;
+            k &= 0xFFFFFFFFL;
+
+            h *= m;
+            h &= 0xFFFFFFFFL;
+            h ^= k;
+
+            offset += 4;
+            len -= 4;
+        }
+
+        // Handle the last few bytes of the input array
+        switch (len) {
+            case 3: h ^= data[offset + 2] << 16;
+            case 2: h ^= data[offset + 1] << 8;
+            case 1: h ^= data[offset];
+                h *= m;
+                h &= 0xFFFFFFFFL;
+        } ;
+
+        // Do a few final mixes of the hash to ensure the last few
+        // bytes are well-incorporated.
+
+        h ^= h >> 13;
+        h *= m;
+        h &= 0xFFFFFFFFL;
+        h ^= h >> 15;
+
+        return h;
+    }
+
+    // 64-bit hash for 32-bit platforms
+    public static long MurmurHash64(byte[] buffer, int start, int len, long seed) {
+        final long m = 0x5bd1e995L;
+        final int r = 24;
+        final int original = len;
+
+        long h1 = (seed) ^ len;
+        long h2 = (seed >> 32);
+
+        int offset = start;
+        while (len >= 8) {
+            long k1 = getUInt32(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]);
+            // long k1 = buffer.getInt(offset);
+
+            k1 *= m; k1 &= 0xFFFFFFFFL; k1 ^= k1 >> r; k1 *= m; k1 &= 0xFFFFFFFFL;
+            h1 *= m; h1 &= 0xFFFFFFFFL; h1 ^= k1;
+            offset += 4;
+
+            long k2 = getUInt32(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]);
+            // long k2 = buffer.getInt(offset);
+            k2 *= m; k2 &= 0xFFFFFFFFL; k2 ^= k2 >> r; k2 *= m; k2 &= 0xFFFFFFFFL;
+            h2 *= m; h2 &= 0xFFFFFFFFL; h2 ^= k2;
+
+            offset += 4;
+            len -= 8;
+        }
+
+        if (len >= 4) {
+            long k1 = getUInt32(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]);
+            // long k1 = buffer.getInt(offset);
+            k1 *= m; k1 &= 0xFFFFFFFFL; k1 ^= k1 >> r; k1 *= m; k1 &= 0xFFFFFFFFL;
+            h1 *= m; h1 &= 0xFFFFFFFFL; h1 ^= k1;
+            offset += 4;
+            len -= 4;
+        }
+
+        switch (len) {
+            case 3: h2 ^= (buffer[offset + 2] & 0xFF) << 16;
+            case 2: h2 ^= (buffer[offset + 1] & 0xFF) << 8;
+            case 1: h2 ^= (buffer[offset] & 0xFF);
+                h2 *= m;
+                h2 &= 0xFFFFFFFFL;
+        } ;
+
+        h1 ^= h2 >> 18;
+        h1 *= m; h1 &= 0xFFFFFFFFL;
+        h2 ^= h1 >> 22;
+        h2 *= m; h2 &= 0xFFFFFFFFL;
+        h1 ^= h2 >> 17;
+        h1 *= m; h1 &= 0xFFFFFFFFL;
+        h2 ^= h1 >> 19;
+        h2 *= m; h2 &= 0xFFFFFFFFL;
+
+        /*BigInteger ans = BigInteger.valueOf(h1).shiftLeft(32).or(BigInteger.valueOf(h2));
+        return ans.longValue();*/
+        //System.err.println("feature: " + new String(buffer, 0, original) + " length: " + original + " hash: " + (h1 << 32 | h2) + " daze");
+        return h1 << 32 | h2;
+    }
+
+    // 64-bit hash for 32-bit platforms
+    public static BigInteger MurmurHash64(byte data[], int len, long seed) {
+        long m = 0x5bd1e995L;
+        int r = 24;
+
+        long h1 = (seed) ^ len;
+        long h2 = (seed >> 32);
+
+        int offset = 0;
+        while (len >= 8) {
+            long k1 = getUInt32(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
+            k1 *= m; k1 &= 0xFFFFFFFFL; k1 ^= k1 >> r; k1 *= m; k1 &= 0xFFFFFFFFL;
+            h1 *= m; h1 &= 0xFFFFFFFFL; h1 ^= k1;
+
+            long k2 = getUInt32(data[offset + 4], data[offset + 5], data[offset + 6], data[offset + 7]);
+            k2 *= m; k2 &= 0xFFFFFFFFL; k2 ^= k2 >> r; k2 *= m; k2 &= 0xFFFFFFFFL;
+            h2 *= m; h2 &= 0xFFFFFFFFL; h2 ^= k2;
+
+            offset += 8;
+            len -= 8;
+        }
+
+        if (len >= 4) {
+            long k1 = getUInt32(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
+            k1 *= m; k1 &= 0xFFFFFFFFL; k1 ^= k1 >> r; k1 *= m; k1 &= 0xFFFFFFFFL;
+            h1 *= m; h1 &= 0xFFFFFFFFL; h1 ^= k1;
+            offset += 4;
+            len -= 4;
+        }
+
+        switch (len) {
+            case 3: h2 ^= (data[offset + 2] & 0xFF) << 16;
+            case 2: h2 ^= (data[offset + 1] & 0xFF) << 8;
+            case 1: h2 ^= (data[offset] & 0xFF);
+                h2 *= m;
+                h2 &= 0xFFFFFFFFL;
+        } ;
+
+        h1 ^= h2 >> 18;
+        h1 *= m; h1 &= 0xFFFFFFFFL;
+        h2 ^= h1 >> 22;
+        h2 *= m; h2 &= 0xFFFFFFFFL;
+        h1 ^= h2 >> 17;
+        h1 *= m; h1 &= 0xFFFFFFFFL;
+        h2 ^= h1 >> 19;
+        h2 *= m; h2 &= 0xFFFFFFFFL;
+
+        BigInteger ans = BigInteger.valueOf(h1).shiftLeft(32).or(BigInteger.valueOf(h2));
+        return ans;
+    }
+
+    public static String hash(String input) {
+        byte[] tt = input.getBytes(CharSetUTF8);
+        return MurmurHash64(tt, tt.length, 11L).toString();
+    }
+
+    public static Long hashToLong(String input) {
+        byte[] tt = input.getBytes(CharSetUTF8);
+        return MurmurHash64(tt, tt.length, 11L).longValue();
+    }
+
+    /** the constant 2^64 */
+    private static final BigInteger TWO_64 = BigInteger.ONE.shiftLeft(64);
+
+    public static String asUnsignedLongString(long l) {
+        BigInteger b = BigInteger.valueOf(l);
+        if (b.signum() < 0) {
+            b = b.add(TWO_64);
+        }
+        return b.toString();
+    }
+}

+ 66 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/LRBytesFeatureExtractorBase.java

@@ -0,0 +1,66 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.feature;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+
+import com.tzld.piaoquan.recommend.feature.domain.video.base.RequestContextBytesFeature;
+import com.tzld.piaoquan.recommend.feature.domain.video.base.UserBytesFeature;
+import com.tzld.piaoquan.recommend.feature.domain.video.base.VideoBytesFeature;
+import com.tzld.piaoquan.recommend.feature.domain.video.enums.VlogFeatureGroup;
+import com.tzld.piaoquan.recommend.feature.model.sample.*;
+
+import java.util.List;
+
+
+public abstract class LRBytesFeatureExtractorBase {
+    private static final double DEFAULT_USER_CTR_GROUP = 10.0;
+    private static final double DEFAULT_ARTICLE_CTR_GROUP = 100.0;
+
+
+    private BytesUtils utils;
+    //Feature Group & Features
+    ListMultimap<FeatureGroup, BaseFeature> features = ArrayListMultimap.create();
+    int groupCount;
+
+
+    LRBytesFeatureExtractorBase() {
+        groupCount = VlogFeatureGroup.values().length;
+        BytesGroup[] groups = new BytesGroup[groupCount];
+        for (VlogFeatureGroup g: VlogFeatureGroup.values()) {
+            groups[g.ordinal()] = new BytesGroup(g.ordinal(),
+                    g.getGroupName(), g.getGroupNameBytes());
+        }
+        utils = new BytesUtils(groups);
+    }
+
+    private FeatureGroup makeGroup(VlogFeatureGroup group){
+        FeatureGroup.Builder g = FeatureGroup.newBuilder();
+        g.setType("1");
+        g.setName(group.getGroupName());
+        g.setId(group.ordinal());
+        return g.build();
+    };
+
+
+    void makeFea(VlogFeatureGroup group, byte[] value) {
+        FeatureGroup featureGroup = makeGroup(group);
+        BaseFeature feature = utils.makeFea(group.ordinal(), value);
+        features.put(featureGroup, feature);
+    }
+
+    void makeFea(VlogFeatureGroup group, byte[][] list) {
+        FeatureGroup g = makeGroup(group);
+        List<BaseFeature> featureList = utils.makeFea(group.ordinal(), list);
+        features.putAll(g, featureList);
+    }
+
+    public ListMultimap<FeatureGroup, BaseFeature> getFeatures() {
+        return features;
+    }
+
+    public abstract LRSamples single(UserBytesFeature userBytesFeature,
+                                     VideoBytesFeature videoBytesFeature,
+                                     RequestContextBytesFeature requestContextBytesFeature);
+
+
+}

+ 156 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/domain/video/feature/VlogShareLRFeatureExtractor.java

@@ -0,0 +1,156 @@
+package com.tzld.piaoquan.recommend.feature.domain.video.feature;
+
+import com.tzld.piaoquan.recommend.feature.domain.video.base.RequestContextBytesFeature;
+import com.tzld.piaoquan.recommend.feature.domain.video.base.UserBytesFeature;
+import com.tzld.piaoquan.recommend.feature.domain.video.base.VideoBytesFeature;
+import com.tzld.piaoquan.recommend.feature.domain.video.enums.VlogFeatureGroup;
+import com.tzld.piaoquan.recommend.feature.model.sample.*;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class VlogShareLRFeatureExtractor extends LRBytesFeatureExtractorBase {
+
+    public VlogShareLRFeatureExtractor() {
+        super();
+    }
+
+    // TODO
+    // 补充待抽取的context feature
+    public void getContextFeatures(RequestContextBytesFeature requestContextBytes) {
+        makeFea(VlogFeatureGroup.MACHINEINFO_BRAND, requestContextBytes.getMachineinfo_brand());
+        makeFea(VlogFeatureGroup.MACHINEINFO_MODEL, requestContextBytes.getMachineinfo_model());
+        makeFea(VlogFeatureGroup.MACHINEINFO_PLATFORM, requestContextBytes.getMachineinfo_platform());
+        makeFea(VlogFeatureGroup.MACHINEINFO_SDKVERSION, requestContextBytes.getMachineinfo_sdkversion());
+        makeFea(VlogFeatureGroup.MACHINEINFO_SYSTEM, requestContextBytes.getMachineinfo_system());
+        makeFea(VlogFeatureGroup.MACHINEINFO_WECHATVERSION, requestContextBytes.getMachineinfo_brand());
+
+        makeFea(VlogFeatureGroup.DAY, requestContextBytes.getWeek());
+        makeFea(VlogFeatureGroup.WEEK, requestContextBytes.getWeek());
+        makeFea(VlogFeatureGroup.HOUR, requestContextBytes.getHour());
+
+    }
+
+    //TODO
+    public void getUserFeatures(UserBytesFeature user) {
+        makeFea(VlogFeatureGroup.USER_CYCLE_BUCKET_7DAY, user.getUser_cycle_bucket_7days());
+        makeFea(VlogFeatureGroup.USER_SHARE_BUCKET_30DAY, user.getUser_share_bucket_30days());
+        makeFea(VlogFeatureGroup.USER_SHARE_BUCKET_30DAY, user.getUser_cycle_bucket_30days());
+
+        // 1day features
+        makeFea(VlogFeatureGroup.USER_1DAY_EXP, user.getDay1_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.USER_1DAY_CLICK, user.getDay1_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.USER_1DAY_SHARE, user.getDay1_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.USER_1DAY_RETURN, user.getDay1_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.USER_1DAY_CTR, user.getDay1_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.USER_1DAY_STR, user.getDay1_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.USER_1DAY_ROV, user.getDay1_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.USER_1DAY_ROS, user.getDay1_cnt_features().get("ros"));
+
+        // 3day features
+        makeFea(VlogFeatureGroup.USER_3DAY_EXP, user.getDay3_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.USER_3DAY_CLICK, user.getDay3_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.USER_3DAY_SHARE, user.getDay3_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.USER_3DAY_RETURN, user.getDay3_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.USER_3DAY_CTR, user.getDay3_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.USER_3DAY_STR, user.getDay3_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.USER_3DAY_ROV, user.getDay3_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.USER_3DAY_ROS, user.getDay3_cnt_features().get("ros"));
+
+        // 7day features
+        makeFea(VlogFeatureGroup.USER_7DAY_EXP, user.getDay7_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.USER_7DAY_CLICK, user.getDay7_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.USER_7DAY_SHARE, user.getDay7_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.USER_7DAY_RETURN, user.getDay7_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.USER_7DAY_CTR, user.getDay7_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.USER_7DAY_STR, user.getDay7_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.USER_7DAY_ROV, user.getDay7_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.USER_7DAY_ROS, user.getDay7_cnt_features().get("ros"));
+
+        // 3month features
+        makeFea(VlogFeatureGroup.USER_3MONTH_EXP, user.getMonth3_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_CLICK, user.getMonth3_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_SHARE, user.getMonth3_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_RETURN, user.getMonth3_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_CTR, user.getMonth3_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_STR, user.getMonth3_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_ROV, user.getMonth3_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.USER_3MONTH_ROS, user.getMonth3_cnt_features().get("ros"));
+
+    }
+
+    public void getItemFeature(VideoBytesFeature item) {
+        makeFea(VlogFeatureGroup.VIDEOID, item.getVideoId());
+        makeFea(VlogFeatureGroup.UP_ID, item.getUpId());
+        // 1day features
+        makeFea(VlogFeatureGroup.ITEM_1DAY_EXP, item.getItem_day1_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_CLICK, item.getItem_day1_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_SHARE, item.getItem_day1_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_RETURN, item.getItem_day1_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_CTR, item.getItem_day1_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_STR, item.getItem_day1_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_ROV, item.getItem_day1_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.ITEM_1DAY_ROS, item.getItem_day1_cnt_features().get("ros"));
+
+        // 3day features
+        makeFea(VlogFeatureGroup.ITEM_3DAY_EXP, item.getItem_day1_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_CLICK, item.getItem_day1_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_SHARE, item.getItem_day1_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_RETURN, item.getItem_day1_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_CTR, item.getItem_day1_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_STR, item.getItem_day1_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_ROV, item.getItem_day1_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.ITEM_3DAY_ROS, item.getItem_day1_cnt_features().get("ros"));
+
+        // 7day features
+        makeFea(VlogFeatureGroup.ITEM_7DAY_EXP, item.getItem_day7_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_CLICK, item.getItem_day7_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_SHARE, item.getItem_day7_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_RETURN, item.getItem_day7_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_CTR, item.getItem_day7_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_STR, item.getItem_day7_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_ROV, item.getItem_day7_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.ITEM_7DAY_ROS, item.getItem_day7_cnt_features().get("ros"));
+
+        // 3month features
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_EXP, item.getItem_month3_cnt_features().get("exp"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_CLICK, item.getItem_month3_cnt_features().get("click"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_SHARE, item.getItem_month3_cnt_features().get("share"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_RETURN, item.getItem_month3_cnt_features().get("return"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_CTR, item.getItem_month3_cnt_features().get("ctr"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_STR, item.getItem_month3_cnt_features().get("str"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_ROV, item.getItem_month3_cnt_features().get("rov"));
+        makeFea(VlogFeatureGroup.ITEM_3MONTH_ROS, item.getItem_month3_cnt_features().get("ros"));
+
+    }
+
+    @Override
+    public synchronized LRSamples single(UserBytesFeature userBytesFeature,
+                            VideoBytesFeature videoBytesFeature,
+                            RequestContextBytesFeature requestContextBytesFeature) {
+        features.clear();
+        // extract features
+        getUserFeatures(userBytesFeature);
+        getContextFeatures(requestContextBytesFeature);
+        getItemFeature(videoBytesFeature);
+
+        LRSamples.Builder lr = LRSamples.newBuilder();
+        lr.setGroupNum(groupCount);
+        List<FeatureGroup> keys = new ArrayList<>(features.keySet());
+        int count = 0;
+        for(FeatureGroup group : keys) {
+            List<BaseFeature> fea = features.get(group);
+            GroupedFeature.Builder gf = GroupedFeature.newBuilder();
+            gf.setGroup(group);
+            gf.setCount(fea.size());
+            gf.addAllFeatures(fea);
+            count += fea.size();
+            lr.addFeatures(gf);
+        }
+        lr.setCount(count);
+        return lr.build();
+    }
+
+
+}

+ 2 - 2
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/feature/Feature.java

@@ -116,7 +116,7 @@ public final class Feature {
       "\n1com/tzld/piaoquan/recommend/feature/fe" +
       "ature.proto\032\031google/protobuf/any.proto\0320" +
       "com/tzld/piaoquan/recommend/feature/comm" +
-      "on.proto\"$\n\025GetUserFeatureRequest\022\013\n\003uid" +
+      "on.proto\"$\n\025GetUserFeatureRequest\022\013\n\003mid" +
       "\030\001 \001(\t\"Z\n\026GetUserFeatureResponse\022\027\n\006resu" +
       "lt\030\001 \001(\0132\007.Result\022\'\n\014user_feature\030\002 \001(\0132" +
       "\021.UserFeatureProto\"\334\002\n\020UserFeatureProto\022" +
@@ -222,7 +222,7 @@ public final class Feature {
     internal_static_GetUserFeatureRequest_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_GetUserFeatureRequest_descriptor,
-        new java.lang.String[] { "Uid", });
+        new java.lang.String[] { "Mid", });
     internal_static_GetUserFeatureResponse_descriptor =
       getDescriptor().getMessageTypes().get(1);
     internal_static_GetUserFeatureResponse_fieldAccessorTable = new

+ 48 - 48
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/feature/GetUserFeatureRequest.java

@@ -16,7 +16,7 @@ private static final long serialVersionUID = 0L;
     super(builder);
   }
   private GetUserFeatureRequest() {
-    uid_ = "";
+    mid_ = "";
   }
 
   @java.lang.Override
@@ -52,7 +52,7 @@ private static final long serialVersionUID = 0L;
           case 10: {
             java.lang.String s = input.readStringRequireUtf8();
 
-            uid_ = s;
+            mid_ = s;
             break;
           }
           default: {
@@ -87,38 +87,38 @@ private static final long serialVersionUID = 0L;
             com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest.class, com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest.Builder.class);
   }
 
-  public static final int UID_FIELD_NUMBER = 1;
-  private volatile java.lang.Object uid_;
+  public static final int MID_FIELD_NUMBER = 1;
+  private volatile java.lang.Object mid_;
   /**
-   * <code>string uid = 1;</code>
-   * @return The uid.
+   * <code>string mid = 1;</code>
+   * @return The mid.
    */
   @java.lang.Override
-  public java.lang.String getUid() {
-    java.lang.Object ref = uid_;
+  public java.lang.String getMid() {
+    java.lang.Object ref = mid_;
     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();
-      uid_ = s;
+      mid_ = s;
       return s;
     }
   }
   /**
-   * <code>string uid = 1;</code>
-   * @return The bytes for uid.
+   * <code>string mid = 1;</code>
+   * @return The bytes for mid.
    */
   @java.lang.Override
   public com.google.protobuf.ByteString
-      getUidBytes() {
-    java.lang.Object ref = uid_;
+      getMidBytes() {
+    java.lang.Object ref = mid_;
     if (ref instanceof java.lang.String) {
       com.google.protobuf.ByteString b = 
           com.google.protobuf.ByteString.copyFromUtf8(
               (java.lang.String) ref);
-      uid_ = b;
+      mid_ = b;
       return b;
     } else {
       return (com.google.protobuf.ByteString) ref;
@@ -139,8 +139,8 @@ private static final long serialVersionUID = 0L;
   @java.lang.Override
   public void writeTo(com.google.protobuf.CodedOutputStream output)
                       throws java.io.IOException {
-    if (!getUidBytes().isEmpty()) {
-      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, uid_);
+    if (!getMidBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, mid_);
     }
     unknownFields.writeTo(output);
   }
@@ -151,8 +151,8 @@ private static final long serialVersionUID = 0L;
     if (size != -1) return size;
 
     size = 0;
-    if (!getUidBytes().isEmpty()) {
-      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, uid_);
+    if (!getMidBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, mid_);
     }
     size += unknownFields.getSerializedSize();
     memoizedSize = size;
@@ -169,8 +169,8 @@ private static final long serialVersionUID = 0L;
     }
     com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest other = (com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest) obj;
 
-    if (!getUid()
-        .equals(other.getUid())) return false;
+    if (!getMid()
+        .equals(other.getMid())) return false;
     if (!unknownFields.equals(other.unknownFields)) return false;
     return true;
   }
@@ -182,8 +182,8 @@ private static final long serialVersionUID = 0L;
     }
     int hash = 41;
     hash = (19 * hash) + getDescriptor().hashCode();
-    hash = (37 * hash) + UID_FIELD_NUMBER;
-    hash = (53 * hash) + getUid().hashCode();
+    hash = (37 * hash) + MID_FIELD_NUMBER;
+    hash = (53 * hash) + getMid().hashCode();
     hash = (29 * hash) + unknownFields.hashCode();
     memoizedHashCode = hash;
     return hash;
@@ -317,7 +317,7 @@ private static final long serialVersionUID = 0L;
     @java.lang.Override
     public Builder clear() {
       super.clear();
-      uid_ = "";
+      mid_ = "";
 
       return this;
     }
@@ -345,7 +345,7 @@ private static final long serialVersionUID = 0L;
     @java.lang.Override
     public com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest buildPartial() {
       com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest result = new com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest(this);
-      result.uid_ = uid_;
+      result.mid_ = mid_;
       onBuilt();
       return result;
     }
@@ -394,8 +394,8 @@ private static final long serialVersionUID = 0L;
 
     public Builder mergeFrom(com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest other) {
       if (other == com.tzld.piaoquan.recommend.feature.model.feature.GetUserFeatureRequest.getDefaultInstance()) return this;
-      if (!other.getUid().isEmpty()) {
-        uid_ = other.uid_;
+      if (!other.getMid().isEmpty()) {
+        mid_ = other.mid_;
         onChanged();
       }
       this.mergeUnknownFields(other.unknownFields);
@@ -427,78 +427,78 @@ private static final long serialVersionUID = 0L;
       return this;
     }
 
-    private java.lang.Object uid_ = "";
+    private java.lang.Object mid_ = "";
     /**
-     * <code>string uid = 1;</code>
-     * @return The uid.
+     * <code>string mid = 1;</code>
+     * @return The mid.
      */
-    public java.lang.String getUid() {
-      java.lang.Object ref = uid_;
+    public java.lang.String getMid() {
+      java.lang.Object ref = mid_;
       if (!(ref instanceof java.lang.String)) {
         com.google.protobuf.ByteString bs =
             (com.google.protobuf.ByteString) ref;
         java.lang.String s = bs.toStringUtf8();
-        uid_ = s;
+        mid_ = s;
         return s;
       } else {
         return (java.lang.String) ref;
       }
     }
     /**
-     * <code>string uid = 1;</code>
-     * @return The bytes for uid.
+     * <code>string mid = 1;</code>
+     * @return The bytes for mid.
      */
     public com.google.protobuf.ByteString
-        getUidBytes() {
-      java.lang.Object ref = uid_;
+        getMidBytes() {
+      java.lang.Object ref = mid_;
       if (ref instanceof String) {
         com.google.protobuf.ByteString b = 
             com.google.protobuf.ByteString.copyFromUtf8(
                 (java.lang.String) ref);
-        uid_ = b;
+        mid_ = b;
         return b;
       } else {
         return (com.google.protobuf.ByteString) ref;
       }
     }
     /**
-     * <code>string uid = 1;</code>
-     * @param value The uid to set.
+     * <code>string mid = 1;</code>
+     * @param value The mid to set.
      * @return This builder for chaining.
      */
-    public Builder setUid(
+    public Builder setMid(
         java.lang.String value) {
       if (value == null) {
     throw new NullPointerException();
   }
   
-      uid_ = value;
+      mid_ = value;
       onChanged();
       return this;
     }
     /**
-     * <code>string uid = 1;</code>
+     * <code>string mid = 1;</code>
      * @return This builder for chaining.
      */
-    public Builder clearUid() {
+    public Builder clearMid() {
       
-      uid_ = getDefaultInstance().getUid();
+      mid_ = getDefaultInstance().getMid();
       onChanged();
       return this;
     }
     /**
-     * <code>string uid = 1;</code>
-     * @param value The bytes for uid to set.
+     * <code>string mid = 1;</code>
+     * @param value The bytes for mid to set.
      * @return This builder for chaining.
      */
-    public Builder setUidBytes(
+    public Builder setMidBytes(
         com.google.protobuf.ByteString value) {
       if (value == null) {
     throw new NullPointerException();
   }
   checkByteStringIsUtf8(value);
       
-      uid_ = value;
+      mid_ = value;
       onChanged();
       return this;
     }

+ 6 - 6
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/feature/GetUserFeatureRequestOrBuilder.java

@@ -8,14 +8,14 @@ public interface GetUserFeatureRequestOrBuilder extends
     com.google.protobuf.MessageOrBuilder {
 
   /**
-   * <code>string uid = 1;</code>
-   * @return The uid.
+   * <code>string mid = 1;</code>
+   * @return The mid.
    */
-  java.lang.String getUid();
+  java.lang.String getMid();
   /**
-   * <code>string uid = 1;</code>
-   * @return The bytes for uid.
+   * <code>string mid = 1;</code>
+   * @return The bytes for mid.
    */
   com.google.protobuf.ByteString
-      getUidBytes();
+      getMidBytes();
 }

+ 819 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/BaseFeature.java

@@ -0,0 +1,819 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+/**
+ * Protobuf type {@code BaseFeature}
+ */
+public final class BaseFeature extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:BaseFeature)
+    BaseFeatureOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use BaseFeature.newBuilder() to construct.
+  private BaseFeature(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private BaseFeature() {
+    fea_ = "";
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new BaseFeature();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private BaseFeature(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 8: {
+
+            id_ = input.readInt64();
+            break;
+          }
+          case 16: {
+
+            identifier_ = input.readInt64();
+            break;
+          }
+          case 26: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            fea_ = s;
+            break;
+          }
+          case 33: {
+
+            value_ = input.readDouble();
+            break;
+          }
+          case 41: {
+
+            weight_ = input.readDouble();
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_BaseFeature_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_BaseFeature_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.class, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder.class);
+  }
+
+  public static final int ID_FIELD_NUMBER = 1;
+  private long id_;
+  /**
+   * <code>int64 id = 1;</code>
+   * @return The id.
+   */
+  @java.lang.Override
+  public long getId() {
+    return id_;
+  }
+
+  public static final int IDENTIFIER_FIELD_NUMBER = 2;
+  private long identifier_;
+  /**
+   * <code>int64 identifier = 2;</code>
+   * @return The identifier.
+   */
+  @java.lang.Override
+  public long getIdentifier() {
+    return identifier_;
+  }
+
+  public static final int FEA_FIELD_NUMBER = 3;
+  private volatile java.lang.Object fea_;
+  /**
+   * <code>string fea = 3;</code>
+   * @return The fea.
+   */
+  @java.lang.Override
+  public java.lang.String getFea() {
+    java.lang.Object ref = fea_;
+    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();
+      fea_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string fea = 3;</code>
+   * @return The bytes for fea.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getFeaBytes() {
+    java.lang.Object ref = fea_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      fea_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int VALUE_FIELD_NUMBER = 4;
+  private double value_;
+  /**
+   * <code>double value = 4;</code>
+   * @return The value.
+   */
+  @java.lang.Override
+  public double getValue() {
+    return value_;
+  }
+
+  public static final int WEIGHT_FIELD_NUMBER = 5;
+  private double weight_;
+  /**
+   * <code>double weight = 5;</code>
+   * @return The weight.
+   */
+  @java.lang.Override
+  public double getWeight() {
+    return weight_;
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (id_ != 0L) {
+      output.writeInt64(1, id_);
+    }
+    if (identifier_ != 0L) {
+      output.writeInt64(2, identifier_);
+    }
+    if (!getFeaBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 3, fea_);
+    }
+    if (value_ != 0D) {
+      output.writeDouble(4, value_);
+    }
+    if (weight_ != 0D) {
+      output.writeDouble(5, weight_);
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (id_ != 0L) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt64Size(1, id_);
+    }
+    if (identifier_ != 0L) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt64Size(2, identifier_);
+    }
+    if (!getFeaBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, fea_);
+    }
+    if (value_ != 0D) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeDoubleSize(4, value_);
+    }
+    if (weight_ != 0D) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeDoubleSize(5, weight_);
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature other = (com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature) obj;
+
+    if (getId()
+        != other.getId()) return false;
+    if (getIdentifier()
+        != other.getIdentifier()) return false;
+    if (!getFea()
+        .equals(other.getFea())) return false;
+    if (java.lang.Double.doubleToLongBits(getValue())
+        != java.lang.Double.doubleToLongBits(
+            other.getValue())) return false;
+    if (java.lang.Double.doubleToLongBits(getWeight())
+        != java.lang.Double.doubleToLongBits(
+            other.getWeight())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + ID_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        getId());
+    hash = (37 * hash) + IDENTIFIER_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        getIdentifier());
+    hash = (37 * hash) + FEA_FIELD_NUMBER;
+    hash = (53 * hash) + getFea().hashCode();
+    hash = (37 * hash) + VALUE_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        java.lang.Double.doubleToLongBits(getValue()));
+    hash = (37 * hash) + WEIGHT_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        java.lang.Double.doubleToLongBits(getWeight()));
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code BaseFeature}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:BaseFeature)
+      com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_BaseFeature_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_BaseFeature_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.class, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      id_ = 0L;
+
+      identifier_ = 0L;
+
+      fea_ = "";
+
+      value_ = 0D;
+
+      weight_ = 0D;
+
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_BaseFeature_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature build() {
+      com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature buildPartial() {
+      com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature result = new com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature(this);
+      result.id_ = id_;
+      result.identifier_ = identifier_;
+      result.fea_ = fea_;
+      result.value_ = value_;
+      result.weight_ = weight_;
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature) {
+        return mergeFrom((com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature other) {
+      if (other == com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.getDefaultInstance()) return this;
+      if (other.getId() != 0L) {
+        setId(other.getId());
+      }
+      if (other.getIdentifier() != 0L) {
+        setIdentifier(other.getIdentifier());
+      }
+      if (!other.getFea().isEmpty()) {
+        fea_ = other.fea_;
+        onChanged();
+      }
+      if (other.getValue() != 0D) {
+        setValue(other.getValue());
+      }
+      if (other.getWeight() != 0D) {
+        setWeight(other.getWeight());
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+
+    private long id_ ;
+    /**
+     * <code>int64 id = 1;</code>
+     * @return The id.
+     */
+    @java.lang.Override
+    public long getId() {
+      return id_;
+    }
+    /**
+     * <code>int64 id = 1;</code>
+     * @param value The id to set.
+     * @return This builder for chaining.
+     */
+    public Builder setId(long value) {
+      
+      id_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int64 id = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearId() {
+      
+      id_ = 0L;
+      onChanged();
+      return this;
+    }
+
+    private long identifier_ ;
+    /**
+     * <code>int64 identifier = 2;</code>
+     * @return The identifier.
+     */
+    @java.lang.Override
+    public long getIdentifier() {
+      return identifier_;
+    }
+    /**
+     * <code>int64 identifier = 2;</code>
+     * @param value The identifier to set.
+     * @return This builder for chaining.
+     */
+    public Builder setIdentifier(long value) {
+      
+      identifier_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int64 identifier = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearIdentifier() {
+      
+      identifier_ = 0L;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object fea_ = "";
+    /**
+     * <code>string fea = 3;</code>
+     * @return The fea.
+     */
+    public java.lang.String getFea() {
+      java.lang.Object ref = fea_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        fea_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string fea = 3;</code>
+     * @return The bytes for fea.
+     */
+    public com.google.protobuf.ByteString
+        getFeaBytes() {
+      java.lang.Object ref = fea_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        fea_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string fea = 3;</code>
+     * @param value The fea to set.
+     * @return This builder for chaining.
+     */
+    public Builder setFea(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      fea_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string fea = 3;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearFea() {
+      
+      fea_ = getDefaultInstance().getFea();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string fea = 3;</code>
+     * @param value The bytes for fea to set.
+     * @return This builder for chaining.
+     */
+    public Builder setFeaBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      fea_ = value;
+      onChanged();
+      return this;
+    }
+
+    private double value_ ;
+    /**
+     * <code>double value = 4;</code>
+     * @return The value.
+     */
+    @java.lang.Override
+    public double getValue() {
+      return value_;
+    }
+    /**
+     * <code>double value = 4;</code>
+     * @param value The value to set.
+     * @return This builder for chaining.
+     */
+    public Builder setValue(double value) {
+      
+      value_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>double value = 4;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearValue() {
+      
+      value_ = 0D;
+      onChanged();
+      return this;
+    }
+
+    private double weight_ ;
+    /**
+     * <code>double weight = 5;</code>
+     * @return The weight.
+     */
+    @java.lang.Override
+    public double getWeight() {
+      return weight_;
+    }
+    /**
+     * <code>double weight = 5;</code>
+     * @param value The weight to set.
+     * @return This builder for chaining.
+     */
+    public Builder setWeight(double value) {
+      
+      weight_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>double weight = 5;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearWeight() {
+      
+      weight_ = 0D;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:BaseFeature)
+  }
+
+  // @@protoc_insertion_point(class_scope:BaseFeature)
+  private static final com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature();
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<BaseFeature>
+      PARSER = new com.google.protobuf.AbstractParser<BaseFeature>() {
+    @java.lang.Override
+    public BaseFeature parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new BaseFeature(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<BaseFeature> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<BaseFeature> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 45 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/BaseFeatureOrBuilder.java

@@ -0,0 +1,45 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+public interface BaseFeatureOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:BaseFeature)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>int64 id = 1;</code>
+   * @return The id.
+   */
+  long getId();
+
+  /**
+   * <code>int64 identifier = 2;</code>
+   * @return The identifier.
+   */
+  long getIdentifier();
+
+  /**
+   * <code>string fea = 3;</code>
+   * @return The fea.
+   */
+  java.lang.String getFea();
+  /**
+   * <code>string fea = 3;</code>
+   * @return The bytes for fea.
+   */
+  com.google.protobuf.ByteString
+      getFeaBytes();
+
+  /**
+   * <code>double value = 4;</code>
+   * @return The value.
+   */
+  double getValue();
+
+  /**
+   * <code>double weight = 5;</code>
+   * @return The weight.
+   */
+  double getWeight();
+}

+ 104 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/CtrSamples.java

@@ -0,0 +1,104 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+public final class CtrSamples {
+  private CtrSamples() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistryLite registry) {
+  }
+
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+    registerAllExtensions(
+        (com.google.protobuf.ExtensionRegistryLite) registry);
+  }
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_FeatureGroup_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_FeatureGroup_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_BaseFeature_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_BaseFeature_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_GroupedFeature_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_GroupedFeature_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_LRWeight_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_LRWeight_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_LRSamples_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_LRSamples_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static  com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n5com/tzld/piaoquan/recommend/feature/ct" +
+      "r_samples.proto\"E\n\014FeatureGroup\022\014\n\004type\030" +
+      "\001 \001(\t\022\n\n\002id\030\002 \001(\005\022\014\n\004name\030\003 \001(\t\022\r\n\005field" +
+      "\030\004 \001(\t\"Y\n\013BaseFeature\022\n\n\002id\030\001 \001(\003\022\022\n\nide" +
+      "ntifier\030\002 \001(\003\022\013\n\003fea\030\003 \001(\t\022\r\n\005value\030\004 \001(" +
+      "\001\022\016\n\006weight\030\005 \001(\001\"]\n\016GroupedFeature\022\034\n\005g" +
+      "roup\030\001 \001(\0132\r.FeatureGroup\022\r\n\005count\030\002 \001(\005" +
+      "\022\036\n\010features\030\003 \003(\0132\014.BaseFeature\"=\n\010LRWe" +
+      "ight\022\021\n\tgroup_num\030\001 \001(\005\022\036\n\010features\030\002 \003(" +
+      "\0132\014.BaseFeature\"\207\001\n\tLRSamples\022\020\n\010is_clic" +
+      "k\030\001 \001(\005\022\021\n\tgroup_num\030\002 \001(\005\022\r\n\005count\030\003 \001(" +
+      "\005\022!\n\010features\030\004 \003(\0132\017.GroupedFeature\022\016\n\006" +
+      "weight\030\005 \001(\001\022\023\n\013predict_ctr\030\006 \001(\001B7\n0com" +
+      ".tzld.piaoquan.recommend.feature.model.s" +
+      "ampleP\001\210\001\001b\006proto3"
+    };
+    descriptor = com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+        });
+    internal_static_FeatureGroup_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_FeatureGroup_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_FeatureGroup_descriptor,
+        new java.lang.String[] { "Type", "Id", "Name", "Field", });
+    internal_static_BaseFeature_descriptor =
+      getDescriptor().getMessageTypes().get(1);
+    internal_static_BaseFeature_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_BaseFeature_descriptor,
+        new java.lang.String[] { "Id", "Identifier", "Fea", "Value", "Weight", });
+    internal_static_GroupedFeature_descriptor =
+      getDescriptor().getMessageTypes().get(2);
+    internal_static_GroupedFeature_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_GroupedFeature_descriptor,
+        new java.lang.String[] { "Group", "Count", "Features", });
+    internal_static_LRWeight_descriptor =
+      getDescriptor().getMessageTypes().get(3);
+    internal_static_LRWeight_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_LRWeight_descriptor,
+        new java.lang.String[] { "GroupNum", "Features", });
+    internal_static_LRSamples_descriptor =
+      getDescriptor().getMessageTypes().get(4);
+    internal_static_LRSamples_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_LRSamples_descriptor,
+        new java.lang.String[] { "IsClick", "GroupNum", "Count", "Features", "Weight", "PredictCtr", });
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}

+ 897 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/FeatureGroup.java

@@ -0,0 +1,897 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+/**
+ * Protobuf type {@code FeatureGroup}
+ */
+public final class FeatureGroup extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:FeatureGroup)
+    FeatureGroupOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use FeatureGroup.newBuilder() to construct.
+  private FeatureGroup(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private FeatureGroup() {
+    type_ = "";
+    name_ = "";
+    field_ = "";
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new FeatureGroup();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private FeatureGroup(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 10: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            type_ = s;
+            break;
+          }
+          case 16: {
+
+            id_ = input.readInt32();
+            break;
+          }
+          case 26: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            name_ = s;
+            break;
+          }
+          case 34: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            field_ = s;
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_FeatureGroup_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_FeatureGroup_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.class, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder.class);
+  }
+
+  public static final int TYPE_FIELD_NUMBER = 1;
+  private volatile java.lang.Object type_;
+  /**
+   * <code>string type = 1;</code>
+   * @return The type.
+   */
+  @java.lang.Override
+  public java.lang.String getType() {
+    java.lang.Object ref = type_;
+    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();
+      type_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string type = 1;</code>
+   * @return The bytes for type.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getTypeBytes() {
+    java.lang.Object ref = type_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      type_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int ID_FIELD_NUMBER = 2;
+  private int id_;
+  /**
+   * <code>int32 id = 2;</code>
+   * @return The id.
+   */
+  @java.lang.Override
+  public int getId() {
+    return id_;
+  }
+
+  public static final int NAME_FIELD_NUMBER = 3;
+  private volatile java.lang.Object name_;
+  /**
+   * <code>string name = 3;</code>
+   * @return The name.
+   */
+  @java.lang.Override
+  public java.lang.String getName() {
+    java.lang.Object ref = name_;
+    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();
+      name_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string name = 3;</code>
+   * @return The bytes for name.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getNameBytes() {
+    java.lang.Object ref = name_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      name_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int FIELD_FIELD_NUMBER = 4;
+  private volatile java.lang.Object field_;
+  /**
+   * <code>string field = 4;</code>
+   * @return The field.
+   */
+  @java.lang.Override
+  public java.lang.String getField() {
+    java.lang.Object ref = field_;
+    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();
+      field_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string field = 4;</code>
+   * @return The bytes for field.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getFieldBytes() {
+    java.lang.Object ref = field_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      field_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (!getTypeBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, type_);
+    }
+    if (id_ != 0) {
+      output.writeInt32(2, id_);
+    }
+    if (!getNameBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 3, name_);
+    }
+    if (!getFieldBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 4, field_);
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (!getTypeBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, type_);
+    }
+    if (id_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(2, id_);
+    }
+    if (!getNameBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, name_);
+    }
+    if (!getFieldBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, field_);
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup other = (com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup) obj;
+
+    if (!getType()
+        .equals(other.getType())) return false;
+    if (getId()
+        != other.getId()) return false;
+    if (!getName()
+        .equals(other.getName())) return false;
+    if (!getField()
+        .equals(other.getField())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + TYPE_FIELD_NUMBER;
+    hash = (53 * hash) + getType().hashCode();
+    hash = (37 * hash) + ID_FIELD_NUMBER;
+    hash = (53 * hash) + getId();
+    hash = (37 * hash) + NAME_FIELD_NUMBER;
+    hash = (53 * hash) + getName().hashCode();
+    hash = (37 * hash) + FIELD_FIELD_NUMBER;
+    hash = (53 * hash) + getField().hashCode();
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code FeatureGroup}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:FeatureGroup)
+      com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_FeatureGroup_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_FeatureGroup_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.class, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      type_ = "";
+
+      id_ = 0;
+
+      name_ = "";
+
+      field_ = "";
+
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_FeatureGroup_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup build() {
+      com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup buildPartial() {
+      com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup result = new com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup(this);
+      result.type_ = type_;
+      result.id_ = id_;
+      result.name_ = name_;
+      result.field_ = field_;
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup) {
+        return mergeFrom((com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup other) {
+      if (other == com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.getDefaultInstance()) return this;
+      if (!other.getType().isEmpty()) {
+        type_ = other.type_;
+        onChanged();
+      }
+      if (other.getId() != 0) {
+        setId(other.getId());
+      }
+      if (!other.getName().isEmpty()) {
+        name_ = other.name_;
+        onChanged();
+      }
+      if (!other.getField().isEmpty()) {
+        field_ = other.field_;
+        onChanged();
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+
+    private java.lang.Object type_ = "";
+    /**
+     * <code>string type = 1;</code>
+     * @return The type.
+     */
+    public java.lang.String getType() {
+      java.lang.Object ref = type_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        type_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string type = 1;</code>
+     * @return The bytes for type.
+     */
+    public com.google.protobuf.ByteString
+        getTypeBytes() {
+      java.lang.Object ref = type_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        type_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string type = 1;</code>
+     * @param value The type to set.
+     * @return This builder for chaining.
+     */
+    public Builder setType(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      type_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string type = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearType() {
+      
+      type_ = getDefaultInstance().getType();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string type = 1;</code>
+     * @param value The bytes for type to set.
+     * @return This builder for chaining.
+     */
+    public Builder setTypeBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      type_ = value;
+      onChanged();
+      return this;
+    }
+
+    private int id_ ;
+    /**
+     * <code>int32 id = 2;</code>
+     * @return The id.
+     */
+    @java.lang.Override
+    public int getId() {
+      return id_;
+    }
+    /**
+     * <code>int32 id = 2;</code>
+     * @param value The id to set.
+     * @return This builder for chaining.
+     */
+    public Builder setId(int value) {
+      
+      id_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int32 id = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearId() {
+      
+      id_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object name_ = "";
+    /**
+     * <code>string name = 3;</code>
+     * @return The name.
+     */
+    public java.lang.String getName() {
+      java.lang.Object ref = name_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        name_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string name = 3;</code>
+     * @return The bytes for name.
+     */
+    public com.google.protobuf.ByteString
+        getNameBytes() {
+      java.lang.Object ref = name_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        name_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string name = 3;</code>
+     * @param value The name to set.
+     * @return This builder for chaining.
+     */
+    public Builder setName(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      name_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string name = 3;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearName() {
+      
+      name_ = getDefaultInstance().getName();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string name = 3;</code>
+     * @param value The bytes for name to set.
+     * @return This builder for chaining.
+     */
+    public Builder setNameBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      name_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object field_ = "";
+    /**
+     * <code>string field = 4;</code>
+     * @return The field.
+     */
+    public java.lang.String getField() {
+      java.lang.Object ref = field_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        field_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string field = 4;</code>
+     * @return The bytes for field.
+     */
+    public com.google.protobuf.ByteString
+        getFieldBytes() {
+      java.lang.Object ref = field_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        field_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string field = 4;</code>
+     * @param value The field to set.
+     * @return This builder for chaining.
+     */
+    public Builder setField(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      field_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string field = 4;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearField() {
+      
+      field_ = getDefaultInstance().getField();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string field = 4;</code>
+     * @param value The bytes for field to set.
+     * @return This builder for chaining.
+     */
+    public Builder setFieldBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      field_ = value;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:FeatureGroup)
+  }
+
+  // @@protoc_insertion_point(class_scope:FeatureGroup)
+  private static final com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup();
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<FeatureGroup>
+      PARSER = new com.google.protobuf.AbstractParser<FeatureGroup>() {
+    @java.lang.Override
+    public FeatureGroup parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new FeatureGroup(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<FeatureGroup> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<FeatureGroup> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 51 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/FeatureGroupOrBuilder.java

@@ -0,0 +1,51 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+public interface FeatureGroupOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:FeatureGroup)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>string type = 1;</code>
+   * @return The type.
+   */
+  java.lang.String getType();
+  /**
+   * <code>string type = 1;</code>
+   * @return The bytes for type.
+   */
+  com.google.protobuf.ByteString
+      getTypeBytes();
+
+  /**
+   * <code>int32 id = 2;</code>
+   * @return The id.
+   */
+  int getId();
+
+  /**
+   * <code>string name = 3;</code>
+   * @return The name.
+   */
+  java.lang.String getName();
+  /**
+   * <code>string name = 3;</code>
+   * @return The bytes for name.
+   */
+  com.google.protobuf.ByteString
+      getNameBytes();
+
+  /**
+   * <code>string field = 4;</code>
+   * @return The field.
+   */
+  java.lang.String getField();
+  /**
+   * <code>string field = 4;</code>
+   * @return The bytes for field.
+   */
+  com.google.protobuf.ByteString
+      getFieldBytes();
+}

+ 1022 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/GroupedFeature.java

@@ -0,0 +1,1022 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+/**
+ * Protobuf type {@code GroupedFeature}
+ */
+public final class GroupedFeature extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:GroupedFeature)
+    GroupedFeatureOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use GroupedFeature.newBuilder() to construct.
+  private GroupedFeature(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private GroupedFeature() {
+    features_ = java.util.Collections.emptyList();
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new GroupedFeature();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private GroupedFeature(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    int mutable_bitField0_ = 0;
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 10: {
+            com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder subBuilder = null;
+            if (group_ != null) {
+              subBuilder = group_.toBuilder();
+            }
+            group_ = input.readMessage(com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.parser(), extensionRegistry);
+            if (subBuilder != null) {
+              subBuilder.mergeFrom(group_);
+              group_ = subBuilder.buildPartial();
+            }
+
+            break;
+          }
+          case 16: {
+
+            count_ = input.readInt32();
+            break;
+          }
+          case 26: {
+            if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+              features_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature>();
+              mutable_bitField0_ |= 0x00000001;
+            }
+            features_.add(
+                input.readMessage(com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.parser(), extensionRegistry));
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      if (((mutable_bitField0_ & 0x00000001) != 0)) {
+        features_ = java.util.Collections.unmodifiableList(features_);
+      }
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_GroupedFeature_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_GroupedFeature_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.class, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder.class);
+  }
+
+  public static final int GROUP_FIELD_NUMBER = 1;
+  private com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup group_;
+  /**
+   * <code>.FeatureGroup group = 1;</code>
+   * @return Whether the group field is set.
+   */
+  @java.lang.Override
+  public boolean hasGroup() {
+    return group_ != null;
+  }
+  /**
+   * <code>.FeatureGroup group = 1;</code>
+   * @return The group.
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup getGroup() {
+    return group_ == null ? com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.getDefaultInstance() : group_;
+  }
+  /**
+   * <code>.FeatureGroup group = 1;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder getGroupOrBuilder() {
+    return getGroup();
+  }
+
+  public static final int COUNT_FIELD_NUMBER = 2;
+  private int count_;
+  /**
+   * <code>int32 count = 2;</code>
+   * @return The count.
+   */
+  @java.lang.Override
+  public int getCount() {
+    return count_;
+  }
+
+  public static final int FEATURES_FIELD_NUMBER = 3;
+  private java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> features_;
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  @java.lang.Override
+  public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> getFeaturesList() {
+    return features_;
+  }
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  @java.lang.Override
+  public java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+      getFeaturesOrBuilderList() {
+    return features_;
+  }
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  @java.lang.Override
+  public int getFeaturesCount() {
+    return features_.size();
+  }
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getFeatures(int index) {
+    return features_.get(index);
+  }
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder getFeaturesOrBuilder(
+      int index) {
+    return features_.get(index);
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (group_ != null) {
+      output.writeMessage(1, getGroup());
+    }
+    if (count_ != 0) {
+      output.writeInt32(2, count_);
+    }
+    for (int i = 0; i < features_.size(); i++) {
+      output.writeMessage(3, features_.get(i));
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (group_ != null) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(1, getGroup());
+    }
+    if (count_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(2, count_);
+    }
+    for (int i = 0; i < features_.size(); i++) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(3, features_.get(i));
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature other = (com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature) obj;
+
+    if (hasGroup() != other.hasGroup()) return false;
+    if (hasGroup()) {
+      if (!getGroup()
+          .equals(other.getGroup())) return false;
+    }
+    if (getCount()
+        != other.getCount()) return false;
+    if (!getFeaturesList()
+        .equals(other.getFeaturesList())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    if (hasGroup()) {
+      hash = (37 * hash) + GROUP_FIELD_NUMBER;
+      hash = (53 * hash) + getGroup().hashCode();
+    }
+    hash = (37 * hash) + COUNT_FIELD_NUMBER;
+    hash = (53 * hash) + getCount();
+    if (getFeaturesCount() > 0) {
+      hash = (37 * hash) + FEATURES_FIELD_NUMBER;
+      hash = (53 * hash) + getFeaturesList().hashCode();
+    }
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code GroupedFeature}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:GroupedFeature)
+      com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_GroupedFeature_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_GroupedFeature_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.class, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+        getFeaturesFieldBuilder();
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      if (groupBuilder_ == null) {
+        group_ = null;
+      } else {
+        group_ = null;
+        groupBuilder_ = null;
+      }
+      count_ = 0;
+
+      if (featuresBuilder_ == null) {
+        features_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+      } else {
+        featuresBuilder_.clear();
+      }
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_GroupedFeature_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature build() {
+      com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature buildPartial() {
+      com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature result = new com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature(this);
+      int from_bitField0_ = bitField0_;
+      if (groupBuilder_ == null) {
+        result.group_ = group_;
+      } else {
+        result.group_ = groupBuilder_.build();
+      }
+      result.count_ = count_;
+      if (featuresBuilder_ == null) {
+        if (((bitField0_ & 0x00000001) != 0)) {
+          features_ = java.util.Collections.unmodifiableList(features_);
+          bitField0_ = (bitField0_ & ~0x00000001);
+        }
+        result.features_ = features_;
+      } else {
+        result.features_ = featuresBuilder_.build();
+      }
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature) {
+        return mergeFrom((com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature other) {
+      if (other == com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.getDefaultInstance()) return this;
+      if (other.hasGroup()) {
+        mergeGroup(other.getGroup());
+      }
+      if (other.getCount() != 0) {
+        setCount(other.getCount());
+      }
+      if (featuresBuilder_ == null) {
+        if (!other.features_.isEmpty()) {
+          if (features_.isEmpty()) {
+            features_ = other.features_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+          } else {
+            ensureFeaturesIsMutable();
+            features_.addAll(other.features_);
+          }
+          onChanged();
+        }
+      } else {
+        if (!other.features_.isEmpty()) {
+          if (featuresBuilder_.isEmpty()) {
+            featuresBuilder_.dispose();
+            featuresBuilder_ = null;
+            features_ = other.features_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+            featuresBuilder_ = 
+              com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ?
+                 getFeaturesFieldBuilder() : null;
+          } else {
+            featuresBuilder_.addAllMessages(other.features_);
+          }
+        }
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+    private int bitField0_;
+
+    private com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup group_;
+    private com.google.protobuf.SingleFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder> groupBuilder_;
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     * @return Whether the group field is set.
+     */
+    public boolean hasGroup() {
+      return groupBuilder_ != null || group_ != null;
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     * @return The group.
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup getGroup() {
+      if (groupBuilder_ == null) {
+        return group_ == null ? com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.getDefaultInstance() : group_;
+      } else {
+        return groupBuilder_.getMessage();
+      }
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    public Builder setGroup(com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup value) {
+      if (groupBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        group_ = value;
+        onChanged();
+      } else {
+        groupBuilder_.setMessage(value);
+      }
+
+      return this;
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    public Builder setGroup(
+        com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder builderForValue) {
+      if (groupBuilder_ == null) {
+        group_ = builderForValue.build();
+        onChanged();
+      } else {
+        groupBuilder_.setMessage(builderForValue.build());
+      }
+
+      return this;
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    public Builder mergeGroup(com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup value) {
+      if (groupBuilder_ == null) {
+        if (group_ != null) {
+          group_ =
+            com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.newBuilder(group_).mergeFrom(value).buildPartial();
+        } else {
+          group_ = value;
+        }
+        onChanged();
+      } else {
+        groupBuilder_.mergeFrom(value);
+      }
+
+      return this;
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    public Builder clearGroup() {
+      if (groupBuilder_ == null) {
+        group_ = null;
+        onChanged();
+      } else {
+        group_ = null;
+        groupBuilder_ = null;
+      }
+
+      return this;
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder getGroupBuilder() {
+      
+      onChanged();
+      return getGroupFieldBuilder().getBuilder();
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder getGroupOrBuilder() {
+      if (groupBuilder_ != null) {
+        return groupBuilder_.getMessageOrBuilder();
+      } else {
+        return group_ == null ?
+            com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.getDefaultInstance() : group_;
+      }
+    }
+    /**
+     * <code>.FeatureGroup group = 1;</code>
+     */
+    private com.google.protobuf.SingleFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder> 
+        getGroupFieldBuilder() {
+      if (groupBuilder_ == null) {
+        groupBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
+            com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup.Builder, com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder>(
+                getGroup(),
+                getParentForChildren(),
+                isClean());
+        group_ = null;
+      }
+      return groupBuilder_;
+    }
+
+    private int count_ ;
+    /**
+     * <code>int32 count = 2;</code>
+     * @return The count.
+     */
+    @java.lang.Override
+    public int getCount() {
+      return count_;
+    }
+    /**
+     * <code>int32 count = 2;</code>
+     * @param value The count to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCount(int value) {
+      
+      count_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int32 count = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearCount() {
+      
+      count_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> features_ =
+      java.util.Collections.emptyList();
+    private void ensureFeaturesIsMutable() {
+      if (!((bitField0_ & 0x00000001) != 0)) {
+        features_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature>(features_);
+        bitField0_ |= 0x00000001;
+       }
+    }
+
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> featuresBuilder_;
+
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> getFeaturesList() {
+      if (featuresBuilder_ == null) {
+        return java.util.Collections.unmodifiableList(features_);
+      } else {
+        return featuresBuilder_.getMessageList();
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public int getFeaturesCount() {
+      if (featuresBuilder_ == null) {
+        return features_.size();
+      } else {
+        return featuresBuilder_.getCount();
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getFeatures(int index) {
+      if (featuresBuilder_ == null) {
+        return features_.get(index);
+      } else {
+        return featuresBuilder_.getMessage(index);
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder setFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.set(index, value);
+        onChanged();
+      } else {
+        featuresBuilder_.setMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder setFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.set(index, builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.setMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder addFeatures(com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.add(value);
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder addFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.add(index, value);
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder addFeatures(
+        com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.add(builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder addFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.add(index, builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder addAllFeatures(
+        java.lang.Iterable<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> values) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, features_);
+        onChanged();
+      } else {
+        featuresBuilder_.addAllMessages(values);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder clearFeatures() {
+      if (featuresBuilder_ == null) {
+        features_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+        onChanged();
+      } else {
+        featuresBuilder_.clear();
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public Builder removeFeatures(int index) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.remove(index);
+        onChanged();
+      } else {
+        featuresBuilder_.remove(index);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder getFeaturesBuilder(
+        int index) {
+      return getFeaturesFieldBuilder().getBuilder(index);
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder getFeaturesOrBuilder(
+        int index) {
+      if (featuresBuilder_ == null) {
+        return features_.get(index);  } else {
+        return featuresBuilder_.getMessageOrBuilder(index);
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+         getFeaturesOrBuilderList() {
+      if (featuresBuilder_ != null) {
+        return featuresBuilder_.getMessageOrBuilderList();
+      } else {
+        return java.util.Collections.unmodifiableList(features_);
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder addFeaturesBuilder() {
+      return getFeaturesFieldBuilder().addBuilder(
+          com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder addFeaturesBuilder(
+        int index) {
+      return getFeaturesFieldBuilder().addBuilder(
+          index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .BaseFeature features = 3;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder> 
+         getFeaturesBuilderList() {
+      return getFeaturesFieldBuilder().getBuilderList();
+    }
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+        getFeaturesFieldBuilder() {
+      if (featuresBuilder_ == null) {
+        featuresBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<
+            com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder>(
+                features_,
+                ((bitField0_ & 0x00000001) != 0),
+                getParentForChildren(),
+                isClean());
+        features_ = null;
+      }
+      return featuresBuilder_;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:GroupedFeature)
+  }
+
+  // @@protoc_insertion_point(class_scope:GroupedFeature)
+  private static final com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature();
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<GroupedFeature>
+      PARSER = new com.google.protobuf.AbstractParser<GroupedFeature>() {
+    @java.lang.Override
+    public GroupedFeature parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new GroupedFeature(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<GroupedFeature> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<GroupedFeature> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 54 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/GroupedFeatureOrBuilder.java

@@ -0,0 +1,54 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+public interface GroupedFeatureOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:GroupedFeature)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>.FeatureGroup group = 1;</code>
+   * @return Whether the group field is set.
+   */
+  boolean hasGroup();
+  /**
+   * <code>.FeatureGroup group = 1;</code>
+   * @return The group.
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroup getGroup();
+  /**
+   * <code>.FeatureGroup group = 1;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.FeatureGroupOrBuilder getGroupOrBuilder();
+
+  /**
+   * <code>int32 count = 2;</code>
+   * @return The count.
+   */
+  int getCount();
+
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> 
+      getFeaturesList();
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getFeatures(int index);
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  int getFeaturesCount();
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+      getFeaturesOrBuilderList();
+  /**
+   * <code>repeated .BaseFeature features = 3;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder getFeaturesOrBuilder(
+      int index);
+}

+ 1094 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRSamples.java

@@ -0,0 +1,1094 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+/**
+ * Protobuf type {@code LRSamples}
+ */
+public final class LRSamples extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:LRSamples)
+    LRSamplesOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use LRSamples.newBuilder() to construct.
+  private LRSamples(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private LRSamples() {
+    features_ = java.util.Collections.emptyList();
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new LRSamples();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private LRSamples(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    int mutable_bitField0_ = 0;
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 8: {
+
+            isClick_ = input.readInt32();
+            break;
+          }
+          case 16: {
+
+            groupNum_ = input.readInt32();
+            break;
+          }
+          case 24: {
+
+            count_ = input.readInt32();
+            break;
+          }
+          case 34: {
+            if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+              features_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature>();
+              mutable_bitField0_ |= 0x00000001;
+            }
+            features_.add(
+                input.readMessage(com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.parser(), extensionRegistry));
+            break;
+          }
+          case 41: {
+
+            weight_ = input.readDouble();
+            break;
+          }
+          case 49: {
+
+            predictCtr_ = input.readDouble();
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      if (((mutable_bitField0_ & 0x00000001) != 0)) {
+        features_ = java.util.Collections.unmodifiableList(features_);
+      }
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRSamples_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRSamples_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.class, com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.Builder.class);
+  }
+
+  public static final int IS_CLICK_FIELD_NUMBER = 1;
+  private int isClick_;
+  /**
+   * <code>int32 is_click = 1;</code>
+   * @return The isClick.
+   */
+  @java.lang.Override
+  public int getIsClick() {
+    return isClick_;
+  }
+
+  public static final int GROUP_NUM_FIELD_NUMBER = 2;
+  private int groupNum_;
+  /**
+   * <code>int32 group_num = 2;</code>
+   * @return The groupNum.
+   */
+  @java.lang.Override
+  public int getGroupNum() {
+    return groupNum_;
+  }
+
+  public static final int COUNT_FIELD_NUMBER = 3;
+  private int count_;
+  /**
+   * <code>int32 count = 3;</code>
+   * @return The count.
+   */
+  @java.lang.Override
+  public int getCount() {
+    return count_;
+  }
+
+  public static final int FEATURES_FIELD_NUMBER = 4;
+  private java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature> features_;
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  @java.lang.Override
+  public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature> getFeaturesList() {
+    return features_;
+  }
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  @java.lang.Override
+  public java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder> 
+      getFeaturesOrBuilderList() {
+    return features_;
+  }
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  @java.lang.Override
+  public int getFeaturesCount() {
+    return features_.size();
+  }
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature getFeatures(int index) {
+    return features_.get(index);
+  }
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder getFeaturesOrBuilder(
+      int index) {
+    return features_.get(index);
+  }
+
+  public static final int WEIGHT_FIELD_NUMBER = 5;
+  private double weight_;
+  /**
+   * <code>double weight = 5;</code>
+   * @return The weight.
+   */
+  @java.lang.Override
+  public double getWeight() {
+    return weight_;
+  }
+
+  public static final int PREDICT_CTR_FIELD_NUMBER = 6;
+  private double predictCtr_;
+  /**
+   * <code>double predict_ctr = 6;</code>
+   * @return The predictCtr.
+   */
+  @java.lang.Override
+  public double getPredictCtr() {
+    return predictCtr_;
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (isClick_ != 0) {
+      output.writeInt32(1, isClick_);
+    }
+    if (groupNum_ != 0) {
+      output.writeInt32(2, groupNum_);
+    }
+    if (count_ != 0) {
+      output.writeInt32(3, count_);
+    }
+    for (int i = 0; i < features_.size(); i++) {
+      output.writeMessage(4, features_.get(i));
+    }
+    if (weight_ != 0D) {
+      output.writeDouble(5, weight_);
+    }
+    if (predictCtr_ != 0D) {
+      output.writeDouble(6, predictCtr_);
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (isClick_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(1, isClick_);
+    }
+    if (groupNum_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(2, groupNum_);
+    }
+    if (count_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(3, count_);
+    }
+    for (int i = 0; i < features_.size(); i++) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(4, features_.get(i));
+    }
+    if (weight_ != 0D) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeDoubleSize(5, weight_);
+    }
+    if (predictCtr_ != 0D) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeDoubleSize(6, predictCtr_);
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.feature.model.sample.LRSamples)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.feature.model.sample.LRSamples other = (com.tzld.piaoquan.recommend.feature.model.sample.LRSamples) obj;
+
+    if (getIsClick()
+        != other.getIsClick()) return false;
+    if (getGroupNum()
+        != other.getGroupNum()) return false;
+    if (getCount()
+        != other.getCount()) return false;
+    if (!getFeaturesList()
+        .equals(other.getFeaturesList())) return false;
+    if (java.lang.Double.doubleToLongBits(getWeight())
+        != java.lang.Double.doubleToLongBits(
+            other.getWeight())) return false;
+    if (java.lang.Double.doubleToLongBits(getPredictCtr())
+        != java.lang.Double.doubleToLongBits(
+            other.getPredictCtr())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + IS_CLICK_FIELD_NUMBER;
+    hash = (53 * hash) + getIsClick();
+    hash = (37 * hash) + GROUP_NUM_FIELD_NUMBER;
+    hash = (53 * hash) + getGroupNum();
+    hash = (37 * hash) + COUNT_FIELD_NUMBER;
+    hash = (53 * hash) + getCount();
+    if (getFeaturesCount() > 0) {
+      hash = (37 * hash) + FEATURES_FIELD_NUMBER;
+      hash = (53 * hash) + getFeaturesList().hashCode();
+    }
+    hash = (37 * hash) + WEIGHT_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        java.lang.Double.doubleToLongBits(getWeight()));
+    hash = (37 * hash) + PREDICT_CTR_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+        java.lang.Double.doubleToLongBits(getPredictCtr()));
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.feature.model.sample.LRSamples prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code LRSamples}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:LRSamples)
+      com.tzld.piaoquan.recommend.feature.model.sample.LRSamplesOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRSamples_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRSamples_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.class, com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+        getFeaturesFieldBuilder();
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      isClick_ = 0;
+
+      groupNum_ = 0;
+
+      count_ = 0;
+
+      if (featuresBuilder_ == null) {
+        features_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+      } else {
+        featuresBuilder_.clear();
+      }
+      weight_ = 0D;
+
+      predictCtr_ = 0D;
+
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRSamples_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.LRSamples getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.LRSamples build() {
+      com.tzld.piaoquan.recommend.feature.model.sample.LRSamples result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.LRSamples buildPartial() {
+      com.tzld.piaoquan.recommend.feature.model.sample.LRSamples result = new com.tzld.piaoquan.recommend.feature.model.sample.LRSamples(this);
+      int from_bitField0_ = bitField0_;
+      result.isClick_ = isClick_;
+      result.groupNum_ = groupNum_;
+      result.count_ = count_;
+      if (featuresBuilder_ == null) {
+        if (((bitField0_ & 0x00000001) != 0)) {
+          features_ = java.util.Collections.unmodifiableList(features_);
+          bitField0_ = (bitField0_ & ~0x00000001);
+        }
+        result.features_ = features_;
+      } else {
+        result.features_ = featuresBuilder_.build();
+      }
+      result.weight_ = weight_;
+      result.predictCtr_ = predictCtr_;
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.feature.model.sample.LRSamples) {
+        return mergeFrom((com.tzld.piaoquan.recommend.feature.model.sample.LRSamples)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.feature.model.sample.LRSamples other) {
+      if (other == com.tzld.piaoquan.recommend.feature.model.sample.LRSamples.getDefaultInstance()) return this;
+      if (other.getIsClick() != 0) {
+        setIsClick(other.getIsClick());
+      }
+      if (other.getGroupNum() != 0) {
+        setGroupNum(other.getGroupNum());
+      }
+      if (other.getCount() != 0) {
+        setCount(other.getCount());
+      }
+      if (featuresBuilder_ == null) {
+        if (!other.features_.isEmpty()) {
+          if (features_.isEmpty()) {
+            features_ = other.features_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+          } else {
+            ensureFeaturesIsMutable();
+            features_.addAll(other.features_);
+          }
+          onChanged();
+        }
+      } else {
+        if (!other.features_.isEmpty()) {
+          if (featuresBuilder_.isEmpty()) {
+            featuresBuilder_.dispose();
+            featuresBuilder_ = null;
+            features_ = other.features_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+            featuresBuilder_ = 
+              com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ?
+                 getFeaturesFieldBuilder() : null;
+          } else {
+            featuresBuilder_.addAllMessages(other.features_);
+          }
+        }
+      }
+      if (other.getWeight() != 0D) {
+        setWeight(other.getWeight());
+      }
+      if (other.getPredictCtr() != 0D) {
+        setPredictCtr(other.getPredictCtr());
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.feature.model.sample.LRSamples parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.feature.model.sample.LRSamples) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+    private int bitField0_;
+
+    private int isClick_ ;
+    /**
+     * <code>int32 is_click = 1;</code>
+     * @return The isClick.
+     */
+    @java.lang.Override
+    public int getIsClick() {
+      return isClick_;
+    }
+    /**
+     * <code>int32 is_click = 1;</code>
+     * @param value The isClick to set.
+     * @return This builder for chaining.
+     */
+    public Builder setIsClick(int value) {
+      
+      isClick_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int32 is_click = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearIsClick() {
+      
+      isClick_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private int groupNum_ ;
+    /**
+     * <code>int32 group_num = 2;</code>
+     * @return The groupNum.
+     */
+    @java.lang.Override
+    public int getGroupNum() {
+      return groupNum_;
+    }
+    /**
+     * <code>int32 group_num = 2;</code>
+     * @param value The groupNum to set.
+     * @return This builder for chaining.
+     */
+    public Builder setGroupNum(int value) {
+      
+      groupNum_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int32 group_num = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearGroupNum() {
+      
+      groupNum_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private int count_ ;
+    /**
+     * <code>int32 count = 3;</code>
+     * @return The count.
+     */
+    @java.lang.Override
+    public int getCount() {
+      return count_;
+    }
+    /**
+     * <code>int32 count = 3;</code>
+     * @param value The count to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCount(int value) {
+      
+      count_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int32 count = 3;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearCount() {
+      
+      count_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature> features_ =
+      java.util.Collections.emptyList();
+    private void ensureFeaturesIsMutable() {
+      if (!((bitField0_ & 0x00000001) != 0)) {
+        features_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature>(features_);
+        bitField0_ |= 0x00000001;
+       }
+    }
+
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder> featuresBuilder_;
+
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature> getFeaturesList() {
+      if (featuresBuilder_ == null) {
+        return java.util.Collections.unmodifiableList(features_);
+      } else {
+        return featuresBuilder_.getMessageList();
+      }
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public int getFeaturesCount() {
+      if (featuresBuilder_ == null) {
+        return features_.size();
+      } else {
+        return featuresBuilder_.getCount();
+      }
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature getFeatures(int index) {
+      if (featuresBuilder_ == null) {
+        return features_.get(index);
+      } else {
+        return featuresBuilder_.getMessage(index);
+      }
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder setFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.set(index, value);
+        onChanged();
+      } else {
+        featuresBuilder_.setMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder setFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.set(index, builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.setMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder addFeatures(com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.add(value);
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder addFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.add(index, value);
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder addFeatures(
+        com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.add(builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder addFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.add(index, builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder addAllFeatures(
+        java.lang.Iterable<? extends com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature> values) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, features_);
+        onChanged();
+      } else {
+        featuresBuilder_.addAllMessages(values);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder clearFeatures() {
+      if (featuresBuilder_ == null) {
+        features_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+        onChanged();
+      } else {
+        featuresBuilder_.clear();
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public Builder removeFeatures(int index) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.remove(index);
+        onChanged();
+      } else {
+        featuresBuilder_.remove(index);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder getFeaturesBuilder(
+        int index) {
+      return getFeaturesFieldBuilder().getBuilder(index);
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder getFeaturesOrBuilder(
+        int index) {
+      if (featuresBuilder_ == null) {
+        return features_.get(index);  } else {
+        return featuresBuilder_.getMessageOrBuilder(index);
+      }
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder> 
+         getFeaturesOrBuilderList() {
+      if (featuresBuilder_ != null) {
+        return featuresBuilder_.getMessageOrBuilderList();
+      } else {
+        return java.util.Collections.unmodifiableList(features_);
+      }
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder addFeaturesBuilder() {
+      return getFeaturesFieldBuilder().addBuilder(
+          com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder addFeaturesBuilder(
+        int index) {
+      return getFeaturesFieldBuilder().addBuilder(
+          index, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .GroupedFeature features = 4;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder> 
+         getFeaturesBuilderList() {
+      return getFeaturesFieldBuilder().getBuilderList();
+    }
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder> 
+        getFeaturesFieldBuilder() {
+      if (featuresBuilder_ == null) {
+        featuresBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<
+            com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder>(
+                features_,
+                ((bitField0_ & 0x00000001) != 0),
+                getParentForChildren(),
+                isClean());
+        features_ = null;
+      }
+      return featuresBuilder_;
+    }
+
+    private double weight_ ;
+    /**
+     * <code>double weight = 5;</code>
+     * @return The weight.
+     */
+    @java.lang.Override
+    public double getWeight() {
+      return weight_;
+    }
+    /**
+     * <code>double weight = 5;</code>
+     * @param value The weight to set.
+     * @return This builder for chaining.
+     */
+    public Builder setWeight(double value) {
+      
+      weight_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>double weight = 5;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearWeight() {
+      
+      weight_ = 0D;
+      onChanged();
+      return this;
+    }
+
+    private double predictCtr_ ;
+    /**
+     * <code>double predict_ctr = 6;</code>
+     * @return The predictCtr.
+     */
+    @java.lang.Override
+    public double getPredictCtr() {
+      return predictCtr_;
+    }
+    /**
+     * <code>double predict_ctr = 6;</code>
+     * @param value The predictCtr to set.
+     * @return This builder for chaining.
+     */
+    public Builder setPredictCtr(double value) {
+      
+      predictCtr_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>double predict_ctr = 6;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearPredictCtr() {
+      
+      predictCtr_ = 0D;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:LRSamples)
+  }
+
+  // @@protoc_insertion_point(class_scope:LRSamples)
+  private static final com.tzld.piaoquan.recommend.feature.model.sample.LRSamples DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.feature.model.sample.LRSamples();
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRSamples getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<LRSamples>
+      PARSER = new com.google.protobuf.AbstractParser<LRSamples>() {
+    @java.lang.Override
+    public LRSamples parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new LRSamples(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<LRSamples> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<LRSamples> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.LRSamples getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 63 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRSamplesOrBuilder.java

@@ -0,0 +1,63 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+public interface LRSamplesOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:LRSamples)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>int32 is_click = 1;</code>
+   * @return The isClick.
+   */
+  int getIsClick();
+
+  /**
+   * <code>int32 group_num = 2;</code>
+   * @return The groupNum.
+   */
+  int getGroupNum();
+
+  /**
+   * <code>int32 count = 3;</code>
+   * @return The count.
+   */
+  int getCount();
+
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature> 
+      getFeaturesList();
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature getFeatures(int index);
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  int getFeaturesCount();
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder> 
+      getFeaturesOrBuilderList();
+  /**
+   * <code>repeated .GroupedFeature features = 4;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeatureOrBuilder getFeaturesOrBuilder(
+      int index);
+
+  /**
+   * <code>double weight = 5;</code>
+   * @return The weight.
+   */
+  double getWeight();
+
+  /**
+   * <code>double predict_ctr = 6;</code>
+   * @return The predictCtr.
+   */
+  double getPredictCtr();
+}

+ 834 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRWeight.java

@@ -0,0 +1,834 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+/**
+ * Protobuf type {@code LRWeight}
+ */
+public final class LRWeight extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:LRWeight)
+    LRWeightOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use LRWeight.newBuilder() to construct.
+  private LRWeight(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private LRWeight() {
+    features_ = java.util.Collections.emptyList();
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new LRWeight();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private LRWeight(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    int mutable_bitField0_ = 0;
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 8: {
+
+            groupNum_ = input.readInt32();
+            break;
+          }
+          case 18: {
+            if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+              features_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature>();
+              mutable_bitField0_ |= 0x00000001;
+            }
+            features_.add(
+                input.readMessage(com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.parser(), extensionRegistry));
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      if (((mutable_bitField0_ & 0x00000001) != 0)) {
+        features_ = java.util.Collections.unmodifiableList(features_);
+      }
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRWeight_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRWeight_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.class, com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.Builder.class);
+  }
+
+  public static final int GROUP_NUM_FIELD_NUMBER = 1;
+  private int groupNum_;
+  /**
+   * <code>int32 group_num = 1;</code>
+   * @return The groupNum.
+   */
+  @java.lang.Override
+  public int getGroupNum() {
+    return groupNum_;
+  }
+
+  public static final int FEATURES_FIELD_NUMBER = 2;
+  private java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> features_;
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  @java.lang.Override
+  public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> getFeaturesList() {
+    return features_;
+  }
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  @java.lang.Override
+  public java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+      getFeaturesOrBuilderList() {
+    return features_;
+  }
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  @java.lang.Override
+  public int getFeaturesCount() {
+    return features_.size();
+  }
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getFeatures(int index) {
+    return features_.get(index);
+  }
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder getFeaturesOrBuilder(
+      int index) {
+    return features_.get(index);
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (groupNum_ != 0) {
+      output.writeInt32(1, groupNum_);
+    }
+    for (int i = 0; i < features_.size(); i++) {
+      output.writeMessage(2, features_.get(i));
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (groupNum_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(1, groupNum_);
+    }
+    for (int i = 0; i < features_.size(); i++) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(2, features_.get(i));
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.feature.model.sample.LRWeight)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.feature.model.sample.LRWeight other = (com.tzld.piaoquan.recommend.feature.model.sample.LRWeight) obj;
+
+    if (getGroupNum()
+        != other.getGroupNum()) return false;
+    if (!getFeaturesList()
+        .equals(other.getFeaturesList())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + GROUP_NUM_FIELD_NUMBER;
+    hash = (53 * hash) + getGroupNum();
+    if (getFeaturesCount() > 0) {
+      hash = (37 * hash) + FEATURES_FIELD_NUMBER;
+      hash = (53 * hash) + getFeaturesList().hashCode();
+    }
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.feature.model.sample.LRWeight prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code LRWeight}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:LRWeight)
+      com.tzld.piaoquan.recommend.feature.model.sample.LRWeightOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRWeight_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRWeight_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.class, com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+        getFeaturesFieldBuilder();
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      groupNum_ = 0;
+
+      if (featuresBuilder_ == null) {
+        features_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+      } else {
+        featuresBuilder_.clear();
+      }
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.CtrSamples.internal_static_LRWeight_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.LRWeight getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.LRWeight build() {
+      com.tzld.piaoquan.recommend.feature.model.sample.LRWeight result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.feature.model.sample.LRWeight buildPartial() {
+      com.tzld.piaoquan.recommend.feature.model.sample.LRWeight result = new com.tzld.piaoquan.recommend.feature.model.sample.LRWeight(this);
+      int from_bitField0_ = bitField0_;
+      result.groupNum_ = groupNum_;
+      if (featuresBuilder_ == null) {
+        if (((bitField0_ & 0x00000001) != 0)) {
+          features_ = java.util.Collections.unmodifiableList(features_);
+          bitField0_ = (bitField0_ & ~0x00000001);
+        }
+        result.features_ = features_;
+      } else {
+        result.features_ = featuresBuilder_.build();
+      }
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.feature.model.sample.LRWeight) {
+        return mergeFrom((com.tzld.piaoquan.recommend.feature.model.sample.LRWeight)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.feature.model.sample.LRWeight other) {
+      if (other == com.tzld.piaoquan.recommend.feature.model.sample.LRWeight.getDefaultInstance()) return this;
+      if (other.getGroupNum() != 0) {
+        setGroupNum(other.getGroupNum());
+      }
+      if (featuresBuilder_ == null) {
+        if (!other.features_.isEmpty()) {
+          if (features_.isEmpty()) {
+            features_ = other.features_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+          } else {
+            ensureFeaturesIsMutable();
+            features_.addAll(other.features_);
+          }
+          onChanged();
+        }
+      } else {
+        if (!other.features_.isEmpty()) {
+          if (featuresBuilder_.isEmpty()) {
+            featuresBuilder_.dispose();
+            featuresBuilder_ = null;
+            features_ = other.features_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+            featuresBuilder_ = 
+              com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ?
+                 getFeaturesFieldBuilder() : null;
+          } else {
+            featuresBuilder_.addAllMessages(other.features_);
+          }
+        }
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.feature.model.sample.LRWeight parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.feature.model.sample.LRWeight) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+    private int bitField0_;
+
+    private int groupNum_ ;
+    /**
+     * <code>int32 group_num = 1;</code>
+     * @return The groupNum.
+     */
+    @java.lang.Override
+    public int getGroupNum() {
+      return groupNum_;
+    }
+    /**
+     * <code>int32 group_num = 1;</code>
+     * @param value The groupNum to set.
+     * @return This builder for chaining.
+     */
+    public Builder setGroupNum(int value) {
+      
+      groupNum_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>int32 group_num = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearGroupNum() {
+      
+      groupNum_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> features_ =
+      java.util.Collections.emptyList();
+    private void ensureFeaturesIsMutable() {
+      if (!((bitField0_ & 0x00000001) != 0)) {
+        features_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature>(features_);
+        bitField0_ |= 0x00000001;
+       }
+    }
+
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> featuresBuilder_;
+
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> getFeaturesList() {
+      if (featuresBuilder_ == null) {
+        return java.util.Collections.unmodifiableList(features_);
+      } else {
+        return featuresBuilder_.getMessageList();
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public int getFeaturesCount() {
+      if (featuresBuilder_ == null) {
+        return features_.size();
+      } else {
+        return featuresBuilder_.getCount();
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getFeatures(int index) {
+      if (featuresBuilder_ == null) {
+        return features_.get(index);
+      } else {
+        return featuresBuilder_.getMessage(index);
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder setFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.set(index, value);
+        onChanged();
+      } else {
+        featuresBuilder_.setMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder setFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.set(index, builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.setMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder addFeatures(com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.add(value);
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder addFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature value) {
+      if (featuresBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureFeaturesIsMutable();
+        features_.add(index, value);
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder addFeatures(
+        com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.add(builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder addFeatures(
+        int index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder builderForValue) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.add(index, builderForValue.build());
+        onChanged();
+      } else {
+        featuresBuilder_.addMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder addAllFeatures(
+        java.lang.Iterable<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> values) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, features_);
+        onChanged();
+      } else {
+        featuresBuilder_.addAllMessages(values);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder clearFeatures() {
+      if (featuresBuilder_ == null) {
+        features_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+        onChanged();
+      } else {
+        featuresBuilder_.clear();
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public Builder removeFeatures(int index) {
+      if (featuresBuilder_ == null) {
+        ensureFeaturesIsMutable();
+        features_.remove(index);
+        onChanged();
+      } else {
+        featuresBuilder_.remove(index);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder getFeaturesBuilder(
+        int index) {
+      return getFeaturesFieldBuilder().getBuilder(index);
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder getFeaturesOrBuilder(
+        int index) {
+      if (featuresBuilder_ == null) {
+        return features_.get(index);  } else {
+        return featuresBuilder_.getMessageOrBuilder(index);
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+         getFeaturesOrBuilderList() {
+      if (featuresBuilder_ != null) {
+        return featuresBuilder_.getMessageOrBuilderList();
+      } else {
+        return java.util.Collections.unmodifiableList(features_);
+      }
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder addFeaturesBuilder() {
+      return getFeaturesFieldBuilder().addBuilder(
+          com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder addFeaturesBuilder(
+        int index) {
+      return getFeaturesFieldBuilder().addBuilder(
+          index, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .BaseFeature features = 2;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder> 
+         getFeaturesBuilderList() {
+      return getFeaturesFieldBuilder().getBuilderList();
+    }
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+        getFeaturesFieldBuilder() {
+      if (featuresBuilder_ == null) {
+        featuresBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<
+            com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature.Builder, com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder>(
+                features_,
+                ((bitField0_ & 0x00000001) != 0),
+                getParentForChildren(),
+                isClean());
+        features_ = null;
+      }
+      return featuresBuilder_;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:LRWeight)
+  }
+
+  // @@protoc_insertion_point(class_scope:LRWeight)
+  private static final com.tzld.piaoquan.recommend.feature.model.sample.LRWeight DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.feature.model.sample.LRWeight();
+  }
+
+  public static com.tzld.piaoquan.recommend.feature.model.sample.LRWeight getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<LRWeight>
+      PARSER = new com.google.protobuf.AbstractParser<LRWeight>() {
+    @java.lang.Override
+    public LRWeight parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new LRWeight(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<LRWeight> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<LRWeight> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.feature.model.sample.LRWeight getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 39 - 0
recommend-feature-client/src/main/java/com/tzld/piaoquan/recommend/feature/model/sample/LRWeightOrBuilder.java

@@ -0,0 +1,39 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/feature/ctr_samples.proto
+
+package com.tzld.piaoquan.recommend.feature.model.sample;
+
+public interface LRWeightOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:LRWeight)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>int32 group_num = 1;</code>
+   * @return The groupNum.
+   */
+  int getGroupNum();
+
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  java.util.List<com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature> 
+      getFeaturesList();
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature getFeatures(int index);
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  int getFeaturesCount();
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  java.util.List<? extends com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder> 
+      getFeaturesOrBuilderList();
+  /**
+   * <code>repeated .BaseFeature features = 2;</code>
+   */
+  com.tzld.piaoquan.recommend.feature.model.sample.BaseFeatureOrBuilder getFeaturesOrBuilder(
+      int index);
+}

+ 49 - 0
recommend-feature-client/src/main/proto/com/tzld/piaoquan/recommend/feature/ctr_samples.proto

@@ -0,0 +1,49 @@
+syntax = "proto3";
+
+
+option java_multiple_files = true;
+option java_package = "com.tzld.piaoquan.recommend.feature.model.sample";
+option java_generic_services = true;
+
+
+
+message FeatureGroup {
+    string type = 1;
+    int32 id = 2;
+    string name = 3;
+    string field = 4;
+}
+
+message BaseFeature {
+    int64 id = 1;
+    int64 identifier = 2;
+    string fea = 3;
+    double value = 4;
+    double weight =5;
+}
+
+
+message GroupedFeature {
+    FeatureGroup group = 1;
+    int32 count = 2;
+    repeated BaseFeature features = 3;
+}
+
+
+
+message LRWeight {
+    int32 group_num = 1;
+    repeated BaseFeature features = 2;
+}
+
+
+
+message LRSamples {
+    int32 is_click = 1;
+    int32 group_num = 2;
+    int32 count = 3;
+    repeated GroupedFeature features = 4;
+    double weight = 5;
+    double predict_ctr = 6;
+}
+

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

@@ -9,7 +9,7 @@ option java_generic_services = true;
 
 
 message GetUserFeatureRequest {
-  string uid = 1;
+  string mid = 1;
 }
 
 message GetUserFeatureResponse {

+ 110 - 14
recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/model/AdItemFeature.java

@@ -25,6 +25,7 @@ public class AdItemFeature {
     @Setter
     @NotNull
     private String advertiserCode = "0";
+
     @Setter
     @NotNull
     private String campaignId = "0";
@@ -42,39 +43,134 @@ public class AdItemFeature {
     private String creativeCode = "0";
 
 
-
+    // adid 计划维度统计信息
     // 当天统计量信息
-    private AdActionFeature day1_cnt_features;
+    @Setter
+    @NotNull
+    private AdActionFeature day1_cnt_features = new AdActionFeature();
     // 3天内统计量
-    private AdActionFeature day3_cnt_features;
+    @Setter
+    @NotNull
+    private AdActionFeature day3_cnt_features = new AdActionFeature();
     // 7天内统计量
-    private AdActionFeature day7_cnt_features;
+    @Setter
+    @NotNull
+    private AdActionFeature day7_cnt_features = new AdActionFeature();
     // 3个月统计量
-    private AdActionFeature month3_cnt_features;
+    @Setter
+    @NotNull
+    private AdActionFeature month3_cnt_features = new AdActionFeature();
+
+
+    // 创意维度统计信息
+    @Setter
+    @NotNull
+    private AdActionFeature creative_1day_cnt_features = new AdActionFeature();
+    @Setter
+    @NotNull
+    private AdActionFeature creative_3day_cnt_features = new AdActionFeature();
+    @Setter
+    @NotNull
+    private AdActionFeature creative_7day_cnt_features = new AdActionFeature();
+    @Setter
+    @NotNull
+    private AdActionFeature creative_3month_cnt_features = new AdActionFeature();
+
+    // 广告主维度统计信息
+    @Setter
+    @NotNull
+    private AdActionFeature advertiser_1day_cnt_features = new AdActionFeature();
+    @Setter
+    @NotNull
+    private AdActionFeature advertiser_3day_cnt_features = new AdActionFeature();
+    @Setter
+    @NotNull
+    private AdActionFeature advertiser_7day_cnt_features = new AdActionFeature();
+    @Setter
+    @NotNull
+    private AdActionFeature advertiser_3month_cnt_features = new AdActionFeature();
+
+
+    public void setAdId(String key) {
+        if (key == null) {
+            this.adId = "0";
+        } else {
+            this.adId = key;
+        }
+    }
+
+
+    public void setAdvertiserId(String key) {
+        if (key == null) {
+            this.advertiserId = "0";
+        } else {
+            this.advertiserId = key;
+        }
+    }
+
+    public void setCampaignId(String key) {
+        if (key == null) {
+            this.campaignId = "0";
+        } else {
+            this.campaignId = key;
+        }
+    }
+
+
+    public void setCreativeId(String key) {
+        if (key == null) {
+            this.creativeId = "0";
+        } else {
+            this.creativeId = key;
+        }
+    }
+
+
+    //creative
+    public void setCreative_1day_cnt_features(AdActionFeature feature) {
+        this.creative_1day_cnt_features = feature;
+    }
+
+
+    public void setCreative_3day_cnt_features(AdActionFeature feature) {
+        this.creative_3day_cnt_features = feature;
+
+    }
+
+    public void setCreative_7day_cnt_features(AdActionFeature feature) {
+        this.creative_7day_cnt_features = feature;
+
+    }
+
+    public void setCreative_3month_cnt_features(AdActionFeature feature) {
+        this.creative_3month_cnt_features = feature;
+
+    }
 
 
-    public void setDay1_cnt_features(AdActionFeature feature) {
-        this.day1_cnt_features = feature;
+    // advertiser 维度
+    public void setAdvertiser_1day_cnt_features(AdActionFeature feature) {
+        this.advertiser_1day_cnt_features = feature;
     }
 
 
-    public void setDay3_cnt_features(AdActionFeature feature) {
-        this.day3_cnt_features = feature;
+    public void setAdvertiser_3day_cnt_features(AdActionFeature feature) {
+        this.advertiser_3day_cnt_features = feature;
 
     }
 
-    public void setDay7_cnt_features(AdActionFeature feature) {
-        this.day7_cnt_features = feature;
+    public void setAdvertiser_7day_cnt_features(AdActionFeature feature) {
+        this.advertiser_7day_cnt_features = feature;
 
     }
 
-    public void setMonth3_cnt_features(AdActionFeature feature) {
-        this.month3_cnt_features = feature;
+    public void setAdvertiser_3month_cnt_features(AdActionFeature feature) {
+        this.advertiser_3month_cnt_features = feature;
 
     }
 
     public String getKey() {
-        return this.adId;
+        return this.creativeId;
     }
 
     public String getValue() {

+ 22 - 15
recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/model/UserFeature.java

@@ -8,6 +8,7 @@ import lombok.Data;
 @Data
 public class UserFeature {
     private String uid;
+    private String mid;
     // 当天统计量信息
     private UserActionFeature day1_cnt_features;
     // 3天内统计量
@@ -21,53 +22,59 @@ public class UserFeature {
     private String user_cycle_bucket_30days;
     private String user_share_bucket_30days;
 
-    public void setUid(String key){
+    public void setMid(String key) {
+        this.mid = key;
+        if (key == null)
+            this.mid = "0";
+    }
+
+    public void setUid(String key) {
         this.uid = key;
-        if(key == null)
+        if (key == null)
             this.uid = "0";
     }
 
 
-    public void setDay1_cnt_features(UserActionFeature key){
+    public void setDay1_cnt_features(UserActionFeature key) {
         this.day1_cnt_features = key;
-        if(key == null)
+        if (key == null)
             this.day1_cnt_features = new UserActionFeature();
     }
 
-    public void setDay3_cnt_features(UserActionFeature key){
+    public void setDay3_cnt_features(UserActionFeature key) {
         this.day3_cnt_features = key;
-        if(key == null)
+        if (key == null)
             this.day3_cnt_features = new UserActionFeature();
     }
 
-    public void setDay7_cnt_features(UserActionFeature key){
+    public void setDay7_cnt_features(UserActionFeature key) {
         this.day7_cnt_features = key;
-        if(key == null)
+        if (key == null)
             this.day7_cnt_features = new UserActionFeature();
     }
 
     public void setMonth3_cnt_features(UserActionFeature key) {
         this.month3_cnt_features = key;
-        if(key == null)
+        if (key == null)
             this.month3_cnt_features = new UserActionFeature();
     }
 
 
-    public void setUser_cycle_bucket_7days(String key){
+    public void setUser_cycle_bucket_7days(String key) {
         this.user_cycle_bucket_7days = key;
-        if(key == null)
+        if (key == null)
             this.user_cycle_bucket_7days = "0";
     }
 
-    public void setUser_cycle_bucket_30days(String key){
+    public void setUser_cycle_bucket_30days(String key) {
         this.user_cycle_bucket_30days = key;
-        if(key == null)
+        if (key == null)
             this.user_cycle_bucket_30days = "0";
     }
 
-    public void setUser_share_bucket_30days(String key){
+    public void setUser_share_bucket_30days(String key) {
         this.user_share_bucket_30days = key;
-        if(key == null)
+        if (key == null)
             this.user_share_bucket_30days = "0";
     }
 

+ 4 - 3
recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/service/FeatureConverter.java

@@ -14,6 +14,7 @@ public class FeatureConverter {
         }
         UserFeatureProto.Builder builder = UserFeatureProto.newBuilder();
         builder.setUid(Strings.nullToEmpty(userFeature.getUid()))
+                .setMid(Strings.nullToEmpty(userFeature.getMid()))
                 .setUserCycleBucket7Day(Strings.nullToEmpty(userFeature.getUser_cycle_bucket_7days()))
                 .setUserCycleBucket30Day(Strings.nullToEmpty(userFeature.getUser_cycle_bucket_30days()))
                 .setUserShareBucket30Day(Strings.nullToEmpty(userFeature.getUser_share_bucket_30days()));
@@ -82,7 +83,7 @@ public class FeatureConverter {
 
     public static UserAdFeatureProto convertToProto(UserAdFeature userAdFeature) {
         UserAdFeatureProto.Builder builder = UserAdFeatureProto.newBuilder();
-        if(userAdFeature==null) return builder.build();
+        if (userAdFeature == null) return builder.build();
         builder.setMid(userAdFeature.getMid());
         builder.setGender(userAdFeature.getGender());
         builder.setUserType(userAdFeature.getUser_type());
@@ -131,7 +132,7 @@ public class FeatureConverter {
     public static AdActionFeatureProto convertToProto(AdActionFeature adActionFeature) {
 
         AdActionFeatureProto.Builder builder = AdActionFeatureProto.newBuilder();
-        if(adActionFeature==null) return builder.build();
+        if (adActionFeature == null) return builder.build();
         builder.setAdView(adActionFeature.getAdView());
         builder.setAdClick(adActionFeature.getAdClick());
         builder.setAdConversion(adActionFeature.getAdConversion());
@@ -141,7 +142,7 @@ public class FeatureConverter {
     }
 
     public static AdItemFeatureProto convertToProto(AdItemFeature adItemFeature) {
-        if(adItemFeature==null) return null;
+        if (adItemFeature == null) return null;
         AdItemFeatureProto.Builder builder = AdItemFeatureProto.newBuilder();
         builder.setAdId(adItemFeature.getAdId());
         builder.setAdCode(adItemFeature.getAdCode());

+ 3 - 3
recommend-feature-service/src/main/java/com/tzld/piaoquan/recommend/feature/service/UserFeatureService.java

@@ -33,13 +33,13 @@ public class UserFeatureService extends AbstractFeatureService<String, UserFeatu
 
 
     public GetUserFeatureResponse getUserFeature(GetUserFeatureRequest request) {
-        String uid = request.getUid();
-        if (StringUtils.isBlank(uid)) {
+        String mid = request.getMid();
+        if (StringUtils.isBlank(mid)) {
             return GetUserFeatureResponse.newBuilder()
                     .setResult(Result.newBuilder().setCode(1))
                     .build();
         }
-        UserFeature userFeature = super.get(uid);
+        UserFeature userFeature = super.get(mid);
         GetUserFeatureResponse.Builder builder = GetUserFeatureResponse.newBuilder();
         builder.setResult(Result.newBuilder().setCode(1));
         if (userFeature != null) {

+ 1 - 1
recommend-feature-service/src/main/resources/application-dev.yml

@@ -18,7 +18,7 @@ eureka:
 
 spring:
   redis:
-    hostName: r-bp1pi8wyv6lzvgjy5z.redis.rds.aliyuncs.com
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
     port: 6379
     password: Wqsd@2019
     timeout: 1000