From beb7c2494fc631605f720ac54ca918853f0eda80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=8D=93?= Date: Wed, 12 Nov 2025 14:36:26 +0800 Subject: [PATCH 1/3] (feat) add global_scene --- pom.xml | 21 ++- .../openservices/pairec/ExperimentClient.java | 10 +- .../openservices/pairec/common/Constants.java | 1 + .../pairec/model/ExperimentResult.java | 140 +++++++++++++++--- .../openservices/pairec/util/JsonUtils.java | 14 ++ .../pairec/util/TemplateUtils.java | 35 +++++ 6 files changed, 200 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/aliyun/openservices/pairec/util/JsonUtils.java create mode 100644 src/main/java/com/aliyun/openservices/pairec/util/TemplateUtils.java diff --git a/pom.xml b/pom.xml index f39e883..8daf11b 100644 --- a/pom.xml +++ b/pom.xml @@ -265,7 +265,26 @@ mvel2 2.4.12.Final - + + com.fasterxml.jackson.core + jackson-core + 2.15.2 + + + com.fasterxml.jackson.core + jackson-annotations + 2.15.2 + + + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + + + org.apache.commons + commons-lang3 + 3.12.0 + 1.8 diff --git a/src/main/java/com/aliyun/openservices/pairec/ExperimentClient.java b/src/main/java/com/aliyun/openservices/pairec/ExperimentClient.java index f02d07a..eab4a54 100644 --- a/src/main/java/com/aliyun/openservices/pairec/ExperimentClient.java +++ b/src/main/java/com/aliyun/openservices/pairec/ExperimentClient.java @@ -188,10 +188,18 @@ public ExperimentResult matchExperiment(String sceneName, ExperimentContext expe ExperimentResult experimentResult = new ExperimentResult(sceneName, experimentContext); if (!sceneData.containsKey(sceneName)) { - logger.warn("scene:{}, not found the scene info", sceneName); + if (!Constants.Global_Scene_Name.equals(sceneName)){ + logger.warn("scene:{}, not found the scene info", sceneName); + } return experimentResult; } + if (!Constants.Global_Scene_Name.equals(sceneName)) { + experimentResult.setGlobalSceneExperimentResult( + matchExperiment(Constants.Global_Scene_Name, experimentContext) + ); + } + Scene scene = sceneData.get(sceneName); ExperimentRoom defaultExperimentRoom = null; ExperimentRoom matchExperimentRoom = null; diff --git a/src/main/java/com/aliyun/openservices/pairec/common/Constants.java b/src/main/java/com/aliyun/openservices/pairec/common/Constants.java index 499cc4e..ed84178 100644 --- a/src/main/java/com/aliyun/openservices/pairec/common/Constants.java +++ b/src/main/java/com/aliyun/openservices/pairec/common/Constants.java @@ -51,5 +51,6 @@ public static String environmentDesc2OpenApiString(String environment) { return ""; } + public static final String Global_Scene_Name = "pairec_abtest_global_scene"; } diff --git a/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java b/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java index 698574c..7cb54d4 100644 --- a/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java +++ b/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java @@ -1,13 +1,22 @@ package com.aliyun.openservices.pairec.model; import com.aliyun.openservices.pairec.common.Constants; +import com.aliyun.openservices.pairec.util.JsonUtils; +import com.aliyun.openservices.pairec.util.TemplateUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.zip.CheckedOutputStream; + +import static com.aliyun.openservices.pairec.ExperimentClient.logger; public class ExperimentResult { + private static final Logger log = LoggerFactory.getLogger(ExperimentResult.class); private String expId = ""; private String sceneName; @@ -26,6 +35,10 @@ public class ExperimentResult { private LayerParams mergedLayerParams; + private ExperimentResult globalSceneExperimentResult; + + private Map globalParams = new HashMap<>(); + public ExperimentResult(String sceneName, ExperimentContext experimentContext) { this.sceneName = sceneName; this.experimentContext = experimentContext; @@ -91,37 +104,114 @@ public boolean containsLayer(String layerName) { public void init() { StringBuilder buf = new StringBuilder(); - if (null != this.experimentRoom) { + if (null != this.experimentRoom && !Constants.Global_Scene_Name.equals(sceneName)) { buf.append("ER").append(this.experimentRoom.getExpRoomId()); } - for (Layer layer : this.layerList) { - buf.append("_L").append(layer.getLayerId()); - - if (this.layer2ExperimentGroup.containsKey(layer.getLayerName())) { - buf.append("#"); - ExperimentGroup experimentGroup = this.layer2ExperimentGroup.get(layer.getLayerName()); - buf.append("EG").append(experimentGroup.getExpGroupId()); + for(int i = 0;i parsed = JsonUtils.parseJson(groupConfig); + this.globalParams.putAll(parsed); + if(this.experimentContext != null && this.experimentContext.getFilterParams() != null){ + this.experimentContext.getFilterParams().putAll(parsed); + } + }catch (Exception e){ + logger.error(e.getMessage()); + } + }else { + if(groupConfig.contains("${")&& this.globalSceneExperimentResult != null&& !this.globalSceneExperimentResult.getGlobalParams().isEmpty()){ + groupConfig = TemplateUtils.executeTemplate(groupConfig,this.globalSceneExperimentResult.getGlobalParams()); + } + try{ + Map parsed = JsonUtils.parseJson(groupConfig); + layerParams.addParams(parsed); + }catch (Exception e){ + logger.error(e.getMessage()); } + } + } + Experiment experiment = this.layer2Experiment.get(layerName); + if(experiment != null){ + if(experiment.getType() != Constants.Experiment_Type_Default){ + buf.append("#E").append(experiment.getExperimentId()); + } - layerParams.addParams(experiment.getExperimentParams()); + String expConfig = experiment.getExperimentConfig(); + if(expConfig != null && !expConfig.isEmpty()){ + if(Constants.Global_Scene_Name.equals(sceneName)){ + try{ + Map parsed = JsonUtils.parseJson(expConfig); + this.globalParams.putAll(parsed); + if(this.experimentContext!= null && this.experimentContext.getFilterParams() != null){ + this.experimentContext.getFilterParams().putAll(parsed); + } + }catch (Exception e){ + logger.error(e.getMessage()); + } + }else { + if (expConfig.contains("${")&&this.globalSceneExperimentResult != null && !this.globalSceneExperimentResult.getGlobalParams().isEmpty()){ + expConfig = TemplateUtils.executeTemplate(expConfig,this.globalSceneExperimentResult.getGlobalParams()); + } + try { + Map parsed = JsonUtils.parseJson(expConfig); + layerParams.addParams(parsed); + }catch (Exception e){ + logger.error(e.getMessage()); + } + } } + } + + this.layerParamsMap.put(layerName,layerParams); + } + String id = trimTrailingDelimiter(buf.toString()); - this.layerParamsMap.put(layer.getLayerName(), layerParams); + if (!Constants.Global_Scene_Name.equals(sceneName) && this.globalSceneExperimentResult != null){ + String globalId = this.globalSceneExperimentResult.getExpId(); + if (StringUtils.isNotEmpty(globalId)) { + id = id + "_" + globalId; + id = trimTrailingDelimiter(id); } } - this.expId = buf.toString(); + this.expId = id; + } + + private String trimTrailingDelimiter(String s) { + if (s == null || s.isEmpty()) { + return s; + } + int len = s.length(); + char last = s.charAt(len - 1); + if (last == '_' || last == '#') { + return s.substring(0, len - 1); + } + return s; } public LayerParams getLayerParams(String layerName) { @@ -179,4 +269,16 @@ public LayerParams getExperimentParams() { return this.mergedLayerParams; } + + public ExperimentResult getGlobalSceneExperimentResult() { + return globalSceneExperimentResult; + } + + public void setGlobalSceneExperimentResult(ExperimentResult globalSceneExperimentResult) { + this.globalSceneExperimentResult = globalSceneExperimentResult; + } + + public Map getGlobalParams() { + return globalParams; // 或返回 new HashMap<>(globalParams) 保证封装性 + } } diff --git a/src/main/java/com/aliyun/openservices/pairec/util/JsonUtils.java b/src/main/java/com/aliyun/openservices/pairec/util/JsonUtils.java new file mode 100644 index 0000000..0463130 --- /dev/null +++ b/src/main/java/com/aliyun/openservices/pairec/util/JsonUtils.java @@ -0,0 +1,14 @@ +package com.aliyun.openservices.pairec.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; + +public class JsonUtils { + private static final ObjectMapper mapper = new ObjectMapper(); + + public static Map parseJson(String json) throws Exception{ + return mapper.readValue(json, new TypeReference>() { + }); + } +} diff --git a/src/main/java/com/aliyun/openservices/pairec/util/TemplateUtils.java b/src/main/java/com/aliyun/openservices/pairec/util/TemplateUtils.java new file mode 100644 index 0000000..2756fdc --- /dev/null +++ b/src/main/java/com/aliyun/openservices/pairec/util/TemplateUtils.java @@ -0,0 +1,35 @@ +package com.aliyun.openservices.pairec.util; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TemplateUtils { + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}"); + + public static String executeTemplate(String template, Map params){ + if(template == null || params == null) return template; + + Matcher matcher = PLACEHOLDER_PATTERN.matcher(template); + StringBuffer result = new StringBuffer(); + + while (matcher.find()){ + String key = matcher.group(1); + Object value = params.get(key); + + String replacement; + if (value == null){ + replacement = "${" + key +"}"; + }else if (value instanceof Map || value instanceof Iterable){ + replacement = "${" + key + "}"; + }else { + replacement = value.toString(); + } + + matcher.appendReplacement(result,Matcher.quoteReplacement(replacement)); + } + matcher.appendTail(result); + + return result.toString(); + } +} From e2f1f8413e60b25889f405533daec09731b0ebfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=8D=93?= Date: Thu, 13 Nov 2025 10:27:01 +0800 Subject: [PATCH 2/3] (feat) add global_scene --- .../aliyun/openservices/pairec/model/ExperimentResult.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java b/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java index 7cb54d4..10e8503 100644 --- a/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java +++ b/src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java @@ -4,19 +4,15 @@ import com.aliyun.openservices.pairec.util.JsonUtils; import com.aliyun.openservices.pairec.util.TemplateUtils; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.zip.CheckedOutputStream; import static com.aliyun.openservices.pairec.ExperimentClient.logger; public class ExperimentResult { - private static final Logger log = LoggerFactory.getLogger(ExperimentResult.class); private String expId = ""; private String sceneName; From 4753ab16bcdb0badced4966edbd69f1fc5fd8960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=81=E9=9D=99?= Date: Mon, 17 Nov 2025 10:35:12 +0800 Subject: [PATCH 3/3] publish 1.0.6 version --- README.md | 5 ++++- pom.xml | 14 +++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed687c2..dfbb6f4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Java sdk for PA-REC config server. Aliyun product [link](https://pairec.console. com.aliyun.openservices.aiservice pairec-sdk - 1.0.5 + 1.0.6 ``` @@ -66,6 +66,9 @@ public class ExperimentTest { ``` ## 版本说明 +1.0.6 (2025-11-17) +* 全场景实验的支持 + 1.0.5 (2024-07-05) * 修复实验组设置过滤条件时,上下文不传过滤参数时抛出异常 diff --git a/pom.xml b/pom.xml index 8daf11b..04a2984 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ pairec-sdk jar pairec-sdk - 1.0.5 + 1.0.6 >http://maven.apache.org SDK for PAI-REC config service @@ -107,6 +107,17 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 + true + + central + true + + +