Browse Source

feat:VOV排序迭代

zhaohaipeng 6 tháng trước cách đây
mục cha
commit
bcc61e8e51

+ 197 - 83
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankStrategy4RegionMergeModelV565.java

@@ -1,6 +1,7 @@
 package com.tzld.piaoquan.recommend.server.service.rank.strategy;
 
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
 import com.tzld.piaoquan.recommend.server.common.base.RankItem;
 import com.tzld.piaoquan.recommend.server.model.Video;
 import com.tzld.piaoquan.recommend.server.service.FeatureService;
@@ -11,7 +12,9 @@ import com.tzld.piaoquan.recommend.server.service.score.ScorerUtils;
 import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.math3.util.Pair;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.io.BufferedReader;
@@ -19,6 +22,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.*;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Service
@@ -26,13 +31,15 @@ import java.util.stream.Collectors;
 public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeModelBasic {
     @ApolloJsonValue("${rank.score.merge.weightv565:}")
     private Map<String, Double> mergeWeight;
-
     @Autowired
     private FeatureService featureService;
 
     Map<String, double[]> bucketsMap = new HashMap<>();
     Map<String, Double> bucketsLen = new HashMap<>();
 
+    @Value("${similarity.concurrent: false}")
+    private boolean similarityConcurrent;
+
     @Override
     public List<Video> mergeAndRankRovRecall(RankParam param) {
         Map<String, Double> mergeWeight = this.mergeWeight != null ? this.mergeWeight : new HashMap<>(0);
@@ -69,13 +76,12 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
         rovRecallRank.addAll(v1);
         setVideo.addAll(v1.stream().map(Video::getVideoId).collect(Collectors.toSet()));
 
-
         //-------------------排-------------------
         //-------------------序-------------------
         //-------------------逻-------------------
         //-------------------辑-------------------
 
-        // TODO 1 批量获取特征  省份参数要对齐  headvid  要传递过来!
+        // 1 批量获取特征  省份参数要对齐  headvid  要传递过来!
         List<String> vids = CommonCollectionUtils.toListDistinct(rovRecallRank, v -> String.valueOf(v.getVideoId()));
 
         // k1:视频、k2:表、k3:特征、v:特征值
@@ -87,7 +93,7 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
         Map<String, Map<String, Map<String, String>>> featureOriginVideo = feature.getVideoFeature();
 
 
-        // TODO 2 特征处理
+        // 2 特征处理
         Map<String, Double> userFeatureMapDouble = new HashMap<>();
         String mid = param.getMid();
         Map<String, String> c1 = featureOriginUser.getOrDefault("alg_mid_feature_play", new HashMap<>());
@@ -95,8 +101,8 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
         Map<String, String> c3 = featureOriginUser.getOrDefault("alg_mid_feature_play_tags", new HashMap<>());
         Map<String, String> c4 = featureOriginUser.getOrDefault("alg_mid_feature_return_tags", new HashMap<>());
         Map<String, String> c5 = featureOriginUser.getOrDefault("alg_mid_feature_share_tags", new HashMap<>());
-        Map<String, String> c6 = featureOriginUser.getOrDefault("alg_mid_feature_feed_exp_share_tags", new HashMap<>());
-        Map<String, String> c7 = featureOriginUser.getOrDefault("alg_mid_feature_feed_exp_return_tags", new HashMap<>());
+        Map<String, String> c6 = featureOriginUser.getOrDefault("alg_mid_feature_feed_exp_share_tags_v2", new HashMap<>());
+        Map<String, String> c7 = featureOriginUser.getOrDefault("alg_mid_feature_feed_exp_return_tags_v2", new HashMap<>());
         Map<String, String> c8 = featureOriginUser.getOrDefault("alg_mid_feature_sharecf", new HashMap<>());
         Map<String, String> c9 = featureOriginUser.getOrDefault("alg_mid_feature_returncf", new HashMap<>());
 
@@ -166,21 +172,21 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
         for (RankItem item : rankItems) {
             Map<String, Double> featureMap = new HashMap<>();
             String vid = item.getVideoId() + "";
-            Map<String, String> b1 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_all_exp", new HashMap<>());
+            Map<String, String> b1 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_all_exp_v2", new HashMap<>());
             Map<String, String> b2 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_all_share", new HashMap<>());
             Map<String, String> b3 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_all_return", new HashMap<>());
-            Map<String, String> b6 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_exp2share", new HashMap<>());
+            Map<String, String> b6 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_exp2share_v2", new HashMap<>());
             Map<String, String> b7 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_share2return", new HashMap<>());
 
-            Map<String, String> b8 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_noflow_exp", new HashMap<>());
-            Map<String, String> b9 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_noflow_root_share", new HashMap<>());
-            Map<String, String> b10 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_noflow_root_return", new HashMap<>());
-            Map<String, String> b11 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_flow_exp", new HashMap<>());
-            Map<String, String> b12 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_flow_root_share", new HashMap<>());
-            Map<String, String> b13 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_flow_root_return", new HashMap<>());
-            Map<String, String> b17 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_province_exp", new HashMap<>());
-            Map<String, String> b18 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_province_root_share", new HashMap<>());
-            Map<String, String> b19 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_province_root_return", new HashMap<>());
+            Map<String, String> b8 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_noflow_exp_v2", new HashMap<>());
+            Map<String, String> b9 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_noflow_root_share_v2", new HashMap<>());
+            Map<String, String> b10 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_noflow_root_return_v2", new HashMap<>());
+            Map<String, String> b11 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_flow_exp_v2", new HashMap<>());
+            Map<String, String> b12 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_flow_root_share_v2", new HashMap<>());
+            Map<String, String> b13 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_flow_root_return_v2", new HashMap<>());
+            Map<String, String> b17 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_province_exp_v2", new HashMap<>());
+            Map<String, String> b18 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_province_root_share_v2", new HashMap<>());
+            Map<String, String> b19 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_vid_feature_feed_province_root_return_v2", new HashMap<>());
 
             List<Tuple4> originData = Arrays.asList(
                     new Tuple4(b1, b2, b3, "b123"),
@@ -222,14 +228,41 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
 
             String title = videoInfo.getOrDefault("title", "");
             if (!title.isEmpty()) {
-                for (String name : Arrays.asList("c3_feature", "c4_feature", "c5_feature", "c6_feature", "c7_feature")) {
-                    for (String key_time : Arrays.asList("tags_1d", "tags_3d", "tags_7d")) {
-                        String tags = c34567Map.getOrDefault(name + "_" + key_time, "");
-                        if (!tags.isEmpty()) {
-                            Double[] doubles = ExtractorUtils.funcC34567ForTags(tags, title);
-                            featureMap.put(name + "_" + key_time + "_matchnum", doubles[0]);
-                            featureMap.put(name + "_" + key_time + "_maxscore", doubles[1]);
-                            featureMap.put(name + "_" + key_time + "_avgscore", doubles[2]);
+                if (similarityConcurrent) {
+                    List<Future<Pair<String, Double[]>>> futures = new ArrayList<>();
+                    for (String name : Arrays.asList("c3_feature", "c4_feature", "c5_feature", "c6_feature", "c7_feature")) {
+                        for (String key_time : Arrays.asList("tags_1d", "tags_3d", "tags_7d")) {
+                            String key = name + "_" + key_time;
+                            String tags = c34567Map.getOrDefault(key, "");
+                            if (!tags.isEmpty()) {
+                                Future<Pair<String, Double[]>> future = ThreadPoolFactory.defaultPool().submit(() -> {
+                                    Double[] doubles = ExtractorUtils.funcC34567ForTags(tags, title);
+                                    return Pair.create(key, doubles);
+                                });
+                                futures.add(future);
+                            }
+                        }
+                    }
+                    try {
+                        for (Future<Pair<String, Double[]>> future : futures) {
+                            Pair<String, Double[]> pair = future.get(1000, TimeUnit.MILLISECONDS);
+                            featureMap.put(pair.getFirst() + "_matchnum", pair.getSecond()[0]);
+                            featureMap.put(pair.getFirst() + "_maxscore", pair.getSecond()[1]);
+                            featureMap.put(pair.getFirst() + "_avgscore", pair.getSecond()[2]);
+                        }
+                    } catch (Exception e) {
+                        log.error("concurrent similarity error", e);
+                    }
+                } else {
+                    for (String name : Arrays.asList("c3_feature", "c4_feature", "c5_feature", "c6_feature", "c7_feature")) {
+                        for (String key_time : Arrays.asList("tags_1d", "tags_3d", "tags_7d")) {
+                            String tags = c34567Map.getOrDefault(name + "_" + key_time, "");
+                            if (!tags.isEmpty()) {
+                                Double[] doubles = ExtractorUtils.funcC34567ForTags(tags, title);
+                                featureMap.put(name + "_" + key_time + "_matchnum", doubles[0]);
+                                featureMap.put(name + "_" + key_time + "_maxscore", doubles[1]);
+                                featureMap.put(name + "_" + key_time + "_avgscore", doubles[2]);
+                            }
                         }
                     }
                 }
@@ -251,7 +284,7 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
                     }
                 }
             }
-            Map<String, String> d1 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_recsys_feature_cf_i2i_new", new HashMap<>());
+            Map<String, String> d1 = featureOriginVideo.getOrDefault(vid, new HashMap<>()).getOrDefault("alg_recsys_feature_cf_i2i_new_v2", new HashMap<>());
             if (!d1.isEmpty()) {
                 featureMap.put("d1_exp", Double.parseDouble(d1.getOrDefault("exp", "0")));
                 featureMap.put("d1_return_n", Double.parseDouble(d1.getOrDefault("return_n", "0")));
@@ -293,32 +326,109 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
             item.featureMap = featureMap;
         }
 
-        // TODO 3 排序
+        // 3 排序
         Map<String, String> sceneFeatureMap = new HashMap<>(0);
 
-        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_20240609.conf")
+        List<RankItem> items = ScorerUtils.getScorerPipeline("feeds_score_config_20240807.conf")
                 .scoring(sceneFeatureMap, userFeatureMap, rankItems);
-        String redisScoreKey =  mergeWeight.getOrDefault("redisScoreKey", 0.0) < 0.5 ? "redis:vid_hasreturn_rov:" : "redis:vid_hasreturn_rov_7d:";
-        Map<String, Map<String, String>> vid2MapFeature = this.getVideoRedisFeature(vids, redisScoreKey);
+
+
+        // 获取VoV预测模型参数
+        // 融合权重
+        double alpha_vov = mergeWeight.getOrDefault("alpha_vov", 1.0);
+
+        double vov_thresh = mergeWeight.getOrDefault("vov_thresh", -1d);
+
+        double view_thresh = mergeWeight.getOrDefault("view_thresh", 1500.0);
+
+        double level50_vov = mergeWeight.getOrDefault("level50_vov", 0.08);
+
+        double level_95_vov = mergeWeight.getOrDefault("level_95_vov", 0.178);
+
+        double beta_vov = mergeWeight.getOrDefault("beta_vov", 10.0);
+
+        List<Double> weightList = new ArrayList<>(3);
+        // weightList.add(mergeWeight.getOrDefault("d2_ago_vov_w", 0.0));
+        // weightList.add(mergeWeight.getOrDefault("d1_ago_vov_w", 0.0));
+        // weightList.add(mergeWeight.getOrDefault("h48_ago_vov_w", 0.0));
+        // weightList.add(mergeWeight.getOrDefault("h24_ago_vov_w", 0.0));
+        weightList.add(mergeWeight.getOrDefault("h3_ago_vov_w", 0.0));
+        weightList.add(mergeWeight.getOrDefault("h2_ago_vov_w", 0.0));
+        weightList.add(mergeWeight.getOrDefault("h1_ago_vov_w", 0.0));
+
+
+
+        Map<String, Map<String, String>> vid2MapFeature = this.getVideoRedisFeature(vids, "redis:vid_hasreturn_rov:");
+        Map<String, Map<String, String>> vid2VovFeatureMap = this.getVideoRedisFeature(vids, "redis:vid_vovhour4rank:");
         List<Video> result = new ArrayList<>();
-        String hasReturnRovKey = mergeWeight.getOrDefault("hasReturnRovKey", 1.0) < 0.5 ? "rate_1" : "rate_n";
-        Double chooseFunction = mergeWeight.getOrDefault("chooseFunction", 0.0);
-        Double rosDefault = mergeWeight.getOrDefault("rosDefault", 0.1);
+//        String hasReturnRovKey = mergeWeight.getOrDefault("hasReturnRovKey", 1.0) < 0.5 ? "rate_1" : "rate_n";
+//        Double chooseFunction = mergeWeight.getOrDefault("chooseFunction", 0.0);
 
         for (RankItem item : items) {
             double score = 0.0;
+            // 获取其他模型输出score
+            double fmRovOrigin = item.getScoreRov();
+            item.getScoresMap().put("fmRovOrigin", fmRovOrigin);
+            double fmRov = restoreScore(fmRovOrigin);
+            item.getScoresMap().put("fmRov", fmRov);
+
+
+            // 获取VoV输入特征
+            double h1_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("h1_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+            double h2_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("h2_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+            double h3_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("h3_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+            double h24_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("h24_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+            double h48_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("h48_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+            double d1_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("d1_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+            double d2_ago_vov = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("d2_ago_vov", "-2")); // 如果没有时,默认为多少?? 需要考虑
+
+            double h1_ago_view = Double.parseDouble(vid2VovFeatureMap.getOrDefault(item.getVideoId() + "", new HashMap<>())
+                    .getOrDefault("h1_ago_view", "-2")); // 如果没有时,默认为多少?? 需要考虑
+
+            item.getScoresMap().put("h1_ago_vov", h1_ago_vov);
+            item.getScoresMap().put("h2_ago_vov", h2_ago_vov);
+            item.getScoresMap().put("h3_ago_vov", h3_ago_vov);
+            item.getScoresMap().put("h24_ago_vov", h24_ago_vov);
+            item.getScoresMap().put("h48_ago_vov", h48_ago_vov);
+            item.getScoresMap().put("d1_ago_vov", d1_ago_vov);
+            item.getScoresMap().put("d2_ago_vov", d2_ago_vov);
+
+            item.getScoresMap().put("h1_ago_view", h1_ago_view);
+            item.getScoresMap().put("alpha_vov", alpha_vov);
+            item.getScoresMap().put("view_thresh", view_thresh);
+            item.getScoresMap().put("vov_thresh", vov_thresh);
+
+
+
+            List<Double> featureList = new ArrayList<>(3);
+            // featureList.add(d2_ago_vov);
+            // featureList.add(d1_ago_vov);
+            // featureList.add(h48_ago_vov);
+            // featureList.add(h24_ago_vov);
+            featureList.add(h3_ago_vov);
+            featureList.add(h2_ago_vov);
+            featureList.add(h1_ago_vov);
+
+            // todo 线性加权 预测VoV
+
+
+            double vov_p = calculateScore(featureList, weightList, item, vov_thresh, view_thresh, h1_ago_view, level50_vov, level_95_vov, beta_vov);
+
+
             double hasReturnRovScore = Double.parseDouble(vid2MapFeature.getOrDefault(item.getVideoId() + "", new HashMap<>())
-                    .getOrDefault(hasReturnRovKey, "0"));
+                    .getOrDefault("rate_n", "0"));
             item.getScoresMap().put("hasReturnRovScore", hasReturnRovScore);
-            double fmRov = item.getScoreRov();
-            item.getScoresMap().put("fmRov", fmRov);
-            if (chooseFunction == 0){
-                score = fmRov * (rosDefault + hasReturnRovScore);
-            }else if (chooseFunction == 1){
-                score = fmRov * (1 + Math.log(hasReturnRovScore + 1));
-            }else {
-                score = fmRov * (1 + hasReturnRovScore);
-            }
+            score = fmRov * (1 + hasReturnRovScore)  * (1.0 + alpha_vov * vov_p);
+
+
+            item.getScoresMap().put("vov_p", vov_p);
 
             Video video = item.getVideo();
             video.setScore(score);
@@ -341,23 +451,55 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
         return result;
     }
 
-    private Map<String, Map<String, String>> extractVideoFeature(Map<String, Map<String, Map<String, String>>> featureMap) {
-        // TODO
-        return null;
-    }
 
-    private Map<String, String> extractSceneFeature(Map<String, Map<String, Map<String, String>>> featureMap) {
-        // TODO
-        return null;
-    }
+    private  double calculateScore(List<Double> featureList, List<Double> weightList,RankItem rankItem,
+                                   double vov_thresh, double view_thresh, double h1_ago_view,double level50_vov,double level_95_vov,double beta_vov) {
+        // 检查 h1_ago_view 条件
+        if (h1_ago_view == -2 || h1_ago_view == -1 || h1_ago_view < view_thresh) {
+            rankItem.getScoresMap().put("origin_vov_p", 0d);
+            return 0;
+        }
 
-    private Map<String, String> extractUserFeature(Map<String, Map<String, Map<String, String>>> featureMap) {
-        // TODO
-        return null;
+        // // 检查 featureList 是否全为 -1
+        // if (featureList.stream().allMatch(f -> f == -1)) {
+        //     rankItem.getScoresMap().put("origin_vov_p", 0d);
+        //     return 0;
+        // }
+
+        // 计算有效特征的总权重和得分
+        double score = 0;
+        List<Integer> validIndices = new ArrayList<>();
+
+        for (int i = 0; i < featureList.size(); i++) {
+            if (featureList.get(i) != -1) {
+                validIndices.add(i);
+            }
+        }
+
+        // 如果没有有效特征,返回 0
+        if (validIndices.isEmpty()) {
+            rankItem.getScoresMap().put("origin_vov_p", 0d);
+            return 0;
+        }
+
+        // 计算得分,动态调整权重
+        for (int index : validIndices) {
+            double weight = weightList.get(index);
+            score += featureList.get(index) * weight;
+        }
+        rankItem.getScoresMap().put("origin_vov_p", score);
+        // 调整vov
+        if (score < vov_thresh) {
+            score = 0;
+        } else {
+            score = 1 / (1 + Math.exp(-1 * beta_vov * (score - level50_vov)));
+        }
+        return score;
     }
 
+
     private void readBucketFile() {
-        InputStream resourceStream = RankStrategy4RegionMergeModelV999.class.getClassLoader().getResourceAsStream("20240609_bucket_274.txt");
+        InputStream resourceStream = RankStrategy4RegionMergeModelV562.class.getClassLoader().getResourceAsStream("20240609_bucket_274.txt");
         if (resourceStream != null) {
             try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream))) {
                 Map<String, double[]> bucketsMap = new HashMap<>();
@@ -387,35 +529,7 @@ public class RankStrategy4RegionMergeModelV565 extends RankStrategy4RegionMergeM
         } else {
             log.error("no bucket file");
         }
-
     }
 
-    static class Tuple4 {
-        public Map<String, String> first;
-        public Map<String, String> second;
-        public Map<String, String> third;
-
-        public String name;
-
-        public Tuple4(Map<String, String> first, Map<String, String> second, Map<String, String> third, String name) {
-            this.first = first;
-            this.second = second;
-            this.third = third;
-            this.name = name;
-        }
-
-    }
-
-    static class Tuple2 {
-        public Map<String, String> first;
-
-        public String name;
-
-        public Tuple2(Map<String, String> first, String name) {
-            this.first = first;
-            this.name = name;
-        }
-
-    }
 
 }