Java A/B Testing SDK 依赖神策分析 SDK。在使用前请确保已经成功集成神策分析 SDK,并进行了 SDK 初始化,详情可参考 SDK集成(Java)

Java A/B Testing SDK 需要 JDK 1.7+,Java A/B Testing SDK 依赖 Java 神策分析 SDK,支持版本 3.2.0+,引用 guava 18.0 版本

1. SDK 集成

本次 SDK 推荐的集成方式是采用 Maven 集成。

<dependency>
      <groupId>com.sensorsdata.analytics.javasdk</groupId>
      <artifactId>SensorsABTesting</artifactId>
      <version>1.0.0</version>
</dependency>
CODE

非 Maven 项目可以去 Maven 中央仓库搜索下载 jar 包到本地,然后手动添加到项目中。

2. 初始化 SDK

Java A/B Testing SDK 依赖神策分析 SDK。请确保已经成功集成神策分析 SDK,并进行了 SDK 初始化。成功引入 A/B Testing SDK 之后,请先在神策分析前端页面创建相关的分流试验,然后获取生成的分流 URL。

2.1. 在普通 Java 项目初始化 SDK

        // 初始化神策分析 SDK
        final ISensorsAnalytics sa = new SensorsAnalytics(new ConcurrentLoggingConsumer("file.log"));
        // 构建配置 A/B Testing 试验全局参数
        ABGlobalConfig abGlobalConfig = ABGlobalConfig.builder()
                                            .setApiUrl("分流试验请求地址")    
                                            .setSensorsAnalytics(sa)    // 神策分析埋点 SDK 实例
                                            .build();
        // 初始化 A/B Testing SDK
        final ISensorsABTest abTest = new SensorsABTest(abGlobalConfig);
JAVA

2.2. 在 Spring 框架里面初始化 SDK

A/B Testing SDK 与神策分析 SDK 初始化方式相同,需要在全局初始化一次即可。推荐将初始化操作装配成 Bean,交给 Spring 容器来管理。下面提供两种方式创建 Bean,在实际项目中根据实际情况任选其一进行创建即可。

2.2.1. 使用 xml 配置文件创建 Bean 对象

首先构建静态工厂,生成 A/B  Testing 试验实例对象。

public class ABTestInstanceFactory {

  public static ISensorsABTest getABTestConfigInstance(String url, ISensorsAnalytics sa)
      throws InvalidArgumentException {
    ABGlobalConfig config = ABGlobalConfig.builder().setApiUrl(url).setSensorsAnalytics(sa).build();
    return new SensorsABTest(config);
  }

}
JAVA

然后在 xml 配置文件中创建 Bean 对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <!-- 本地日志模式(此模式会在指定路径生成相应的日志文件) -->
    <bean id="loggingConsumer" class="com.sensorsdata.analytics.javasdk.consumer.ConcurrentLoggingConsumer">
        <constructor-arg name="filenamePrefix" value="您的日志文件路径"/>
    </bean>

    <!-- debug 模式(此模式只适用于测试集成 SDK 功能,千万不要使用到生产环境!!!) -->
    <!--<bean id="debugConsumer" class="com.sensorsdata.analytics.javasdk.consumer.DebugConsumer">
        <constructor-arg name="serverUrl" value="数据接收地址"/>
        <constructor-arg name="writeData" value="true"/>
    </bean>-->

    <!-- 网络批量发送模式(此模式在容器关闭的时候,如果存在数据还没有发送完毕,就会丢失未发送的数据!!!)-->
    <!--<bean id="batchConsumer" class="com.sensorsdata.analytics.javasdk.consumer.BatchConsumer">
        <constructor-arg name="serverUrl" value="数据接收地址"/>
    </bean>-->

    <!-- 此处选择合适的模式进行数据采集操作(此处选择本地日志模式) -->
    <bean id="sensorsAnalytics" class="com.sensorsdata.analytics.javasdk.SensorsAnalytics" destroy-method="shutdown">
        <constructor-arg name="consumer" ref="loggingConsumer"/>
    </bean>

    <!-- 通过构建的静态工厂创建 A/B Testing SDK Bean -->
    <bean id="abTest" class="com.sensorsdata.demo.config.ABTestInstanceFactory"
          factory-method="getABTestConfigInstance">
        <constructor-arg name="url" value="分流试验请求地址"/>
        <constructor-arg name="sa" ref="sensorsAnalytics"/>
    </bean>
</beans>

CODE

2.3. 使用注解创建 Bean 对象

@Configuration
public class SensorsConfig {

  @Bean(name = "sa", destroyMethod = "shutdown")
  public ISensorsAnalytics initSensorsAnalytics() throws IOException {
    //本地日志模式(此模式会在指定路径生成相应的日志文件)
    return new SensorsAnalytics(new ConcurrentLoggingConsumer("file.log"));
    //debug 模式(此模式只适用于测试集成 SDK 功能,千万不要使用到生产环境!!!)
    //return new SensorsAnalytics(new DebugConsumer("数据接收地址", true));
    //网络批量发送模式(此模式在容器关闭的时候,如果存在数据还没有发送完毕,就会丢失未发送的数据!!!)
    //return new SensorsAnalytics(new BatchConsumer("数据接收地址"));
  }

  @Bean
  public ISensorsABTest initSensorsABTest(ISensorsAnalytics sa) throws InvalidArgumentException {
    String url = "分流试验地址";
    ABGlobalConfig config = ABGlobalConfig.builder().setApiUrl(url).setSensorsAnalytics(sa).build();
    return new SensorsABTest(config);
  }

}

JAVA

2.4. 在业务代码中调用 Bean 对象

@Service
public class TestServiceImpl implements ITestService {

  //注入神策实例化对象
  @Autowired
  ISensorsAnalytics sa;
  
  //注入 A/B Testing 实例化对象
  @Autowired
  ISensorsABTest abTest;
  
  public String abTest(String userId) throws InvalidArgumentException, IOException {
    Experiment<String> experiment = abTest.asyncFetchABTest(userId, true, "color", "grey");
    String result = experiment.getResult();
    switch (result) {
      case "试验值一":
        //命中试验一 do something
        break;
      case "试验值二":
        //命中试验二 do something
        break;
      case "grey":
        //没有命中任何试验,返回设置默认值
        break;
    }
    return "success";
  }
}

JAVA

3. 获取分流试验变量信息

Java SDK 提供两种方式获取试验变量信息:

  • asyncFetchABTest :忽略内存缓存,从服务端获取数据
  • fastFetchABTest 优先读取内存缓存,缓存不存在时从服务端获取数据。

应该选择哪个API获取试验变量值?

1.一般情况下,我们推荐使用fastFetchABTest获取试验变量值。

2.如果您进行的是时间片轮转等在试验过程中用户会进入不同组的试验,建议您使用asyncFetchABTest,直接从服务端获取数据,保证获取变量的准确性。

1. 接入前请参考如何设置distinctId,在调用时正确设置distinctId参数.

2. 请确保对A/B分流返回的 result 结果 & 接口中使用的默认值,都做了正常的业务逻辑处理!

3. 请确保默认值 default_value 和当前试验值类型相同。比如参数对应试验值为 Int 类型,则传入的 default_value 也必须是 Int 类型,同时返回的试验结果 result 也是 Int 类型

如果您需要在新用户注册流程中使用A/B Testing服务端SDK新用户进行用户主体或神策ID主体分流试验,不建议您使用loginId请求分流。可参考以下方案,根据您试验的实际情况选择其中一个:

  1. 如果您目前的A/B Testing 版本在v0.9.1以上,可以在创建试验时采用登录ID作为试验的分流主体。
  2. 如果用户只会在一台设备登录,没有多设备登录场景,可使用客户端设备的匿名ID请求分流,即distinctId为从客户端获取的匿名ID,isLoginId为false.
  3. 可以将试验移到客户端进行。
  4. 可以使用服务端SDK进行自定义主体分流试验。

fastFetchABTest 为例

String distinctId = "fz123456"; // 具体的用户 ID 标识
boolean isLoginId = true; // 当前用户是否是登录 ID
  
// Integer 类型试验(第四个参数 0,表示未命中试验时,会返回此默认值,请根据业务需要更改此处的值)
Experiment<Integer> experiment = abTest.fastFetchABTest(distinctId, isLoginId, "具体的试验参数", 0);
int result = experiment.getResult();                 
// TODO 根据 result 处理相应逻辑
        switch (result) {
            case 0:
                break;
            case 1:
                // 试验组 1 的处理逻辑
                break;
            case 2:
                // 试验组 2 的处理逻辑
                break;
            // ……
            // ……
            default:
                // 其他情况的处理逻辑
                break;
        }
JAVA

4. 携带自定义属性获取试验变量

v0.0.3 及以上版本 SDK 支持自定义属性扩充受众筛选能力,可以在初始化 SDK 后,通过 API 添加自定义属性获取具体试验的变量值,根据获取试验变量值的方式,可分为下面 2 种策略:

  • asyncFetchABTest忽略本地缓存,从服务端获取数据
  • fastFetchABTest优先读取本地缓存,缓存不存在时从服务端获取数据

fastFetchABTest 为例,可在相应的业务逻辑中添加如下代码:

// 当前为 Integer 类型试验(第二个参数 0,表示未命中试验时,会返回此默认值,请根据业务需要更改此处的值)
String distinctId = "fz123456"; // 具体的用户 ID 标识
boolean isLoginId = true; // 当前用户是否是登录 ID
Map<String, Object> properties = Maps.newHashMap();
properties.put("自定义属性对应英文名", "自定义属性对应 value"); // 自定义属性

// 当前为 Integer 类型试验(第四个参数 0,表示未命中试验时,会返回此默认值,请根据业务需要更改此处的值)
Experiment<Integer> experiment = abTest.fastFetchABTest(distinctId, isLoginId, "具体的试验参数", 0, properties);
// TODO 请根据 experiment.getResult() 进行自己的试验
switch (result) {
    case 0:
        break;
    case 1:
        // 试验组 1 的处理逻辑
        break;
    case 2:
        // 试验组 2 的处理逻辑
        break;
    // ……
    // ……
    default:
        // 其他情况的处理逻辑
        break;
}
JAVA

自定义属性值支持字符串、字符串数组、数值、布尔和日期时间格式,并且属性名支持英文、数字、下划线,且不能以数字开头

5. 携带自定义主体获取试验变量

v0.0.5及以上版本SDK支持使用自定义主体进行分流。在接入前,需要确认以下几点:

  • 确认您要使用的自定义主体参数名(例如 phone_number, account等,支持自定义)。
  • 在神策元数据管理将该自定义主体设置为公共属性。
  • 将自定义主体名提供给神策,由神策技术人员将其配置到分流服务后台。

初始化SDK后,在调用获取试验变量API时,手动将自定义主体添加到接口请求参数customId中,并在后续上报的事件中添加该自定义主体作为事件属性。

 fastFetchABTest 为例:

String distinctId = "fz123456"; // 具体的用户 ID 标识
boolean isLoginId = true; // 当前用户是否是登录 ID
   
// Integer 类型试验(第四个参数 0,表示未命中试验时,会返回此默认值,请根据业务需要更改此处的值)
Experiment<Integer> experiment = abTest.fastFetchABTest(
              SensorsABParams.starter(distinctId, isLoginId, "具体的试验参数", 0).addCustomId("自定义主体参数名", "自定义主体参数值").build());
int result = experiment.getResult();                
// TODO 根据 result 处理相应逻辑
        switch (result) {
            case 0:
                break;
            case 1:
                // 试验组 1 的处理逻辑
                break;
            case 2:
                // 试验组 2 的处理逻辑
                break;
            // ……
            // ……
            default:
                // 其他情况的处理逻辑
                break;
        }
 
//如果需要上报事件参与AB试验指标计算,需要将该自定义主体作为事件属性
      sa.track(EventRecord.builder().setDistinctId(distinctId).isLoginId(isLoginId)
          .setEventName("buy")
          .addProperty("自定义主体参数名", "自定义主体参数值")
          .addProperty("price", 100)
          .build());
JAVA

6. 获取设备主体试验变量

SDK支持使用设备主体进行分流,需要根据您使用的SDK版本和A/B Testing版本,做对应的接入设置。

接入前请参考如何设置distinctId,在调用时正确设置distinctId参数。获取设备主体试验变量时,distinctId为从客户端获取的匿名ID。

请确保对A/B分流返回的 result 结果 & 接口中使用的默认值,都做了正常的业务逻辑处理!

  1. 如果您使用的A/B Testing Java SDK为1.0.0及以上版本,且当前A/B Testing为0.9.1及以上版本,可以采用以下方式获取设备主体试验变量

    String distinctId = "anonymous_id"; // 匿名ID
    boolean isLoginId = false; // 当前distinctId不是登录ID
       
    // Integer 类型试验(第四个参数 0,表示未命中试验时,会返回此默认值,请根据业务需要更改此处的值)
    Experiment<Integer> experiment = abTest.fastFetchABTest(distinctId, isLoginId, "具体的试验参数", 0);
    int result = experiment.getResult();                
    // TODO 根据 result 处理相应逻辑
            switch (result) {
                case 0:
                    break;
                case 1:
                    // 试验组 1 的处理逻辑
                    break;
                case 2:
                    // 试验组 2 的处理逻辑
                    break;
                // ……
                // ……
                default:
                    // 其他情况的处理逻辑
                    break;
            }
     
    //如果需要上报事件参与AB设备主体试验指标计算,需要在每条埋点事件中将anonymous_id作为事件属性上报,如下所示
    sa.track(EventRecord.builder().setDistinctId(distinctId).isLoginId(isLoginId)
      .setEventName("buy")
      .addProperty("anonymous_id", distinctId)    //将anonymous_id作为事件属性上报
      .addProperty("price", 100)
      .build());
    JAVA
  2. 如果您使用的A/B Testing Java SDK 或 A/B Testing版本不满足上述要求,可采用以下方式获取设备主体试验变量
    String distinctId = "anonymous_id"; // 匿名ID
    boolean isLoginId = false; // 当前distinctId不是登录ID
       
    // Integer 类型试验(第四个参数 0,表示未命中试验时,会返回此默认值,请根据业务需要更改此处的值)
    // 第五个参数是false, 设置为手动上报$ABTestTrigger事件
    Experiment<Integer> experiment = abTest.fastFetchABTest(distinctId, isLoginId, "具体的试验参数", 0, false);
    
    //手动上报$ABTestTrigger事件,将anonymous_id作为事件属性
    Map<String,Object> anonymousIdMap = new HashMap<>();
    anonymousIdMap.put("anonymous_id", distinctId);
    abtest.trackABTestTrigger(experiment, anonymousIdMap);
    
    int result = experiment.getResult();                
    // TODO 根据 result 处理相应逻辑
            switch (result) {
                case 0:
                    break;
                case 1:
                    // 试验组 1 的处理逻辑
                    break;
                case 2:
                    // 试验组 2 的处理逻辑
                    break;
                // ……
                // ……
                default:
                    // 其他情况的处理逻辑
                    break;
            }
    
    
    //如果需要上报事件参与AB设备主体试验指标计算,需要在每条埋点事件中将anonymous_id作为事件属性上报,如下所示
    sa.track(EventRecord.builder().setDistinctId(distinctId).isLoginId(isLoginId)
      .setEventName("buy")
      .addProperty("anonymous_id", distinctId)    //将anonymous_id作为事件属性上报
      .addProperty("price", 100)
      .build());
    JAVA



7. API 介绍

7.1. 初始化全局参数设置说明

Java A/B Testing SDK 的全局参数封装在 ABGlobalConfig 类中,具体参数如下:

参数名类型说明
eventCacheTime

Integer

单用户事件缓存时间,默认值为 1440min,最大限制 1440min,最小限制 0min

eventCacheSize

Integer

事件总缓存用户量,默认值为 4096,无上限设置,最小限制 0

experimentCacheSize

Integer

试验总缓存用户量,默认值 4096,无上限设置,最小限制 0

experimentCacheTime

Integer

单用户试验缓存时间,默认值为 1440min,最大限制 1440min,最小限制 0min

enableEventCacheBoolean上报事件缓存开关,默认开启缓存

apiUrl

String

分流试验地址,必填,默认为空

sensorsAnalytics

ISensorsAnalytics

神策分析 SDK 实例对象,必填,默认为空(此处使用神策分析 SDK 版本为 3.2.0 及以上版本)

enableLogBoolean是否开启 SDK 运行输出控制台日志。默认开启

7.2. API 方法说明

描述说明
方法名asyncFetchABTest/fastFetchABTest
参数
  • distinctId 具体的用户 ID 标识
  • isLoginId 当前用户是否是登录 ID
  • experimentVariableName 试验变量名称
  • defaultValue 未命中试验,返回默认值(支持数据类型:number|boolean|String|json)
  • enableAutoTrackEvent 是否开启自动上报 $ABTestTrigger 事件,默认自动上报
  • timeoutMilliseconds 请求超时设置 默认 3000ms
  • properties 自定义属性
返回值
Experiment<T>

7.3. 方法返回值说明

Java A/B Testing SDK 统一返回 Experiment<T>对象,具体返回参数如下:

参数名类型说明

distinctId

String具体的用户 ID 标识

isLoginId

boolean当前用户是否是登录 ID

abTestExperimentId

String试验 ID

abTestExperimentGroupId

String试验分组 ID
isWhiteListboolean是否白名单用户,白名单用户不进行试验事件的上报
isControlGroupboolean是否是对照组

result

T 范型试验命中返回值,目前支持类型 (number|boolean|String|json)

8. 手动触发 A/B 测试($ABTestTrigger)事件说明

Java A/B Testing SDK 中提供的方法中,如果设置参数 enableAutoTrackEvent=true 或者不设置,并且事件内存缓存中不存在,SDK 会自动上报 A/B 测试($ABTestTrigger)事件。

如果设置 enableAutoTrackEvent=false ,则需要用户自己手动触发上报 A/B 测试($ABTestTrigger)事件

SDK 提供 trackABTestTrigger 方法,示例如下:

// 手动触发 A/B 测试($ABTestTrigger)事件
abTest.trackABTestTrigger(experiment)
JAVA

 trackABTestTrigger 方法使用说明:

方法名trackABTestTrigger
参数

Experiment<T>,即获取分流试验结果返回对象

Map<String,Object>,上报事件的属性值集合,可不传

返回结果

9. 调试试验

  1. 可以通过录入调试设备的方式,把用户加入指定分组中;加入调试设备后,会强制命中当前试验指定的分组调试设备在调试状态和正式上线阶段都会生效)。
  2. 使用服务端SDK对该用户请求分流,返回当前试验指定的分组。需要注意的是,在请求分流时,请根据调试设备的ID类型(设备ID、登录ID)正确设置分流API中使用的distinctId与isLoginId参数,否则可能不会命中试验。