Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Java sdk for PA-REC config server. Aliyun product [link](https://pairec.console.
<dependency>
<groupId>com.aliyun.openservices.aiservice</groupId>
<artifactId>pairec-sdk</artifactId>
<version>1.0.5</version>
<version>1.0.6</version>
</dependency>
```

Expand Down Expand Up @@ -66,6 +66,9 @@ public class ExperimentTest {

```
## 版本说明
1.0.6 (2025-11-17)
* 全场景实验的支持

1.0.5 (2024-07-05)
* 修复实验组设置过滤条件时,上下文不传过滤参数时抛出异常

Expand Down
35 changes: 33 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>pairec-sdk</artifactId>
<packaging>jar</packaging>
<name>pairec-sdk</name>
<version>1.0.5</version>
<version>1.0.6</version>
<url>>http://maven.apache.org</url>
<description>SDK for PAI-REC config service</description>
<scm>
Expand Down Expand Up @@ -107,6 +107,17 @@
</executions>
</plugin>

<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.8.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
Expand All @@ -119,6 +130,7 @@
<stagingProfileId>260e4248b30bd2</stagingProfileId>
</configuration>
</plugin>
-->
</plugins>
</build>
<distributionManagement>
Expand Down Expand Up @@ -265,7 +277,26 @@
<artifactId>mvel2</artifactId>
<version>2.4.12.Final</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ public static String environmentDesc2OpenApiString(String environment) {
return "";
}

public static final String Global_Scene_Name = "pairec_abtest_global_scene";
}

136 changes: 117 additions & 19 deletions src/main/java/com/aliyun/openservices/pairec/model/ExperimentResult.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.aliyun.openservices.pairec.ExperimentClient.logger;

public class ExperimentResult {
private String expId = "";

Expand All @@ -26,6 +31,10 @@ public class ExperimentResult {

private LayerParams mergedLayerParams;

private ExperimentResult globalSceneExperimentResult;

private Map<String,Object> globalParams = new HashMap<>();

public ExperimentResult(String sceneName, ExperimentContext experimentContext) {
this.sceneName = sceneName;
this.experimentContext = experimentContext;
Expand Down Expand Up @@ -91,37 +100,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<this.layerList.size();i++){
Layer layer = this.layerList.get(i);

LayerParams layerParams = new DefaultLayerParams();

layerParams.addParams(experimentGroup.getExperimentParams());
if (Constants.Global_Scene_Name.equals(sceneName)){
if(i == 0){
buf.append("GL");
}else {
buf.append("_GL");
}
}else {
buf.append("_L");
}
buf.append(layer.getLayerId());

if (this.layer2Experiment.containsKey(layer.getLayerName())) {
Experiment experiment = this.layer2Experiment.get(layer.getLayerName());
if (experiment.getType() != Constants.Experiment_Type_Default) {
buf.append("#");
buf.append("E").append(experiment.getExperimentId());
String layerName = layer.getLayerName();
ExperimentGroup group = this.layer2ExperimentGroup.get(layerName);
if (group == null){
continue;
}
buf.append("#EG").append(group.getExpGroupId());

LayerParams layerParams = new DefaultLayerParams();
String groupConfig = group.getExpGroupConfig();

if(groupConfig != null && !groupConfig.isEmpty()){
if(Constants.Global_Scene_Name.equals(sceneName)){
try{
Map<String,Object> 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<String,Object> 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<String,Object> 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<String,Object> 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) {
Expand Down Expand Up @@ -179,4 +265,16 @@ public LayerParams getExperimentParams() {

return this.mergedLayerParams;
}

public ExperimentResult getGlobalSceneExperimentResult() {
return globalSceneExperimentResult;
}

public void setGlobalSceneExperimentResult(ExperimentResult globalSceneExperimentResult) {
this.globalSceneExperimentResult = globalSceneExperimentResult;
}

public Map<String, Object> getGlobalParams() {
return globalParams; // 或返回 new HashMap<>(globalParams) 保证封装性
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/aliyun/openservices/pairec/util/JsonUtils.java
Original file line number Diff line number Diff line change
@@ -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<String,Object> parseJson(String json) throws Exception{
return mapper.readValue(json, new TypeReference<Map<String, Object>>() {
});
}
}
Original file line number Diff line number Diff line change
@@ -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<String,Object> 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();
}
}
Loading