gufengshou1 1 yıl önce
ebeveyn
işleme
bf75b6b8fc
40 değiştirilmiş dosya ile 1613 ekleme ve 635 silme
  1. 15 82
      ad-engine-commons/pom.xml
  2. 0 149
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/RedisTemplateConfig.java
  3. 6 1
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AdOwnRedisHelper.java
  4. 9 1
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AlgorithmRedisHelper.java
  5. 2 1
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/CommonCollectionUtils.java
  6. 3 2
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/HttpClientFactory.java
  7. 3 3
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/JSONUtils.java
  8. 10 5
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/Application.java
  9. 4 5
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/controller/ControllerAspect.java
  10. 46 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/controller/PredictController.java
  11. 0 28
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonCollectionUtils.java
  12. 0 8
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonTypeToken.java
  13. 0 30
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/DateUtils.java
  14. 0 136
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/HttpClientFactory.java
  15. 0 38
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/JSONUtils.java
  16. 0 48
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/TraceUtils.java
  17. 0 94
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/RecommendController.java
  18. 1 1
      ad-engine-server/src/main/resources/application-dev.yml
  19. 3 3
      ad-engine-server/src/main/resources/application.yml
  20. 14 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/PredictModelService.java
  21. 20 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/calculator/ThresholdPredictCalculator.java
  22. 620 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/config/AbConfig.java
  23. 14 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/config/AdOutV1OnlineWeightConfig.java
  24. 22 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/config/RuleRedisKeyConst.java
  25. 98 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/impl/PredictModelServiceImpl.java
  26. 4 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/Model.java
  27. 34 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/containner/ThresholdModelContainer.java
  28. 87 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/AddThresholdPredictModel.java
  29. 93 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/BasicThresholdPredictModel.java
  30. 92 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/MultiplyThresholdPredictModel.java
  31. 29 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/RoiThresholdPredictModel.java
  32. 98 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/ScoreThresholdPredictModel.java
  33. 24 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/ThresholdPredictModel.java
  34. 151 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/RuleParamHelper.java
  35. 19 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/ThresholdCalculateParam.java
  36. 33 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/ThresholdPredictModelParam.java
  37. 13 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/AdCheckShowAdDto.java
  38. 15 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/RoiPredictModelRequestParam.java
  39. 21 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/ThresholdPredictModelRequestParam.java
  40. 10 0
      pom.xml

+ 15 - 82
ad-engine-commons/pom.xml

@@ -11,89 +11,22 @@
 
     <artifactId>ad-engine-commons</artifactId>
     <version>1.0.0</version>
-
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
     <dependencies>
-        <dependency>
-            <groupId>net.devh</groupId>
-            <artifactId>grpc-client-spring-boot-starter</artifactId>
-            <version>2.9.0.RELEASE</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java</artifactId>
-            <version>3.12.0</version>
-        </dependency>
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <version>1.16.8</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java-util</artifactId>
-            <version>3.6.0</version>
-            <exclusions>
-                <exclusion>
-                    <artifactId>protobuf-java</artifactId>
-                    <groupId>com.google.protobuf</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>net.devh</groupId>-->
+<!--            <artifactId>grpc-client-spring-boot-starter</artifactId>-->
+<!--            <version>2.9.0.RELEASE</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.projectlombok</groupId>-->
+<!--            <artifactId>lombok</artifactId>-->
+<!--            <version>1.18.22</version>-->
+<!--        </dependency>-->
     </dependencies>
-    <build>
-        <extensions>
-            <extension>
-                <groupId>kr.motd.maven</groupId>
-                <artifactId>os-maven-plugin</artifactId>
-                <version>1.6.0</version>
-            </extension>
-        </extensions>
-        <plugins>
-            <plugin>
-                <groupId>org.xolstice.maven.plugins</groupId>
-                <artifactId>protobuf-maven-plugin</artifactId>
-                <version>0.6.1</version>
-                <configuration>
-                    <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
-                    <pluginId>grpc-java</pluginId>
-                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier}</pluginArtifact>
-                    <!--设置grpc生成代码到指定路径-->
-                    <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
-                    <!--生成代码前是否清空目录-->
-                    <clearOutputDirectory>false</clearOutputDirectory>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>compile</goal>
-                            <goal>compile-custom</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-
-            <!-- 设置多个源文件夹 -->
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <version>3.0.0</version>
-                <executions>
-                    <!-- 添加主源码目录 -->
-                    <execution>
-                        <id>add-source</id>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>${project.basedir}/src/main/java</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
 
-        </plugins>
-    </build>
 </project>

+ 0 - 149
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/RedisTemplateConfig.java

@@ -1,149 +0,0 @@
-package com.tzld.piaoquan.ad.engine.commons.config;
-
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
-import com.tzld.piaoquan.ad.engine.commons.redis.FastJson2JsonRedisSerializer;
-import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-import org.springframework.data.redis.connection.RedisConnectionFactory;
-import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
-import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
-import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
-import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
-import org.springframework.data.redis.serializer.StringRedisSerializer;
-
-/**
- * @author ehlxr
- */
-@Configuration
-public class RedisTemplateConfig {
-
-    @Bean
-    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
-    public GenericObjectPoolConfig<LettucePoolingClientConfiguration> redisPool() {
-        return new GenericObjectPoolConfig<>();
-    }
-
-    @Bean
-    @ConfigurationProperties(prefix = "spring.redis")
-    public RedisStandaloneConfiguration redisConfig() {
-        return new RedisStandaloneConfiguration();
-    }
-
-    @Bean("factory")
-    @Primary
-    public LettuceConnectionFactory factory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration redisConfig) {
-        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
-        return new LettuceConnectionFactory(redisConfig, lettuceClientConfiguration);
-    }
-
-    @Bean(name = "redisTemplate")
-    public RedisTemplate<String, String> getRedisTemplate(@Qualifier("factory") RedisConnectionFactory factory) {
-        return buildRedisTemplateByString(factory);
-    }
-
-    @Bean
-    @ConfigurationProperties(prefix = "spring.redis-ad")
-    public RedisStandaloneConfiguration adOwnRedisConfig() {
-        return new RedisStandaloneConfiguration();
-    }
-
-    @Bean("adOwnFactory")
-    public LettuceConnectionFactory pushCenterFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration adOwnRedisConfig) {
-        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
-        return new LettuceConnectionFactory(adOwnRedisConfig, lettuceClientConfiguration);
-    }
-
-    @Bean(name = "adOwnRedisTemplate")
-    public RedisTemplate<String, String> getPushCenterRedisTemplate(@Qualifier("adOwnFactory") RedisConnectionFactory pushCenterFactory) {
-        return buildRedisTemplateByString(pushCenterFactory);
-    }
-
-    /**
-     * 构建redisTemplate 使用string序列化
-     *
-     * @param factory
-     * @return
-     */
-    public RedisTemplate<String, String> buildRedisTemplateByString(RedisConnectionFactory factory) {
-        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
-        redisTemplate.setConnectionFactory(factory);
-        // key的序列化类型 保证可读性
-        redisTemplate.setKeySerializer(new StringRedisSerializer());
-        redisTemplate.setValueSerializer(new StringRedisSerializer());
-        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
-        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
-        return redisTemplate;
-    }
-
-    /**
-     * 构建redisTemplate value使用fastjson序列化
-     *
-     * @param factory
-     * @return
-     */
-    public RedisTemplate<String, Object> buildRedisTemplateByFastJson(RedisConnectionFactory factory) {
-        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
-        redisTemplate.setConnectionFactory(factory);
-        // key的序列化类型 保证可读性
-        redisTemplate.setKeySerializer(new StringRedisSerializer());
-        //value的序列化类型 fastjson 保证效率
-        FastJson2JsonRedisSerializer fastJson2JsonRedisSerializer = fastJson2JsonRedisSerializer();
-        redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
-        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
-        redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
-        return redisTemplate;
-    }
-
-    /**
-     * 构建redisTemplate value使用jackson序列化
-     *
-     * @param factory
-     * @return
-     */
-    public RedisTemplate<String, Object> buildRedisTemplateByJackson(RedisConnectionFactory factory) {
-        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
-        redisTemplate.setConnectionFactory(factory);
-        // key的序列化类型 保证可读性
-        redisTemplate.setKeySerializer(new StringRedisSerializer());
-        //value的序列化类型 jackson 保证效率
-        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();
-        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
-        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
-        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
-        return redisTemplate;
-    }
-
-    /**
-     * Jackson 序列化
-     *
-     * @return
-     */
-    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
-        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
-        ObjectMapper objectMapper = new ObjectMapper();
-        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
-        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
-        return jackson2JsonRedisSerializer;
-    }
-
-    /**
-     * FastJson 序列化
-     *
-     * @return
-     */
-    public FastJson2JsonRedisSerializer<Object> fastJson2JsonRedisSerializer() {
-        return new FastJson2JsonRedisSerializer(Object.class);
-    }
-}

+ 6 - 1
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AdOwnRedisHelper.java

@@ -4,6 +4,7 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
@@ -14,7 +15,7 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
-@Service
+@Component
 public class AdOwnRedisHelper {
 
     private final static Logger log = LoggerFactory.getLogger(AdOwnRedisHelper.class);
@@ -128,6 +129,10 @@ public class AdOwnRedisHelper {
         adOwnRedisTemplate.opsForValue().set(key, val);
     }
 
+    public Double zScore(String key, String value) {
+        return adOwnRedisTemplate.opsForZSet().score(key, value);
+    }
+
     public Long getKeyExpire(String key) {
         return adOwnRedisTemplate.getExpire(key, TimeUnit.SECONDS);
     }

+ 9 - 1
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AlgorithmRedisHelper.java

@@ -4,6 +4,7 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
@@ -13,20 +14,27 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+@Component
 public class AlgorithmRedisHelper {
     private final static Logger log = LoggerFactory.getLogger(AdOwnRedisHelper.class);
 
     private final static Long AD_FILTER_DEFAULT_EXPIRE_TIME = 30L * 24 * 60 * 60; // 排除人群(广告、计划)默认设置30天,单位秒
     private final static Long AD_FILTER_DELAY_QUEUE_EXPIRETIME = 5L * 60 * 1000; // 排除人群优化默认设置5分钟,单位毫秒
     private final static Long AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME = 1L * 24 * 60 * 60; // 排除人群优化默认设置1天,单位秒
-    @Resource(name = "adOwnRedisTemplate")
+    @Resource(name = "algorithmRedisTemplate")
     private RedisTemplate<String, String> redisTemplate;
 
 
+
+
     public boolean contantinsKey(String key) {
         return redisTemplate.hasKey(key);
     }
 
+    public Double zScore(String key, String value) {
+        return redisTemplate.opsForZSet().score(key, value);
+    }
+
     public String getString(String key) {
         Object obj = redisTemplate.opsForValue().get(key);
         return Objects.isNull(obj) ? null : obj.toString();

+ 2 - 1
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/CommonCollectionUtils.java

@@ -1,6 +1,7 @@
 package com.tzld.piaoquan.ad.engine.commons.util;
 
-import org.apache.commons.collections4.CollectionUtils;
+
+import org.apache.commons.collections.CollectionUtils;
 
 import java.util.Collections;
 import java.util.List;

+ 3 - 2
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/HttpClientFactory.java

@@ -1,7 +1,6 @@
 package com.tzld.piaoquan.ad.engine.commons.util;
 
 import com.google.common.collect.Lists;
-import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.apache.http.HttpRequestInterceptor;
 import org.apache.http.client.config.RequestConfig;
@@ -17,6 +16,8 @@ import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.ssl.SSLContexts;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
 
 import javax.net.ssl.SSLContext;
@@ -28,9 +29,9 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
-@Slf4j
 public class HttpClientFactory {
 
+    private static final Logger log = LoggerFactory.getLogger(HttpClientFactory.class);
     private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1,
             new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> log.error(" monitor push reject task error={}", e.toString()));
 

+ 3 - 3
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/JSONUtils.java

@@ -3,13 +3,13 @@ package com.tzld.piaoquan.ad.engine.commons.util;
 import com.alibaba.fastjson.JSONObject;
 import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
-import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-@Slf4j
 public class JSONUtils {
 
-
+    private static final Logger log = LoggerFactory.getLogger(JSONUtils.class);
     public static String toJson(Object obj) {
         if (obj == null) {
             return "";

+ 10 - 5
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/Application.java

@@ -1,23 +1,28 @@
 package com.tzld.piaoquan.ad.engine.server;
 
+import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 /**
  * https://github.com/grpc-swagger/grpc-swagger/blob/master/README_CN.md
  */
-@SpringBootApplication
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,SecurityAutoConfiguration.class})
 @ComponentScan({
-        "com.tzld.piaoquan.recommend.server.service",
-        "com.tzld.piaoquan.recommend.server.grpcservice",
-        "com.tzld.piaoquan.recommend.server.config",
-        "com.tzld.piaoquan.recommend.server.web"
+        "com.tzld.piaoquan.ad.engine.*"
 })
 @EnableEurekaClient
 @EnableAspectJAutoProxy
+@EnableScheduling
+@EnableApolloConfig
+@EnableFeignClients
 public class Application {
     public static void main(String[] args) {
         SpringApplication.run(Application.class, args);

+ 4 - 5
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/ControllerAspect.java → ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/controller/ControllerAspect.java

@@ -1,8 +1,8 @@
-package com.tzld.piaoquan.ad.engine.server.web;
+package com.tzld.piaoquan.ad.engine.server.controller;
 
 import com.google.common.base.Stopwatch;
-import com.tzld.piaoquan.ad.engine.server.util.TraceUtils;
-import com.tzld.piaoquan.ad.engine.server.util.JSONUtils;
+import com.tzld.piaoquan.ad.engine.commons.util.JSONUtils;
+import com.tzld.piaoquan.ad.engine.commons.util.TraceUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
@@ -20,10 +20,9 @@ import java.util.concurrent.TimeUnit;
 @Slf4j
 public class ControllerAspect {
 
-    @Around("execution(* com.tzld.piaoquan.recommend.server.web.*Controller.*(..))")
+    @Around("execution(* com.tzld.piaoquan.ad.engine.server.controller.*Controller.*(..))")
     public Object around(ProceedingJoinPoint pjp) throws Throwable {
         TraceUtils.setMDC();
-
         String className = pjp.getTarget().getClass().getSimpleName();
         MethodSignature signature = (MethodSignature) pjp.getSignature();
         Stopwatch stopwatch = Stopwatch.createStarted();

+ 46 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/controller/PredictController.java

@@ -0,0 +1,46 @@
+package com.tzld.piaoquan.ad.engine.server.controller;
+
+import com.tzld.piaoquan.ad.engine.service.predict.PredictModelService;
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.RoiPredictModelRequestParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.ThresholdPredictModelRequestParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@RestController
+@RequestMapping("/predict")
+public class PredictController {
+
+    @Autowired
+    PredictModelService predictModelService;
+    private final static Logger log = LoggerFactory.getLogger(PredictController.class);
+
+    @RequestMapping("/ab/model")
+    public Map<String,Object> adPredictByAbTestModel(@RequestBody ThresholdPredictModelRequestParam param){
+
+        return predictModelService.adPredict(param);
+    }
+
+
+    @RequestMapping("/test")
+    public void adPredictByAbTestModel(){
+
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+        System.out.println("___________________________");
+    }
+    @RequestMapping("/roi/model")
+    public Map<String,Object> adPredictByRoiModel(RoiPredictModelRequestParam param){
+        return predictModelService.adRecommendPredictByRoiModel(param);
+    }
+}

+ 0 - 28
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonCollectionUtils.java

@@ -1,28 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.util;
-
-import org.apache.commons.collections4.CollectionUtils;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-/**
- * @author dyp
- */
-public class CommonCollectionUtils {
-    public static <T, R> List<R> toList(List<T> list, Function<T, R> map) {
-        if (CollectionUtils.isEmpty(list)) {
-            return Collections.emptyList();
-        }
-        return list.stream().map(map).collect(Collectors.toList());
-    }
-
-    public static <T, K, V> Map<K, V> toMap(List<T> list, Function<T, K> keyFunc, Function<T, V> valueFunc) {
-        if (CollectionUtils.isEmpty(list)) {
-            return Collections.emptyMap();
-        }
-        return list.stream().collect(Collectors.toMap(keyFunc::apply, valueFunc::apply));
-    }
-}

+ 0 - 8
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonTypeToken.java

@@ -1,8 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.util;
-
-import com.google.common.reflect.TypeToken;
-
-/**
- * @author dyp
- */
-

+ 0 - 30
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/DateUtils.java

@@ -1,30 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.util;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * @author dyp
- */
-public final class DateUtils {
-    public static String getCurrentDateStr(String format) {
-        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
-        Date currentDate = new Date();
-        return dateFormat.format(currentDate);
-    }
-
-    public static int getCurrentHour() {
-        Calendar calendar = Calendar.getInstance();
-        return calendar.get(Calendar.HOUR_OF_DAY);
-    }
-
-    public static String getBeforeDaysDateStr(String format, int d) {
-        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        calendar.add(Calendar.DAY_OF_MONTH, -d);
-        Date previousDate = calendar.getTime();
-        return dateFormat.format(previousDate);
-    }
-}

+ 0 - 136
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/HttpClientFactory.java

@@ -1,136 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.util;
-
-import com.google.common.collect.Lists;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.HttpClientConnectionManager;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.NoopHostnameVerifier;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.ssl.SSLContexts;
-import org.slf4j.MDC;
-
-import javax.net.ssl.SSLContext;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-@Slf4j
-public class HttpClientFactory {
-
-    private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1,
-            new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> log.error(" monitor push reject task error={}", e.toString()));
-
-    private static final List<HttpClientConnectionManager> HTTP_CLIENT_CONNECTION_MANAGERS = Lists.newArrayList();
-
-    static {
-        SCHEDULED_CLOSED_EXECUTOR.schedule(() -> HTTP_CLIENT_CONNECTION_MANAGERS.forEach(HttpClientConnectionManager::closeExpiredConnections), 5, TimeUnit.SECONDS);
-    }
-
-    private static HttpRequestInterceptor getInterceptor() {
-        HttpRequestInterceptor requestInterceptor = (request, context) -> {
-            try {
-                String missSpanId = MDC.get("missSpanId");
-                String missTraceId = MDC.get("request-id");
-                if (missTraceId != null && !"".equals(missTraceId.trim())) {
-                    request.setHeader("request-id", missTraceId);
-                }
-                if (missSpanId != null && !"".equals(missSpanId.trim())) {
-                    request.setHeader("missSpanId", missSpanId);
-                }
-            } catch (Exception e) {
-                log.error(e.getMessage(), e);
-            }
-        };
-        return requestInterceptor;
-    }
-
-//    public String request(HttpRequestBase request) {
-//
-//        HttpEntity entity = null;
-//        try {
-//            log.info("request={}", JSONUtils.toJson(request));
-//            CloseableHttpResponse chr = request((HttpUriRequest) request);
-//            log.info("response={}", JSONUtils.toJson(chr));
-//            if (chr == null
-//                    || chr.getStatusLine() == null
-//                    || chr.getStatusLine().getStatusCode() != 200) {
-//                log.error("request failed http status exception!");
-//                return Strings.EMPTY;
-//            }
-//            entity = chr.getEntity();
-//            if (entity == null) {
-//                return Strings.EMPTY;
-//            }
-//            String content = EntityUtils.toString(entity, "UTF-8");
-//            log.info("response entity={}", JSONUtils.toJson(content));
-//        } catch (Exception e) {
-//            log.error("request error url={}", request.getURI().getPath(), e);
-//        } finally {
-//            if (request != null) {
-//                request.abort();
-//            }
-//            EntityUtils.consumeQuietly(entity);
-//        }
-//    }
-//
-//
-//    public CloseableHttpResponse request(HttpUriRequest request) {
-//        try {
-//            CloseableHttpResponse execute = closeableHttpClient.execute(request);
-//            return execute;
-//        } catch (Exception e) {
-//            log.error(String.format("http timeout request url = %s .", request.getURI().getPath()));
-//            throw new RuntimeException(e);
-//        }
-//    }
-
-    /**
-     * @param connectTimeout 连接超时时间 ms
-     * @param socketTimeout  读超时时间(等待数据超时时间)ms
-     * @param maxPerRoute    每个路由的最大连接数
-     * @param maxTotal       最大连接数
-     * @param retryCount     重试次数
-     * @return httpclient instance
-     */
-    public static CloseableHttpClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal,
-                                                int retryCount, int connectionWaitTimeout) {
-        try {
-            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).setConnectionRequestTimeout(connectionWaitTimeout).build();
-            CloseableHttpClient client = HttpClientBuilder.create()
-                    .setDefaultRequestConfig(requestConfig)
-                    .setConnectionManager(createConnectionManager(maxPerRoute, maxTotal))
-                    .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).addInterceptorFirst(getInterceptor()).build();
-            return client;
-        } catch (Throwable e) {
-            log.error("create HttpPoolClient exception", e);
-            throw new RuntimeException("create HttpPoolClient exception");
-        }
-    }
-
-    private static PoolingHttpClientConnectionManager createConnectionManager(int maxPerRoute, int maxTotal) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
-        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build();
-        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
-                .register("http", PlainConnectionSocketFactory.getSocketFactory())
-                .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
-        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
-        cm.setDefaultMaxPerRoute(maxPerRoute);
-        cm.setMaxTotal(maxTotal);
-        HTTP_CLIENT_CONNECTION_MANAGERS.add(cm);
-        return cm;
-    }
-
-}

+ 0 - 38
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/JSONUtils.java

@@ -1,38 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.util;
-
-import com.alibaba.fastjson.JSONObject;
-import com.google.common.reflect.TypeToken;
-import com.google.gson.Gson;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-@Slf4j
-public class JSONUtils {
-
-
-    public static String toJson(Object obj) {
-        if (obj == null) {
-            return "";
-        }
-        try {
-            return new Gson().toJson(obj);
-        } catch (Exception e) {
-            log.error("toJson exception", e);
-            return "";
-        }
-    }
-
-    public static <T> T fromJson(String value, TypeToken<T> typeToken, T defaultValue) {
-
-        if (StringUtils.isBlank(value)) {
-            return defaultValue;
-        }
-        try {
-            return JSONObject.parseObject(value, typeToken.getType());
-        } catch (Exception e) {
-            log.error("parseObject error! value=[{}]", value, e);
-        }
-        return defaultValue;
-    }
-
-}

+ 0 - 48
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/TraceUtils.java

@@ -1,48 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.util;
-
-import org.apache.commons.lang.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.MDC;
-
-import java.net.InetAddress;
-
-/**
- * @author dyp
- */
-public class TraceUtils {
-    public static final String TRACE_ID_KEY = "traceId";
-    public static final String DEFAULT_TRACE_ID = "default_trace_id";
-
-    public static void setMDC() {
-        MDC.put(TraceUtils.TRACE_ID_KEY, genTraceId());
-    }
-
-    public static void removeMDC() {
-        MDC.remove(TraceUtils.TRACE_ID_KEY);
-    }
-
-    public static String genTraceId() {
-        StringBuilder traceIdBuilder = new StringBuilder();
-        InetAddress address = InetAddress.getLoopbackAddress();
-        if (address == null) {
-            return DEFAULT_TRACE_ID;
-        }
-        String addressStr = address.getHostAddress();
-        if (StringUtils.isBlank(addressStr)) {
-            return DEFAULT_TRACE_ID;
-        }
-        String[] addressArr = addressStr.split("\\.");
-        if (addressArr.length != 4) {
-            return DEFAULT_TRACE_ID;
-        }
-
-        traceIdBuilder.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[0])), 2, '0'))
-                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[1])), 2, '0'))
-                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[2])), 2, '0'))
-                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[3])), 2, '0'))
-                .append(System.currentTimeMillis())
-                .append(RandomStringUtils.randomAlphabetic(4))
-                .append(Thread.currentThread().getId());
-        return traceIdBuilder.toString();
-    }
-}

+ 0 - 94
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/RecommendController.java

@@ -1,94 +0,0 @@
-package com.tzld.piaoquan.ad.engine.server.web;
-
-import com.google.common.base.Strings;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.tzld.piaoquan.recommend.server.client.ProtobufUtils;
-import com.tzld.piaoquan.recommend.server.client.RecommendHttpRequest;
-import com.tzld.piaoquan.recommend.server.gen.recommend.RecommendRequest;
-import com.tzld.piaoquan.recommend.server.gen.recommend.RecommendResponse;
-import com.tzld.piaoquan.ad.engine.server.service.RecommendService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.MapUtils;
-import org.slf4j.MDC;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * @author dyp
- */
-@RestController
-@Slf4j
-public class RecommendController {
-    @Autowired
-    private RecommendService recommendService;
-
-    @Bean
-    public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
-        return new ProtobufHttpMessageConverter();
-    }
-
-    @RequestMapping("/homepage/recommend")
-    public String homepageRecommend(@RequestBody RecommendHttpRequest httpRequest) {
-        MDC.put("appType", String.valueOf(httpRequest.getAppType()));
-        RecommendResponse response = recommendService.homepageRecommend(generate(httpRequest));
-        String result = "";
-        try {
-            result = ProtobufUtils.toJson(response);
-        } catch (InvalidProtocolBufferException e) {
-            log.error("homepageRecommend ProtobufUtils.toJson", e);
-        }
-        return result;
-    }
-
-    @RequestMapping("/relevant/recommend")
-    public String relevantRecommend(@RequestBody RecommendHttpRequest httpRequest) {
-        MDC.put("appType", String.valueOf(httpRequest.getAppType()));
-
-        RecommendResponse response = recommendService.relevantRecommend(generate(httpRequest));
-        String result = "";
-        try {
-            result = ProtobufUtils.toJson(response);
-        } catch (InvalidProtocolBufferException e) {
-            log.error("relevantRecommend ProtobufUtils.toJson", e);
-        }
-        return result;
-    }
-
-    private RecommendRequest generate(RecommendHttpRequest httpRequest) {
-        if (httpRequest == null) {
-            return null;
-        }
-        RecommendRequest.Builder builder = RecommendRequest.newBuilder();
-
-        builder.setRequestId(Strings.nullToEmpty(httpRequest.getRequestId()))
-                .setMid(Strings.nullToEmpty(httpRequest.getMid()))
-                .setUid(Strings.nullToEmpty(httpRequest.getUid()))
-                .setSize(httpRequest.getSize())
-                .setAppType(httpRequest.getAppType())
-                .setCityCode(Strings.nullToEmpty(httpRequest.getCityCode()))
-                .setProvinceCode(Strings.nullToEmpty(httpRequest.getProvinceCode()))
-                .setVersionAuditStatus(httpRequest.getVersionAuditStatus())
-                .setRecommendTraceId(Strings.nullToEmpty(httpRequest.getRecommendTraceId()))
-                .setVideoId(httpRequest.getVideoId());
-
-        if (CollectionUtils.isNotEmpty(httpRequest.getAbExpCodes())) {
-            builder.addAllAbExpCode(httpRequest.getAbExpCodes());
-        }
-        if (MapUtils.isNotEmpty(httpRequest.getEventIdMap())) {
-            builder.putAllEventId(httpRequest.getEventIdMap());
-        }
-
-        return builder.build();
-    }
-
-    @GetMapping("/ok")
-    public String ok() {
-        return "ok";
-    }
-}

+ 1 - 1
ad-engine-server/src/main/resources/application-dev.yml

@@ -1,5 +1,5 @@
 server:
-  port: 8081
+  port: 8086
 
 eureka:
   client:

+ 3 - 3
ad-engine-server/src/main/resources/application.yml

@@ -33,7 +33,7 @@ spring:
   profiles:
     active: dev
   application:
-    name: ad
+    name: ad-engine
   jackson:
     default-property-inclusion: non_null
   servlet:
@@ -51,7 +51,7 @@ server:
     accept-count: 1000
     connection-timeout: 30000
   servlet:
-    context-path: /ad
+    context-path: /ad-engine
     session:
       timeout: 60
 pagehelper:
@@ -70,7 +70,7 @@ apollo:
   cacheDir: ${datalog}/apollo-cache-dir
 
 mybatis:
-  type-aliases-package: com.tzld.piaoquan.ad.model.po
+  type-aliases-package: com.tzld.piaoquan.ad.engine.commons.model
   mapper-locations: classpath:mapper/*.xml, classpath:mapper/ext/*.xml
   configuration:
     log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl

+ 14 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/PredictModelService.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.ad.engine.service.predict;
+
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.RoiPredictModelRequestParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.ThresholdPredictModelRequestParam;
+
+import java.util.Map;
+
+public interface PredictModelService {
+
+    public Map<String,Object> adPredict(ThresholdPredictModelRequestParam requestParam);
+
+    public Map<String,Object> adRecommendPredictByRoiModel(RoiPredictModelRequestParam requestParam);
+}
+

+ 20 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/calculator/ThresholdPredictCalculator.java

@@ -0,0 +1,20 @@
+package com.tzld.piaoquan.ad.engine.service.predict.calculator;
+
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdCalculateParam;
+
+public class ThresholdPredictCalculator {
+
+   public static <T extends ThresholdCalculateParam> Double basicCalculate(T param) {
+      return param.getGroupShareRate()*param.getVideoShareRate();
+   }
+
+   public static <T extends ThresholdCalculateParam> Double multiplyCalculate(T param) {
+      return param.getGroupShareRate()*param.getGroupOutRate()*param.getVideoShareRate()*param.getVideoOutRate();
+   }
+
+   public static <T extends ThresholdCalculateParam> Double addWeightCalculate(T param) {
+      double groupRate= param.getShareWeight()* param.getGroupShareRate()+ param.getOutWeight()*param.getGroupOutRate();
+      double videoRate= param.getShareWeight()* param.getVideoShareRate()+ param.getOutWeight()*param.getVideoOutRate();
+      return groupRate*videoRate;
+   }
+}

+ 620 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/config/AbConfig.java

@@ -0,0 +1,620 @@
+package com.tzld.piaoquan.ad.engine.service.predict.config;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.gson.Gson;
+import com.tzld.piaoquan.ad.engine.service.predict.model.threshold.ThresholdPredictModel;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.*;
+
+@Component
+public class AbConfig {
+    HashMap<String,Map<String,Object>> abConfigMap;
+    Gson gson=new Gson();
+    @PostConstruct
+    public void init() {
+        abConfigMap=getAbConfigMap();
+    }
+
+    public String[] getAbParams(String abTestCode, JSONObject abExpInfo){
+        String abtestId = null;
+        String abtestConfigTag = null;
+        // Extract A/B test IDs from AD_ABTEST_CONFIG
+        List<String> ad_abtest_id_list = new ArrayList<>();
+
+        for (String key : abConfigMap.keySet()) {
+            String[] parts = key.split("-");
+            if (parts.length > 0) {
+                ad_abtest_id_list.add(parts[0]);
+            }
+        }
+        // Initialize a dictionary to store A/B test configurations
+        Map<String, Object> configValueDict = new HashMap<>();
+        // Check if ab_exp_info is not null
+        if (abExpInfo != null) {
+            // Retrieve the list of A/B tests under the key \"ab_test002\"
+            JSONArray abExpList = abExpInfo.getJSONArray("ab_test002");
+            if (abExpList != null) {
+                // Process each A/B test item
+                for (Map<String, Object> abItem : abExpList.toJavaList(Map.class)) {
+                    // Get the \"abExpCode\" from the A/B test item
+                    String ab_exp_code = (String) abItem.get("abExpCode");
+                    // Check if \"abExpCode\" is not null
+                    if (ab_exp_code != null) {
+                        // Check if \"abExpCode\" exists in ad_abtest_id_list
+                        if (ad_abtest_id_list.contains(ab_exp_code)) {
+                            // Get the \"configValue\" from the A/B test item
+                            Object configValue = abItem.get("configValue");
+                            // Check if \"configValue\" is not null
+                            if (configValue != null) {
+                                // Store the configuration value in config_value_dict
+                                configValueDict.put(ab_exp_code, configValue);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (configValueDict.size() > 0) {
+            for (Map.Entry<String, Object> entry : configValueDict.entrySet()) {
+                String ab_exp_code = entry.getKey();
+                Map<String, List<String>> config_value = gson.fromJson((String)entry.getValue(),Map.class);
+
+                for (Map.Entry<String, List<String>> configEntry : config_value.entrySet()) {
+                    String tag = configEntry.getKey();
+                    configEntry.getValue();
+
+                    if (configEntry.getValue().contains(abTestCode)) {
+                        abtestId = ab_exp_code;
+                        abtestConfigTag = tag;
+                        break;
+                    }
+                }
+            }
+        }
+        if(abtestId!=null){
+            return new String[]{abtestId,abtestConfigTag};
+        }else {
+            return null;
+        }
+
+    }
+
+
+    public HashMap<String,Map<String,Object>> getAbConfigMap(){
+        String configStr="{\n" +
+                "        \"173-j\": {\n" +
+                "            \"video\": {\"data\": \"videos0\"},\n" +
+                "            \"user\": {\"data\": \"user0\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"173-l\": {\n" +
+                "            \"video\": {\"data\": \"videos0\"},\n" +
+                "            \"user\": {\"data\": \"user0\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"173-n\": {\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"173-s\": {\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule3\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class3\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"173-t\": {\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"no_ad_group_with_video_mapping\": {\n" +
+                "                \"mean_group\": [\"top3\"],\n" +
+                "                \"return0share1mids\": [\"top3\"],\n" +
+                "                \"return0share2_nmids\": [\"top3\"],\n" +
+                "                \"return1mids\": [\"top3\"],\n" +
+                "                \"return2_3mids\": [\"top3\"],\n" +
+                "                \"return4_8mids\": [\"top3\"],\n" +
+                "                \"return9_24mids\": [\"top3\"],\n" +
+                "                \"return25_nmids\": [\"top3\"],\n" +
+                "            }\n" +
+                "        }, " +
+                "        \"173-u\": {\n" +
+                "            \"threshold_mix_func\": \"model\",\n" +
+                "            \"model_key\": \"ad_out_v1\",\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"173-v\": {\n" +
+                "            \"threshold_mix_func\": \"model\",\n" +
+                "            \"model_key\": \"ad_out_v1\",\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"190-f\": {\n" +
+                "            \"video\": {\"data\": \"videos21\"},\n" +
+                "            \"user\": {\"data\": \"user21\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"190-g\": {\n" +
+                "            \"video\": {\"data\": \"videos21out\"},\n" +
+                "            \"user\": {\"data\": \"user21out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"190-h\": {\n" +
+                "            \"video\": {\"data\": \"videos21out\"},\n" +
+                "            \"user\": {\"data\": \"user21out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"190-i\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos21\"}, \"user\": {\"data\": \"user21\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos21out\"}, \"user\": {\"data\": \"user21out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        },  " +
+                "        \"190-j\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos21\"}, \"user\": {\"data\": \"user21\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos21out\"}, \"user\": {\"data\": \"user21out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        },  " +
+                "        \"194-g\": {\n" +
+                "            \"video\": {\"data\": \"videos4\"},\n" +
+                "            \"user\": {\"data\": \"user4\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"194-i\": {\n" +
+                "            \"video\": {\"data\": \"videos4out\"},\n" +
+                "            \"user\": {\"data\": \"user4out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"194-j\": {\n" +
+                "            \"video\": {\"data\": \"videos4out\"},\n" +
+                "            \"user\": {\"data\": \"user4out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"194-k\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos4\"}, \"user\": {\"data\": \"user4\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos4out\"}, \"user\": {\"data\": \"user4out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        },  " +
+                "        \"194-l\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos4\"}, \"user\": {\"data\": \"user4\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos4out\"}, \"user\": {\"data\": \"user4out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        }, " +
+                "        \"194-m\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos4new\"}, \"user\": {\"data\": \"user4new\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos4out\"}, \"user\": {\"data\": \"user4out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        }," +
+                "        \"194-n\": {\n" +
+                "            \"video\": {\"data\": \"videos4out\"},\n" +
+                "            \"user\": {\"data\": \"user4out\", \"rule\": \"rule3\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class3\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"194-o\": {\n" +
+                "            \"video\": {\"data\": \"videos4out\"},\n" +
+                "            \"user\": {\"data\": \"user4out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"no_ad_group_with_video_mapping\": {\n" +
+                "                \"mean_group\": [\"top3\"],\n" +
+                "                \"return0share1mids\": [\"top3\"],\n" +
+                "                \"return0share2_nmids\": [\"top3\"],\n" +
+                "                \"return1mids\": [\"top3\"],\n" +
+                "                \"return2_3mids\": [\"top3\"],\n" +
+                "                \"return4_8mids\": [\"top3\"],\n" +
+                "                \"return9_24mids\": [\"top3\"],\n" +
+                "                \"return25_nmids\": [\"top3\"],\n" +
+                "            }\n" +
+                "        },  " +
+                "        \"195-f\": {\n" +
+                "            \"video\": {\"data\": \"videos5\"},\n" +
+                "            \"user\": {\"data\": \"user5\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"195-h\": {\n" +
+                "            \"video\": {\"data\": \"videos5out\"},\n" +
+                "            \"user\": {\"data\": \"user5out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"195-i\": {\n" +
+                "            \"video\": {\"data\": \"videos5out\"},\n" +
+                "            \"user\": {\"data\": \"user5out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"195-j\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos5\"}, \"user\": {\"data\": \"user5\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos5out\"}, \"user\": {\"data\": \"user5out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        },  " +
+                "        \"195-k\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos5\"}, \"user\": {\"data\": \"user5\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos5out\"}, \"user\": {\"data\": \"user5out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        },  " +
+                "        \"195-l\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos5new\"}, \"user\": {\"data\": \"user5new\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos5out\"}, \"user\": {\"data\": \"user5out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        },  " +
+                "        \"195-m\": {\n" +
+                "            \"video\": {\"data\": \"videos5out\"},\n" +
+                "            \"user\": {\"data\": \"user5out\", \"rule\": \"rule3\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class3\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"195-n\": {\n" +
+                "            \"video\": {\"data\": \"videos5out\"},\n" +
+                "            \"user\": {\"data\": \"user5out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"no_ad_group_with_video_mapping\": {\n" +
+                "                \"mean_group\": [\"top3\"],\n" +
+                "                \"return0share1mids\": [\"top3\"],\n" +
+                "                \"return0share2_nmids\": [\"top3\"],\n" +
+                "                \"return1mids\": [\"top3\"],\n" +
+                "                \"return2_3mids\": [\"top3\"],\n" +
+                "                \"return4_8mids\": [\"top3\"],\n" +
+                "                \"return9_24mids\": [\"top3\"],\n" +
+                "                \"return25_nmids\": [\"top3\"],\n" +
+                "            }\n" +
+                "        },  " +
+                "        \"196-f\": {\n" +
+                "            \"video\": {\"data\": \"videos6\"},\n" +
+                "            \"user\": {\"data\": \"user6\", \"rule\": \"rule1\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"196-g\": {\n" +
+                "            \"video\": {\"data\": \"videos6out\"},\n" +
+                "            \"user\": {\"data\": \"user6out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"196-h\": {\n" +
+                "            \"video\": {\"data\": \"videos6out\"},\n" +
+                "            \"user\": {\"data\": \"user6out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"196-i\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos6\"}, \"user\": {\"data\": \"user6\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos6out\"}, \"user\": {\"data\": \"user6out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        },  " +
+                "        \"196-j\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos6\"}, \"user\": {\"data\": \"user6\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos6out\"}, \"user\": {\"data\": \"user6out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        },  " +
+                "        \"197-f\": {\n" +
+                "            \"video\": {\"data\": \"data5\"},\n" +
+                "            \"user\": {\"data\": \"user18\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        },  " +
+                "        \"197-g\": {\n" +
+                "            \"video\": {\"data\": \"videos18out\"},\n" +
+                "            \"user\": {\"data\": \"user18out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"197-h\": {\n" +
+                "            \"video\": {\"data\": \"videos18out\"},\n" +
+                "            \"user\": {\"data\": \"user18out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"197-i\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos18\"}, \"user\": {\"data\": \"user18\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos18out\"}, \"user\": {\"data\": \"user18out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        }, " +
+                "        \"197-j\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos18\"}, \"user\": {\"data\": \"user18\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos18out\"}, \"user\": {\"data\": \"user18out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        }, " +
+                "        \"198-f\": {\n" +
+                "            \"video\": {\"data\": \"videos19\"},\n" +
+                "            \"user\": {\"data\": \"user19\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"198-g\": {\n" +
+                "            \"video\": {\"data\": \"videos19out\"},\n" +
+                "            \"user\": {\"data\": \"user19out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        }, " +
+                "        \"198-h\": {\n" +
+                "            \"video\": {\"data\": \"videos19out\"},\n" +
+                "            \"user\": {\"data\": \"user19out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }," +
+                "        \"198-i\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos19\"}, \"user\": {\"data\": \"user19\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos19out\"}, \"user\": {\"data\": \"user19out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        }, " +
+                "        \"198-j\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos19\"}, \"user\": {\"data\": \"user19\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos19out\"}, \"user\": {\"data\": \"user19out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        }," +
+                "        \"242-d\": {\n" +
+                "            \"video\": {\"data\": \"videos22\"},\n" +
+                "            \"user\": {\"data\": \"user22\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"242-e\": {\n" +
+                "            \"video\": {\"data\": \"videos22out\"},\n" +
+                "            \"user\": {\"data\": \"user22out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        }, " +
+                "        \"242-f\": {\n" +
+                "            \"video\": {\"data\": \"videos22out\"},\n" +
+                "            \"user\": {\"data\": \"user22out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"242-g\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos22\"}, \"user\": {\"data\": \"user22\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos22out\"}, \"user\": {\"data\": \"user22out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        },  " +
+                "        \"242-h\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos22\"}, \"user\": {\"data\": \"user22\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos22out\"}, \"user\": {\"data\": \"user22out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        }, " +
+                "        \"243-d\": {\n" +
+                "            \"video\": {\"data\": \"videos3\"},\n" +
+                "            \"user\": {\"data\": \"user3\", \"rule\": \"rule1\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"243-e\": {\n" +
+                "            \"video\": {\"data\": \"videos3out\"},\n" +
+                "            \"user\": {\"data\": \"user3out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        }, " +
+                "        \"243-f\": {\n" +
+                "            \"video\": {\"data\": \"videos3out\"},\n" +
+                "            \"user\": {\"data\": \"user3out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"243-g\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos3\"}, \"user\": {\"data\": \"user3\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos3out\"}, \"user\": {\"data\": \"user3out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        }, " +
+                "        \"243-h\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos3\"}, \"user\": {\"data\": \"user3\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos3out\"}, \"user\": {\"data\": \"user3out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        }, " +
+                "        \"324-a\": {\n" +
+                "            \"video\": {\"data\": \"videos0\"},\n" +
+                "            \"user\": {\"data\": \"user0\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"324-b\": {\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\", \"return0share1mids\"],\n" +
+                "        },  " +
+                "        \"324-c\": {\n" +
+                "            \"video\": {\"data\": \"videos0out\"},\n" +
+                "            \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "        }, " +
+                "        \"324-d\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos0\"}, \"user\": {\"data\": \"user0\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos0out\"}, \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"add\",\n" +
+                "            \"mix_param\": {\"share_weight\": 0.2, \"out_weight\": 0.8}\n" +
+                "        }, " +
+                "        \"324-e\": {\n" +
+                "            \"share\": {\"video\": {\"data\": \"videos0\"}, \"user\": {\"data\": \"user0\", \"rule\": \"rule2\"}},\n" +
+                "            \"out\": {\"video\": {\"data\": \"videos0out\"}, \"user\": {\"data\": \"user0out\", \"rule\": \"rule2\"}},\n" +
+                "            \"group_class_key\": \"class1\",\n" +
+                "            \"no_ad_mid_group_list\": [\"class1\"],\n" +
+                "            \"care_model_status_param\": 1,\n" +
+                "            \"care_model_ab_mid_group\": [\"mean_group\"],\n" +
+                "            \"threshold_mix_func\": \"multiply\",\n" +
+                "        },  " +
+                "    }";
+        HashMap<String,Map<String,Object>> abConfigMap=JSONObject.parseObject(configStr,HashMap.class);
+        return abConfigMap;
+    }
+}

+ 14 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/config/AdOutV1OnlineWeightConfig.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.ad.engine.service.predict.config;
+
+import java.util.*;
+
+
+public class AdOutV1OnlineWeightConfig {
+    public static Map<String,Double> weightMap=new HashMap<>();
+
+    public static Double defaultWeight=new Double(0);
+
+    public static Double getWeight(String key){
+        return weightMap.getOrDefault(key,defaultWeight);
+    }
+}

+ 22 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/config/RuleRedisKeyConst.java

@@ -0,0 +1,22 @@
+package com.tzld.piaoquan.ad.engine.service.predict.config;
+
+public class RuleRedisKeyConst {
+//         用户组有广告时的分享率预测结果存放 redis key 前缀,完整格式:ad:users:group:predict:share:rate:{user_data_key}:{date}
+    public static String KEY_NAME_PREFIX_AD_GROUP="ad:users:group:predict:share:rate:";
+//    视频有广告时的分享率预测结果存放 redis key 前缀,完整格式:ad:video:predict:share:rate:{video_data_key}:{date}
+    public static String KEY_NAME_PREFIX_AD_VIDEO="ad:video:predict:share:rate:";
+//    用户分组结果存放 redis key 前缀,完整格式:mid:group:{class_key}:{mid}
+    public static String KEY_NAME_PREFIX_MID_GROUP="mid:group:";
+//    广告推荐阈值结果存放 redis key 前缀,完整格式:ad:threshold:{abtestId}:{abtestConfigTag}:{abtestGroup}:{group}
+    public static String KEY_NAME_PREFIX_AD_THRESHOLD="ad:threshold:";
+//    广告推荐关怀模式实验阈值结果存放 redis key 前缀,完整格式:ad:threshold:care:{abtestId}:{abtestConfigTag}:{abtestGroup}:{group}
+    public static String KEY_NAME_PREFIX_AD_THRESHOLD_CARE_MODEL="ad:threshold:care:";
+//    特定视频不出广告视频列表存放 redis key 前缀,完整格式:no:ad:videos:{appType}
+    public static String KEY_NAME_PREFIX_NO_AD_VIDEOS="no:ad:videos:";
+//    有广告时的用户跳出模型离线分数 redis key 前缀,完整格式:ad:out:model:score:user:{model_key}:{mid}
+    public static String KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_USER="ad:out:model:score:user:";
+//    有广告时的视频跳出模型离线分数 redis key 前缀,完整格式:ad:out:model:score:video:{model_key}:{videoid}
+    public static String KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_ITEM="ad:out:model:score:item:";
+//        # 有广告时的视频跳出模型策略配置  redis key 前缀,完整格式:ad:out:model:config:{model_key}:{abtest_id}:{abtest_config_tag}:{config}
+    public static String KEY_NAME_PREFIX_AD_OUT_MODEL_CONFIG="ad:out:model:config:";
+}

+ 98 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/impl/PredictModelServiceImpl.java

@@ -0,0 +1,98 @@
+package com.tzld.piaoquan.ad.engine.service.predict.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.commons.redis.AlgorithmRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.config.RuleRedisKeyConst;
+import com.tzld.piaoquan.ad.engine.service.predict.PredictModelService;
+import com.tzld.piaoquan.ad.engine.service.predict.config.AbConfig;
+import com.tzld.piaoquan.ad.engine.service.predict.model.containner.ThresholdModelContainer;
+import com.tzld.piaoquan.ad.engine.service.predict.param.RuleParamHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.RoiPredictModelRequestParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.request.ThresholdPredictModelRequestParam;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+public class PredictModelServiceImpl implements PredictModelService {
+
+    @Value("${ad.own.experiment.tier:ab_test002}")
+    private String adOwnExperimentTier;
+
+    @Autowired
+    RuleParamHelper paramHelper;
+
+    @Autowired
+    AlgorithmRedisHelper redisHelper;
+
+    @Autowired
+    AbConfig abConfig;
+
+    public  Map<String,Object> adPredict(ThresholdPredictModelRequestParam requestParam){
+        Map<String,Object> result=new HashMap<>();
+        String[] abParamArr=abConfig.getAbParams(requestParam.getAbTestCode(),requestParam.getAbExpInfo());
+        if(abParamArr==null){
+            return result;
+        }
+        String abtestId=abParamArr[0];
+        String abTestConfigTag=abParamArr[1];
+
+        HashMap<String,Map<String,Object>> abConfigMap=abConfig.getAbConfigMap();
+        Map<String,Object> abtestParam=abConfigMap.getOrDefault(abtestId+"-"+abTestConfigTag,null);
+        if(abtestParam==null){
+            return result;
+        }
+
+        // Determine the group to which mid belongs
+        String groupClassKey = (String) abtestParam.get("group_class_key");
+        String midGroupKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_MID_GROUP + groupClassKey + ":" + requestParam.getMid();
+        String midGroup = redisHelper.getString(midGroupKeyName);
+        if (midGroup == null) {
+            midGroup = "mean_group";
+        }
+        String[] noAdMidGroupList=new String[0];
+        noAdMidGroupList=((JSONArray) abtestParam.get("no_ad_mid_group_list")).toArray(noAdMidGroupList);
+        boolean inNoAdGroup = false;
+        for (String group : noAdMidGroupList) {
+            if (group.equals(midGroup)) {
+                inNoAdGroup = true;
+                break;
+            }
+        }
+        //不出广告组
+        if (inNoAdGroup) {
+            // User is in the no-ad group, no ad should be shown
+            result.put("mid_group", midGroup);
+            result.put("ad_predict", 1);
+            result.put("no_ad_strategy","no_ad_mid_group_with_video");
+            return result;
+        }
+
+        //设置信息
+        ThresholdPredictModelParam modelParam=ThresholdPredictModelParam.builder()
+                .build();
+        BeanUtils.copyProperties(requestParam,modelParam);
+        modelParam.setDate(new Date());
+        modelParam.setAbtestId(abtestId);
+        modelParam.setAbTestConfigTag(abTestConfigTag);
+        modelParam.setAbtestParam(abtestParam);
+        modelParam.setMidGroup(midGroup);
+        Object thresholdMixFunc=abtestParam.getOrDefault("threshold_mix_func","default");
+        result= ThresholdModelContainer.
+                getThresholdPredictModel(thresholdMixFunc.toString())
+                .predict(modelParam);
+        return result;
+    }
+
+    public Map<String,Object> adRecommendPredictByRoiModel(RoiPredictModelRequestParam requestParam){
+        return null;
+    }
+
+
+
+}

+ 4 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/Model.java

@@ -0,0 +1,4 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model;
+
+public interface Model {
+}

+ 34 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/containner/ThresholdModelContainer.java

@@ -0,0 +1,34 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.containner;
+
+import com.tzld.piaoquan.ad.engine.service.predict.model.threshold.ThresholdPredictModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class ThresholdModelContainer {
+
+    @Autowired
+    private ApplicationContext applicationContext;
+
+    public static Map<String,ThresholdPredictModel> modelMap=new HashMap<>();
+    @PostConstruct
+    public void init() {
+        Map<String,ThresholdPredictModel> beanMap= applicationContext.getBeansOfType(ThresholdPredictModel.class);
+        beanMap.forEach((s,model)->{
+            modelMap.put(model.getName(), model);
+        });
+    }
+
+    public static ThresholdPredictModel getThresholdPredictModel(String modelName){
+        return modelMap.getOrDefault(modelName,getBasicPredictModel());
+    }
+
+    public static ThresholdPredictModel getBasicPredictModel(){
+        return modelMap.get("basic");
+    }
+}

+ 87 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/AddThresholdPredictModel.java

@@ -0,0 +1,87 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.threshold;
+
+
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.calculator.ThresholdPredictCalculator;
+import com.tzld.piaoquan.ad.engine.service.predict.config.RuleRedisKeyConst;
+import com.tzld.piaoquan.ad.engine.service.predict.param.RuleParamHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdCalculateParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class AddThresholdPredictModel extends ThresholdPredictModel {
+
+    @Autowired
+    RuleParamHelper paramHelper;
+
+    @Autowired
+    AdOwnRedisHelper redisHelper;
+
+    /**
+     * setModelName
+     */
+    @Override
+    String initName() {
+        return "add";
+    }
+    @Override
+    public Map<String, Object> predict(ThresholdPredictModelParam modelParam) {
+        Map<String, Object> result = new HashMap<>();
+        // Determine the group to which mid belongs
+        String groupClassKey = (String) modelParam.getAbtestParam().get("group_class_key");
+        String midGroupKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_MID_GROUP + groupClassKey + ":" + modelParam.getMid();
+        String midGroup = redisHelper.getString(midGroupKeyName);
+        if (midGroup == null) {
+            midGroup = "mean_group";
+        }
+        // Get group and video share rates
+        Double groupShareRate = paramHelper.getGroupShareRate(modelParam.getAbtestParam(),modelParam.getDate(),midGroup);
+        Double videoShareRate = paramHelper.getVideoShareRate(modelParam.getAbtestParam(), modelParam.getDate(),modelParam.getVideoId());
+        // Get group and video out rates
+        Double groupOutRate = paramHelper.getGroupOutRate(modelParam.getAbtestParam(),modelParam.getDate(),midGroup);
+        Double videoOutRate = paramHelper.getVideoOutRate(modelParam.getAbtestParam(), modelParam.getDate(),modelParam.getVideoId());
+
+        // Calculate mid-video prediction result
+        if (groupShareRate == null || videoShareRate == null || groupOutRate == null || videoOutRate == null) {
+            return null;
+        }
+        double shareWeight = (double) ((Map<String, Object>)modelParam.getAbtestParam().get("mix_param")).get("share_weight");
+        double outWeight = (double) ((Map<String, Object>)modelParam.getAbtestParam().get("mix_param")).get("out_weight");
+        ThresholdCalculateParam calculateParam=ThresholdCalculateParam.builder()
+                .groupOutRate(groupOutRate)
+                .groupShareRate(groupShareRate)
+                .videoOutRate(videoOutRate)
+                .videoShareRate(videoShareRate)
+                .shareWeight(shareWeight).outWeight(outWeight).build();
+        double midVideoPredictRes = ThresholdPredictCalculator.addWeightCalculate(calculateParam);
+
+        // Get the threshold
+        double threshold = paramHelper.getThreshold(
+                modelParam.getAbtestId(),
+                modelParam.getAbTestConfigTag(),
+                modelParam.getAbTestCode(),
+                midGroup,
+                modelParam.getCareModelStatus(),
+                modelParam.getAbtestParam()
+        );
+        // Threshold check
+        int adPredict=midVideoPredictRes > threshold?2:1;
+        result.put("mid_group", midGroup);
+        result.put("group_share_rate", groupShareRate);
+        result.put("video_share_rate", videoShareRate);
+        result.put("group_out_rate", groupOutRate);
+        result.put("video_out_rate", videoOutRate);
+        //中间计算参数 返回结果目前ad用不到
+//        result.put("group_rate", groupRate);
+//        result.put("video_rate", videoRate);
+        result.put("mid_video_predict_res", midVideoPredictRes);
+        result.put("threshold", threshold);
+        result.put("ad_predict", adPredict);
+        return result;
+    }
+}

+ 93 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/BasicThresholdPredictModel.java

@@ -0,0 +1,93 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.threshold;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.calculator.ThresholdPredictCalculator;
+import com.tzld.piaoquan.ad.engine.service.predict.config.RuleRedisKeyConst;
+import com.tzld.piaoquan.ad.engine.service.predict.param.RuleParamHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdCalculateParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+@Component
+public class BasicThresholdPredictModel extends ThresholdPredictModel{
+
+    @Autowired
+    RuleParamHelper paramHelper;
+
+    @Autowired
+    AdOwnRedisHelper redisHelper;
+    @Override
+    String initName() {
+        return "basic";
+    }
+
+    @Override
+    public Map<String, Object> predict(ThresholdPredictModelParam modelParam) {
+        Map<String, Object> result = new HashMap<>();
+
+        String groupClassKey = (String) modelParam.getAbtestParam().get("group_class_key");
+        Map<String, Set<String>> noAdGroupWithVideoMapping = (Map<String, Set<String>>) modelParam.getAbtestParam().getOrDefault("no_ad_group_with_video_mapping", new HashMap<>());
+
+        String midGroupKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_MID_GROUP + groupClassKey + ":" + modelParam.getMid();
+        String midGroup = redisHelper.get(midGroupKeyName);
+        if (midGroup == null) {
+            midGroup = "mean_group";
+        }
+
+        if (noAdGroupWithVideoMapping.containsKey(midGroup)) {
+            Set<String> videoMappingKeyList = noAdGroupWithVideoMapping.get(midGroup);
+            String noAdVideos = redisHelper.get(RuleRedisKeyConst.KEY_NAME_PREFIX_NO_AD_VIDEOS + modelParam.getAppType());
+            Map<String, List<String>> noAdVideosMap = new HashMap<>();
+            if (noAdVideos != null) {
+                noAdVideosMap = new Gson().fromJson(noAdVideos, new TypeToken<Map<String, List<String>>>() {}.getType());
+            }
+
+            Set<String> noAdVideoList = new HashSet<>();
+            for (String videoMappingKey : videoMappingKeyList) {
+                noAdVideoList.addAll(noAdVideosMap.getOrDefault(videoMappingKey, new ArrayList<>()));
+            }
+
+            if (noAdVideoList.contains(modelParam.getVideoId())) {
+                // Video is in the no-ad list, do not show the ad
+                result.put("mid_group", midGroup);
+                result.put("ad_predict", 1);
+                result.put("no_ad_strategy", "no_ad_mid_group_with_video");
+                return result;
+            }
+        }
+        result = predictWithRateProcess(modelParam,midGroup);
+        return result;
+    }
+
+    public Map<String, Object> predictWithRateProcess(ThresholdPredictModelParam modelParam,String midGroup){
+        Double groupShareRate=paramHelper.getGroupShareRate(modelParam.getAbtestParam(),modelParam.getDate(),midGroup);
+        Double videoShareRate=paramHelper.getVideoShareRate(modelParam.getAbtestParam(),modelParam.getDate(),modelParam.getVideoId());
+        double threshold = paramHelper.getThreshold(
+                modelParam.getAbtestId(),
+                modelParam.getAbTestConfigTag(),
+                modelParam.getAbTestCode(),
+                midGroup,
+                modelParam.getCareModelStatus(),
+                modelParam.getAbtestParam()
+        );
+        ThresholdCalculateParam calculateParam=ThresholdCalculateParam.builder()
+                .groupShareRate(groupShareRate)
+                .videoShareRate(videoShareRate).build();
+
+        Double midVideoPredictRes=ThresholdPredictCalculator.basicCalculate(calculateParam);
+        int adPredict=midVideoPredictRes > threshold?2:1;
+        Map<String, Object> resul=new HashMap<>();
+        resul.put("mid_group", midGroup);
+        resul.put("group_share_rate", groupShareRate);
+        resul.put("video_share_rate", videoShareRate);
+        resul.put("mid_video_predict_res", midVideoPredictRes);
+        resul.put("threshold", threshold);
+        resul.put("ad_predict", adPredict);
+        return new HashMap<>();
+    }
+}

+ 92 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/MultiplyThresholdPredictModel.java

@@ -0,0 +1,92 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.threshold;
+
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.calculator.ThresholdPredictCalculator;
+import com.tzld.piaoquan.ad.engine.service.predict.config.RuleRedisKeyConst;
+import com.tzld.piaoquan.ad.engine.service.predict.param.RuleParamHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdCalculateParam;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class MultiplyThresholdPredictModel  extends ThresholdPredictModel{
+
+    @Autowired
+    RuleParamHelper paramHelper;
+
+    @Autowired
+    AdOwnRedisHelper redisHelper;
+    /**
+     * setModelName
+     */
+    @Override
+    String initName() {
+        return "multiply";
+    }
+
+    @Override
+    public Map<String, Object> predict(ThresholdPredictModelParam modelParam) {
+        Map<String, Object> result = new HashMap<>();
+        // Determine the group to which mid belongs
+        String groupClassKey = (String) modelParam.getAbtestParam().get("group_class_key");
+        String midGroupKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_MID_GROUP + groupClassKey + ":" + modelParam.getMid();
+        String midGroup = redisHelper.getString(midGroupKeyName);
+        if (midGroup == null) {
+            midGroup = "mean_group";
+        }
+        // Check if the user is in the no-ad group list
+
+        // Get group and video share rates
+        Double groupShareRate = paramHelper.getGroupShareRate(modelParam.getAbtestParam(),modelParam.getDate(),midGroup);
+        Double videoShareRate = paramHelper.getVideoShareRate(modelParam.getAbtestParam(), modelParam.getDate(),modelParam.getVideoId());
+        // Get group and video out rates
+        Double groupOutRate = paramHelper.getGroupOutRate(modelParam.getAbtestParam(),modelParam.getDate(),midGroup);
+        Double videoOutRate = paramHelper.getVideoOutRate(modelParam.getAbtestParam(), modelParam.getDate(),modelParam.getVideoId());
+
+        // Calculate mid-video prediction result
+        if (groupShareRate == null || videoShareRate == null || groupOutRate == null || videoOutRate == null) {
+            return null;
+        }
+        ThresholdCalculateParam calculateParam=ThresholdCalculateParam.builder()
+                .groupOutRate(groupOutRate)
+                .groupShareRate(groupShareRate)
+                .videoOutRate(videoOutRate)
+                .videoShareRate(videoShareRate).build();
+        double midVideoPredictRes = ThresholdPredictCalculator.multiplyCalculate(calculateParam);
+
+        // Get the threshold
+        double threshold = paramHelper.getThreshold(
+                modelParam.getAbtestId(),
+                modelParam.getAbTestConfigTag(),
+                modelParam.getAbTestCode(),
+                midGroup,
+                modelParam.getCareModelStatus(),
+                modelParam.getAbtestParam()
+        );
+        // Threshold check
+        int adPredict=midVideoPredictRes > threshold?2:1;
+//            if (midVideoPredictRes > threshold) {
+//                // Greater than the threshold, show the ad
+//                adPredict = 2;
+//            } else {
+//                // Otherwise, do not show the ad
+//                adPredict = 1;
+//            }
+        result.put("mid_group", midGroup);
+        result.put("group_share_rate", groupShareRate);
+        result.put("video_share_rate", videoShareRate);
+        result.put("group_out_rate", groupOutRate);
+        result.put("video_out_rate", videoOutRate);
+        //中间计算参数 返回结果目前ad用不到
+//        result.put("group_rate", groupRate);
+//        result.put("video_rate", videoRate);
+        result.put("mid_video_predict_res", midVideoPredictRes);
+        result.put("threshold", threshold);
+        result.put("ad_predict", adPredict);
+        return result;
+    }
+}

+ 29 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/RoiThresholdPredictModel.java

@@ -0,0 +1,29 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.threshold;
+
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.RuleParamHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class RoiThresholdPredictModel extends ThresholdPredictModel{
+
+    @Autowired
+    RuleParamHelper paramHelper;
+
+    @Autowired
+    AdOwnRedisHelper redisHelper;
+
+    @Override
+    String initName() {
+        return "roi";
+    }
+
+    @Override
+    public Map<String, Object> predict(ThresholdPredictModelParam modelParam) {
+        return null;
+    }
+}

+ 98 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/ScoreThresholdPredictModel.java

@@ -0,0 +1,98 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.threshold;
+
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.config.AdOutV1OnlineWeightConfig;
+import com.tzld.piaoquan.ad.engine.service.predict.config.RuleRedisKeyConst;
+import com.tzld.piaoquan.ad.engine.service.predict.model.containner.ThresholdModelContainer;
+import com.tzld.piaoquan.ad.engine.service.predict.param.RuleParamHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class ScoreThresholdPredictModel extends ThresholdPredictModel{
+
+    @Autowired
+    RuleParamHelper paramHelper;
+
+    @Autowired
+    AdOwnRedisHelper redisHelper;
+
+    @Override
+    String initName() {
+        return "model";
+    }
+    @Override
+    public Map<String, Object> predict(ThresholdPredictModelParam modelParam) {
+        Map<String, Object> result;
+
+        String modelKey = (String) modelParam.getAbtestParam().getOrDefault("model_key", "ad_out_v1");
+        String userKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_USER + modelKey + ":" + modelParam.getMid();
+        String itemKeyName = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_ITEM + modelKey + ":" + modelParam.getVideoId();
+
+        String userScore = redisHelper.get(userKeyName);
+        String itemScore = redisHelper.get(itemKeyName);
+
+        if (userScore == null || itemScore == null) {
+            // If offline scores are empty, fall back to baseline logic
+            result = ThresholdModelContainer.
+                    getBasicPredictModel()
+                    .predict(modelParam);
+            return result;
+        }
+        String configKeyPrefix = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_OUT_MODEL_CONFIG
+                + modelKey + ":" + modelParam.getAbtestParam().get("abtest_id") + ":"
+                + modelParam.getAbtestParam().get("abtest_config_tag");
+        String thresholdKey = configKeyPrefix + ":threshold";
+        double offlineScore = Double.parseDouble(userScore) + Double.parseDouble(itemScore);
+
+        SimpleDateFormat hourFormat = new SimpleDateFormat("HH");
+        SimpleDateFormat weekDayFormat = new SimpleDateFormat("u");
+
+
+        Map<String, String> onlineFeatures = new HashMap<>();
+        onlineFeatures.put("ctx_apptype", modelParam.getAppType().toString());
+        onlineFeatures.put("ctx_week", weekDayFormat.format(modelParam.getDate()));
+        onlineFeatures.put("ctx_hour", hourFormat.format(modelParam.getDate()));
+        // Call the getFinalScore method to calculate final and online scores
+        // (You need to implement this method according to your specific logic)
+        double onlineScore=getOlineScore(onlineFeatures);
+        double finalScore =getFinalScore(onlineScore,offlineScore);
+
+        String thresholdValue = redisHelper.get(thresholdKey);
+        double threshold = (thresholdValue != null) ? Double.parseDouble(thresholdValue) : 0.0;
+
+        int adPredict;
+        if (finalScore < threshold) {
+            // If final score is below threshold, show the ad
+            adPredict = 2;
+        } else {
+            // Otherwise, do not show the ad
+            adPredict = 1;
+        }
+        result=new HashMap<>();
+        result.put("user_score", userScore);
+        result.put("item_score", itemScore);
+        result.put("final_score", finalScore);
+        result.put("online_score", onlineScore);
+        result.put("threshold", threshold);
+        result.put("ad_predict", adPredict);
+        result.put("online_features", onlineFeatures);
+        return result;
+    }
+
+    private double getFinalScore(Double onlineScore,Double offlineScore) {
+        double finalScore = onlineScore + offlineScore;
+        return 1.0 / (1.0 + Math.exp(0d-finalScore));
+    }
+
+    private double getOlineScore(Map<String, String> onlineFeatures ) {
+        double score = AdOutV1OnlineWeightConfig.getWeight("bias");
+        for (Map.Entry<String, String> entry : onlineFeatures.entrySet()) {
+            double featureScore = AdOutV1OnlineWeightConfig.getWeight(entry.getKey() + "#" +  entry.getValue());
+            score += featureScore;
+        }
+        return score;
+    }
+}

+ 24 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/model/threshold/ThresholdPredictModel.java

@@ -0,0 +1,24 @@
+package com.tzld.piaoquan.ad.engine.service.predict.model.threshold;
+
+import com.tzld.piaoquan.ad.engine.service.predict.model.Model;
+import com.tzld.piaoquan.ad.engine.service.predict.param.ThresholdPredictModelParam;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+@Getter
+@Setter
+public abstract class ThresholdPredictModel implements Model {
+
+    private final String name;
+
+    abstract public Map<String,Object>  predict(ThresholdPredictModelParam modelParam);
+
+    abstract String initName();
+    public ThresholdPredictModel(){
+        this.name=initName();
+    }
+
+
+}

+ 151 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/RuleParamHelper.java

@@ -0,0 +1,151 @@
+package com.tzld.piaoquan.ad.engine.service.predict.param;
+
+import com.tzld.piaoquan.ad.engine.commons.redis.AdOwnRedisHelper;
+import com.tzld.piaoquan.ad.engine.service.predict.config.RuleRedisKeyConst;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Component
+public class RuleParamHelper {
+
+    @Autowired
+    private AdOwnRedisHelper redisHelper;
+
+    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+    //避免空指异常及重复创建过多Obj
+    Map<String,Object> defaultMap=new HashMap<>();
+    public Double getGroupShareRate( Map<String, Object> abTestParam,Date nowDate,String midGroup){
+        String nowDt = dateFormat.format(nowDate);
+        String shareUserDataKey = (String) ((Map<String,Object>)
+                ((Map<String,Object>)abTestParam.getOrDefault("share",defaultMap))
+                        .getOrDefault("user",defaultMap)).get("data");
+        String shareUserRuleKey = (String) ((Map<String,Object>)
+                ((Map<String,Object>)abTestParam.getOrDefault("share",defaultMap))
+                        .getOrDefault("user",defaultMap)).get("rule");
+        String groupShareRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_GROUP + shareUserDataKey + ":" + shareUserRuleKey + ":" + nowDt;
+
+        if (StringUtils.isEmpty(shareUserDataKey)||StringUtils.isEmpty(shareUserRuleKey)|| !redisHelper.contantinsKey(groupShareRateKey)) {
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(nowDate);
+            cal.add(Calendar.DATE, -1);
+            Date yesterday = cal.getTime();
+            String redisDt = dateFormat.format(yesterday);
+            groupShareRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_GROUP + shareUserDataKey + ":" + shareUserRuleKey + ":" + redisDt;
+        }
+
+        Double groupShareRate = redisHelper.zScore(groupShareRateKey, midGroup);
+        return groupShareRate;
+    }
+
+    public Double getVideoShareRate( Map<String, Object> abTestParam,Date nowDate,Long videoId){
+        String nowDt = dateFormat.format(nowDate);
+        String shareVideoDataKey = (String) ((Map<String,Object>)
+                ((Map<String,Object>)abTestParam.getOrDefault("share",defaultMap))
+                        .getOrDefault("video",defaultMap)).get("data");
+        String videoShareRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_VIDEO + shareVideoDataKey + ":" + nowDt;
+
+        if (StringUtils.isEmpty(shareVideoDataKey)||!redisHelper.contantinsKey(videoShareRateKey)) {
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(nowDate);
+            cal.add(Calendar.DATE, -1);
+            Date yesterday = cal.getTime();
+            String redisDt = dateFormat.format(yesterday);
+            videoShareRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_VIDEO + shareVideoDataKey + ":" + redisDt;
+        }
+
+        Double videoShareRate = redisHelper.zScore(videoShareRateKey, videoId.toString());
+        if (videoShareRate == null) {
+                videoShareRate = redisHelper.zScore(videoShareRateKey, -1+"");
+        }
+
+        return videoShareRate;
+    }
+
+    public Double getGroupOutRate(Map<String, Object> abTestParam,Date nowDate,String midGroup){
+        String nowDt = dateFormat.format(nowDate);
+        String outUserDataKey = (String) ((Map<String,Object>)
+                ((Map<String,Object>)abTestParam.getOrDefault("out",defaultMap))
+                        .getOrDefault("user",defaultMap)).get("data");
+        String outUserRuleKey = (String) ((Map<String,Object>)
+                ((Map<String,Object>)abTestParam.getOrDefault("out",defaultMap))
+                        .getOrDefault("user",defaultMap)).get("rule");
+        String groupOutRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_GROUP + outUserDataKey + ":" + outUserRuleKey + ":" + nowDt;
+
+        if (StringUtils.isEmpty(outUserDataKey)||StringUtils.isEmpty(outUserRuleKey)
+                ||!redisHelper.contantinsKey(groupOutRateKey)) {
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(nowDate);
+            cal.add(Calendar.DATE, -1);
+            Date yesterday = cal.getTime();
+            String redisDt = dateFormat.format(yesterday);
+            groupOutRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_GROUP + outUserDataKey + ":" + outUserRuleKey + ":" + redisDt;
+        }
+
+
+        return redisHelper.zScore(groupOutRateKey, midGroup);
+    }
+
+    public Double getVideoOutRate(Map<String, Object> abTestParam,Date nowDate,Long videoId){
+        String nowDt = dateFormat.format(nowDate);
+        String outVideoDataKey = (String)((Map<String,Object>)
+                ((Map<String,Object>)abTestParam.getOrDefault("out",defaultMap)).getOrDefault("video",defaultMap)).get("data");
+        String videoOutRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_VIDEO + outVideoDataKey + ":" + nowDt;
+
+        if (StringUtils.isEmpty(outVideoDataKey)||!redisHelper.contantinsKey(videoOutRateKey)) {
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(nowDate);
+            cal.add(Calendar.DATE, -1);
+            Date yesterday = cal.getTime();
+            String redisDt = dateFormat.format(yesterday);
+            videoOutRateKey = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_VIDEO + outVideoDataKey + ":" + redisDt;
+        }
+
+        Double videoOutRate = redisHelper.zScore(videoOutRateKey, videoId.toString());
+        if (videoOutRate == null) {
+                videoOutRate = redisHelper.zScore(videoOutRateKey, -1+"");
+        }
+        return videoOutRate;
+    }
+
+    public double getThreshold(
+            String abtestId,
+            String abtestConfigTag,
+            String abTestCode,
+            String midGroup,
+            Long careModelStatus,
+            @NotNull Map<String, Object> abtestParam
+    ) {
+        // Check if it is a care model experiment
+//        Map<String, Object> careModelStatusParam = (Map<String, Object>) abtestParam.get("care_model_status_param");
+        Map<String, Object> careModelStatusParam = (Map<String, Object>) abtestParam.get("care_model_status_param");
+        List<String> careModelAbMidGroup = (List<String>) abtestParam.get("care_model_ab_mid_group");
+
+        String thresholdKeyNamePrefix;
+        if (careModelStatusParam == null) {
+            // No care model experiment
+            thresholdKeyNamePrefix = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_THRESHOLD;
+        } else {
+            // Care model experiment
+            if (careModelStatus == null || careModelAbMidGroup.isEmpty() || "null".equals(careModelStatus)) {
+                // Missing parameters, use default
+                thresholdKeyNamePrefix = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_THRESHOLD;
+            } else if (careModelStatus == (Long) careModelStatusParam.get("value") && careModelAbMidGroup.contains(midGroup)) {
+                // Experiment matches, get the corresponding threshold
+                thresholdKeyNamePrefix = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_THRESHOLD_CARE_MODEL;
+            } else {
+                thresholdKeyNamePrefix = RuleRedisKeyConst.KEY_NAME_PREFIX_AD_THRESHOLD;
+            }
+        }
+
+        String thresholdKeyName = thresholdKeyNamePrefix + abtestId + ":" + abtestConfigTag + ":" + abTestCode + ":" + midGroup;
+        String thresholdStr = redisHelper.get(thresholdKeyName);
+        double threshold = (thresholdStr != null) ? Double.parseDouble(thresholdStr) : 0.0;
+
+        return threshold;
+    }
+}

+ 19 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/ThresholdCalculateParam.java

@@ -0,0 +1,19 @@
+package com.tzld.piaoquan.ad.engine.service.predict.param;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class ThresholdCalculateParam {
+
+    Double shareWeight;
+
+    Double outWeight;
+
+    Double groupShareRate;
+    Double groupOutRate;
+    Double videoShareRate;
+    Double videoOutRate;
+
+}

+ 33 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/ThresholdPredictModelParam.java

@@ -0,0 +1,33 @@
+package com.tzld.piaoquan.ad.engine.service.predict.param;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ *  mid mid
+ *  videoId video_id
+ *  appType  app_id
+ *  abTestCode  用户对应的ab组--对应java group
+ *  abExpInfo AB实验组参数--封装后对应ab_exp_info
+ *  careModelStatus  用户关怀模式状态 1-未开启,2-开启
+ */
+@Data
+@Builder
+public class ThresholdPredictModelParam {
+    String mid;
+    Long videoId;
+    Integer appType;
+    String abTestCode;
+    JSONObject abExpInfo;
+    Long careModelStatus;
+    String abtestId;
+    String abTestConfigTag;
+    Map<String,Object> abtestParam;
+
+    String midGroup;
+    Date date=new Date();
+}

+ 13 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/AdCheckShowAdDto.java

@@ -0,0 +1,13 @@
+package com.tzld.piaoquan.ad.engine.service.predict.param.request;
+
+import lombok.Data;
+
+@Data
+public class AdCheckShowAdDto {
+
+    private String adId;
+
+    private Integer adType;
+
+    private Double ecpm;
+}

+ 15 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/RoiPredictModelRequestParam.java

@@ -0,0 +1,15 @@
+package com.tzld.piaoquan.ad.engine.service.predict.param.request;
+
+import lombok.Data;
+import java.util.*;
+@Data
+public class RoiPredictModelRequestParam {
+
+    String mid;
+
+    Long videoId;
+
+    Integer appType;
+
+    List<AdCheckShowAdDto> ads;
+}

+ 21 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/predict/param/request/ThresholdPredictModelRequestParam.java

@@ -0,0 +1,21 @@
+package com.tzld.piaoquan.ad.engine.service.predict.param.request;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+/**
+ *  mid mid
+ *  videoId video_id
+ *  appType  app_id
+ *  abTestCode  用户对应的ab组--对应java group
+ *  abExpInfo AB实验组参数--封装后对应ab_exp_info
+ *  careModelStatus  用户关怀模式状态 1-未开启,2-开启
+ */
+@Data
+public class ThresholdPredictModelRequestParam {
+    String mid;
+    Long videoId;
+    Integer appType;
+    String abTestCode;
+    JSONObject abExpInfo;
+    Long careModelStatus;
+}

+ 10 - 0
pom.xml

@@ -20,6 +20,11 @@
         <module>ad-engine-service</module>
     </modules>
 
+    <properties>
+        <stuuudy.commons.utils.version>1.0-SNAPSHOT</stuuudy.commons.utils.version>
+<!--        <aliyun.rocketmq.version>1.8.4.Final</aliyun.rocketmq.version>-->
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -85,6 +90,11 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.4</version>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>