소스 검색

加入CPC_pid

gufengshou1 11 달 전
부모
커밋
1b30ed7062

+ 245 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/container/PidLambdaForCpcContainer.java

@@ -0,0 +1,245 @@
+package com.tzld.piaoquan.ad.engine.service.score.container;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.common.auth.CredentialsProvider;
+import com.aliyun.oss.common.auth.DefaultCredentialProvider;
+import com.aliyun.oss.model.CopyObjectResult;
+import com.aliyun.oss.model.OSSObject;
+import com.aliyun.oss.model.PutObjectResult;
+import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class PidLambdaForCpcContainer {
+    private final static Logger log = LoggerFactory.getLogger(PidLambdaForCpcContainer.class);
+
+    private static final int SCHEDULE_PERIOD = 10;
+    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+    @Value("${model.oss.internal.endpoint:oss-cn-hangzhou.aliyuncs.com}")
+    String endpoint = "";
+    @Value("${model.oss.accessKeyId:LTAIP6x1l3DXfSxm}")
+    String accessKeyId = "";
+    @Value("${model.oss.accessKetSecret:KbTaM9ars4OX3PMS6Xm7rtxGr1FLon}")
+    String accessKetSecret = "";
+    @Value("${model.oss.bucketName:art-recommend}")
+    String bucketName = "";
+
+    @Value("${model.oss.pid.cpc.filename.lambda:pid/lambda_cpc.txt}")
+    String lambdaFileName = "";
+
+    @Value("${model.oss.pid.cpc.filename.dCpa:pid/dCpa_cpc.txt}")
+    String dCpaFileName = "";
+
+    @Value("${ad.model.pid.cpc.kp:0.4}")
+    Double kp = 0d;
+
+    @Value("${ad.model.pid.cpc.ki:0.4}")
+    Double ki = 0d;
+
+    @Value("${ad.model.pid.cpc.kd:0.2}")
+    Double kd = 0d;
+
+    @Value("${ad.model.pid.cpc.lambda.max:5.0}")
+    Double maxLambda = 0d;
+
+    @Value("${ad.model.pid.cpc.lambda.min:0.2}")
+    Double minLambda = 0d;
+    OSS client;
+
+    private static ConcurrentHashMap<Long, CpcCacheItem>  lambdaCache=new ConcurrentHashMap<>();
+    private Date cacheDate;
+
+    @PostConstruct
+    private void init(){
+        instanceClient();
+        final Runnable task = new Runnable() {
+            public void run() {
+                try {
+                    loadAndCalIfNeed();
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        };
+        scheduler.scheduleAtFixedRate(task, 0, SCHEDULE_PERIOD, TimeUnit.MINUTES); // 10分钟
+    }
+
+    private void instanceClient(){
+        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKetSecret);
+        this.client = new OSSClientBuilder().build(endpoint, credentialsProvider);
+    }
+
+    private void loadAndCalIfNeed(){
+        loadLambdaFile();
+        OSSObject dCpaFileOjb=client.getObject(bucketName,dCpaFileName);
+        if(cacheDate==null||dCpaFileOjb.getObjectMetadata().getLastModified().after(cacheDate)){
+            calNewLambda(dCpaFileOjb);
+            writeLambdaFileToOss();
+        }
+    }
+
+    private void calNewLambda(OSSObject object) {
+        try {
+            InputStream is=object.getObjectContent();
+            InputStreamReader isr=new InputStreamReader(is);
+            BufferedReader bufferedReader = new BufferedReader(isr);
+            String line = null;
+            ConcurrentHashMap<Long, CpcCacheItem>  temp=new ConcurrentHashMap<>();
+            Double conversion=0d;
+            Double cpa=0d;
+            Double realCost=0d;
+            Double latestRealCPA=0d;
+            double sumE=0d;
+            while ((line = bufferedReader.readLine()) != null){
+                try {
+                    String[] cols=line.split(",");
+                    Long creativeId=Long.parseLong(cols[0]);
+                    CpcCacheItem cacheItem=lambdaCache.getOrDefault(creativeId,new CpcCacheItem(creativeId));
+                    if(DateUtils.getCurrentHour()<=8){
+                        temp.put(creativeId,cacheItem);
+                        continue;
+                    }
+                    conversion=Double.parseDouble(cols[1]);
+                    cpa=Double.parseDouble(cols[2]);
+                    realCost=Double.parseDouble(cols[3]);
+                    if(conversion<1d){
+                        temp.put(creativeId,cacheItem);
+                        continue;
+                    }
+                    latestRealCPA=realCost/conversion;
+                    if(Math.abs(latestRealCPA-cacheItem.latestRealCpa)<0.01){
+                        temp.put(creativeId,cacheItem);
+                        continue;
+                    }
+                    Double lambdaNew =cacheItem.calculate(kp,ki,kd,cpa,latestRealCPA);
+                    if(lambdaNew<minLambda){
+                        lambdaNew=minLambda;
+                    }
+                    cacheItem.lambda=lambdaNew;
+                    cacheItem.latestRealCpa=latestRealCPA;
+                    cacheItem.sumError=sumE;
+                    cacheItem.latestConv=conversion;
+
+                    temp.put(creativeId,cacheItem);
+
+                    log.info("svc=calCPCLambda creativeId={} lambdaNew={}", creativeId,lambdaNew);
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+            lambdaCache.clear();
+            lambdaCache=temp;
+        }catch (Exception e){
+            log.error("svc=calCPCLambda status=failed error={}", Arrays.toString(e.getStackTrace()));
+        }
+    }
+
+    private void writeLambdaFileToOss(){
+        //先不考虑各种更新失败及重复更新问题。
+        try {
+            String tempFile=lambdaFileName+"_temp";
+            String content= JSONObject.toJSONString(lambdaCache);
+            PutObjectResult putObjectResult=client.putObject(bucketName,tempFile,new ByteArrayInputStream(content.getBytes()));
+            CopyObjectResult copyObjectResult=client.copyObject(bucketName, tempFile, bucketName, lambdaFileName);
+            this.cacheDate= copyObjectResult.getLastModified();
+            client.deleteObject(bucketName, tempFile);
+        }catch (Exception e){
+            log.error("svc=writeCPCLambdaFileToOss status=failed error={}", Arrays.toString(e.getStackTrace()));
+            e.printStackTrace();
+        }
+    }
+
+    private void loadLambdaFile(){
+        try {
+            OSSObject object=client.getObject(bucketName,lambdaFileName);
+            if(object==null) return;
+            if(cacheDate!=null&& !cacheDate.before(object.getObjectMetadata().getLastModified())) return;
+            StringBuilder builder=new StringBuilder();
+            InputStream is=object.getObjectContent();
+            InputStreamReader isr=new InputStreamReader(is);
+            BufferedReader bufferedReader = new BufferedReader(isr);
+            String line = null;
+            while ((line=bufferedReader.readLine())!=null){
+                builder.append(line);
+            }
+            lambdaCache=JSONObject.parseObject(builder.toString(),new TypeReference<ConcurrentHashMap<Long, CpcCacheItem>>(){});
+            this.cacheDate=object.getObjectMetadata().getLastModified();
+        }catch (Exception e){
+            log.error("svc=loadCPCLambdaFile status=failed error={}", Arrays.toString(e.getStackTrace()));
+            e.printStackTrace();
+        }
+    }
+
+    public static Double getPidLambda(Long creativeId){
+        try {
+            return lambdaCache.getOrDefault(creativeId,new CpcCacheItem(creativeId)).lambda;
+        }catch (Exception e){
+            return 1d;
+        }
+    }
+
+
+    public static class CpcCacheItem {
+
+        public CpcCacheItem(){
+
+        }
+
+        public CpcCacheItem(Long creativeId){
+            this.creativeId=creativeId;
+        }
+
+        public Long creativeId;
+
+        public double lambda=-1d;
+
+        public double latestConv=0d;
+
+        public double sumError=0d;
+
+        public double latestRealCpa=0d;
+
+        public double processVariable=0d; // 处理变量
+        public double integral=0d; // 积分项
+        public double lastError=0d; // 上一个误差
+
+        public double lastPidValue=0d;
+
+        public double calculate(double kp, double ki, double kd, double setPoint,double currentValue) {
+            processVariable = currentValue;
+            double error = setPoint - processVariable;
+
+            integral += error;
+            if(Math.abs(integral)>2*setPoint){
+                integral=(Math.abs(integral)/integral)*2*setPoint;
+            }
+            double derivative = (error - lastError) / 1; // 假设采样间隔为1
+            lastError = error;
+            return lambda+kp * error + ki * integral + kd * derivative;
+        }
+
+        public void reset() {
+            integral = 0;
+            lastError = 0;
+        }
+
+    }
+}

+ 59 - 32
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/impl/RankServiceImpl.java

@@ -3,6 +3,7 @@ package com.tzld.piaoquan.ad.engine.service.score.impl;
 import com.alibaba.fastjson.JSONObject;
 import com.tzld.piaoquan.ad.engine.service.score.container.AdCreativeFeatureContainer;
 import com.tzld.piaoquan.ad.engine.service.score.container.PidLambdaContainer;
+import com.tzld.piaoquan.ad.engine.service.score.container.PidLambdaForCpcContainer;
 import com.tzld.piaoquan.ad.engine.service.score.container.PidLambdaV2Container;
 import com.tzld.piaoquan.ad.engine.service.score.dto.AdPlatformCreativeDTO;
 import com.tzld.piaoquan.ad.engine.service.score.param.BidRankRecommendRequestParam;
@@ -45,6 +46,8 @@ public class RankServiceImpl implements RankService {
     Double cpmMax=200d;
     @Value("${ad.model.cpm.min:30}")
     Double cpmMin=30d;
+    @Value("${ad.pid.cpc.exp:30}")
+    private String cpcPidExpCode;
 
     public AdRankItem adItemRank(RankRecommendRequestParam request){
         ScoreParam param= RequestConvert.requestConvert(request);
@@ -65,7 +68,6 @@ public class RankServiceImpl implements RankService {
                 .getAdIdList()
                 .stream()
                 .collect(Collectors.groupingBy(creativeDTO -> creativeDTO.getCreativeId()));
-//        Map<Long, AdRankItem> cache=adCreativeFeatureContainer.getAll(request.getAdIdList());
         Map<Long, AdRankItem> cache=adCreativeFeatureContainer.getAll(new ArrayList<>(groupMap.keySet()));
         List<AdRankItem> rankItems=Collections.emptyList();
         if(!cache.isEmpty()){
@@ -81,42 +83,58 @@ public class RankServiceImpl implements RankService {
                 rankItems.add(item);
             }
         }
+        boolean inCpcPidExp=false;
+        if (request.getAdAbExpArr() != null && request.getAdAbExpArr().size() != 0) {
+            for (Map<String, Object> map : request.getAdAbExpArr() ) {
+                if (map.getOrDefault("abExpCode", "").equals(cpcPidExpCode)) {
+                    inCpcPidExp = true;
+                }
+            }
+        }
         double lambda=-1d;
-        for(AdRankItem item:rankItems){
-            try {
-//                AdPlatformBidCreativeDTO dto=groupMap.get(item.getAdId()+"").get(0);
-                AdPlatformCreativeDTO dto=groupMap.get(item.getAdId()).get(0);
-                item.setBid1(dto.getBid1());
-                item.setBid2(dto.getBid2());
-//                lambda=PidLambdaContainer.getPidLambda(item.getAdId());
-//                if(lambda<0){
-//                    item.setCpa(dto.getCpa());
-//                    item.setPidLambda(0.6);
-//                }else {
-//                    if(dto.getCpa()>1&&lambda<=1){
-//                        lambda=2d;
-//                    }
-//                    item.setCpa(lambda);
-//                    item.setPidLambda(1d);
-//                }
-                item.setCpa(dto.getCpa());
-                item.setPidLambda(1d);
-            }catch (Exception e){
-                log.error("rankItems info error itemId={}",item.getAdId());
-                e.printStackTrace();
+        if(inCpcPidExp){
+            for(AdRankItem item:rankItems){
+                try {
+                    AdPlatformCreativeDTO dto=groupMap.get(item.getAdId()).get(0);
+                    item.setBid1(dto.getBid1());
+                    item.setBid2(dto.getBid2());
+                    item.setCpa(dto.getCpa());
+                    item.setPidLambda(1d);
+                }catch (Exception e){
+                    log.error("rankItems info error itemId={}",item.getAdId());
+                    e.printStackTrace();
+                }
+            }
+        }else {
+            for(AdRankItem item:rankItems){
+                try {
+                    AdPlatformCreativeDTO dto=groupMap.get(item.getAdId()).get(0);
+                    item.setBid1(dto.getBid1());
+                    item.setBid2(dto.getBid2());
+                    lambda= PidLambdaForCpcContainer.getPidLambda(item.getAdId());
+                    if(lambda<0){
+                        item.setCpa(dto.getCpa());
+                        item.setPidLambda(1);
+                    }else {
+                        if(dto.getCpa()>1&&lambda<=1){
+                            lambda=2d;
+                        }
+                        item.setCpa(lambda);
+                        item.setPidLambda(1d);
+                    }
+                    item.setCpa(dto.getCpa());
+                    item.setPidLambda(1d);
+                }catch (Exception e){
+                    log.error("rankItems info error itemId={}",item.getAdId());
+                    e.printStackTrace();
+                }
             }
         }
-//        for(AdRankItem item:rankItems){
-//            item.setBid1(1d);
-//            item.setBid2(1d);
-//            item.setCpa(75d);
-//            item.setPidLambda(1d);
-//        }
+
         //兜底方案
         List<AdRankItem> rankResult=rank(param, userAdFeature, rankItems,ScorerUtils.BASE_CONF);
 
         if (!CollectionUtils.isEmpty(rankResult)) {
-//            log.info("svc=adItemRank request={} rankResult={} dataTime={}", JSONObject.toJSONString(request),JSONObject.toJSONString(rankResult),currentTime.format(timeFormatter));
             JSONObject object=new JSONObject();
             object.put("mid",request.getMid());
             object.put("adid",rankResult.get(0).getAdId());
@@ -127,9 +145,17 @@ public class RankServiceImpl implements RankService {
             object.put("pidLambda",rankResult.get(0).getPidLambda());
             object.put("lrsamples",rankResult.get(0).getLrSampleString());
             object.put("dataTime",currentTime.format(timeFormatter));
+
             log.info("svc=adItemRank {}", JSONObject.toJSONString(object));
             object.remove("lrsamples");
-            log.info("svc=pid_log obj={}", JSONObject.toJSONString(object));
+            if(inCpcPidExp){
+                AdPlatformCreativeDTO dto=groupMap.get(rankResult.get(0).getAdId()).get(0);
+                object.put("cpa",dto.getCpa()*dto.getBid1());
+                object.put("oCpa",dto.getCpa());
+                log.info("svc=cpc_pid obj={}", JSONObject.toJSONString(object));
+            }else {
+                log.info("svc=pid_log obj={}", JSONObject.toJSONString(object));
+            }
             return rankResult.get(0);
         }else {
             //空返回值
@@ -137,6 +163,8 @@ public class RankServiceImpl implements RankService {
         }
     }
 
+
+
     @Override
     public AdPlatformCreativeDTO adBidRank(BidRankRecommendRequestParam request) {
 
@@ -169,7 +197,6 @@ public class RankServiceImpl implements RankService {
         double lambda=-1d;
         for(AdRankItem item:rankItems){
             try {
-//                AdPlatformBidCreativeDTO dto=groupMap.get(item.getAdId()+"").get(0);
                 AdPlatformCreativeDTO dto=groupMap.get(item.getAdId()).get(0);
                 item.setBid1(dto.getBid1());
                 item.setBid2(dto.getBid2());

+ 18 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/impl/RankServiceThompsonImpl.java

@@ -45,6 +45,24 @@ public class RankServiceThompsonImpl implements RankService {
         }
     }
 
+    public AdRankItem adItemRankV2(RankRecommendRequestParam request) {
+
+        ScoreParam param = RequestConvert.requestConvert(request);
+        UserAdFeature userAdFeature = new UserAdFeature();
+        List<AdRankItem> rankItems = featureRemoteService.getAllAdFeatureList(
+                CommonCollectionUtils.toList(request.getAdIdList(), creativeDTO -> creativeDTO.getCreativeId().toString())
+        );
+        List<AdRankItem> rankResult = ScorerUtils
+                .getScorerPipeline(ScorerUtils.THOMPSON_CONF)
+                .scoring(param, userAdFeature, rankItems);
+
+        if (!CollectionUtils.isEmpty(rankResult)) {
+            return rankResult.get(0);
+        } else {
+            return null;
+        }
+    }
+
     @Override
     public AdPlatformCreativeDTO adBidRank(BidRankRecommendRequestParam request) {
         return null;

+ 5 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/score/param/RecommendRequestParam.java

@@ -3,6 +3,9 @@ package com.tzld.piaoquan.ad.engine.service.score.param;
 import lombok.Data;
 import lombok.ToString;
 
+import java.util.List;
+import java.util.Map;
+
 @Data
 @ToString
 public class RecommendRequestParam {
@@ -14,4 +17,6 @@ public class RecommendRequestParam {
     //市-中文
     String city = "-1";
     Integer newExpGroup;
+
+    List<Map> adAbExpArr ;
 }