Skip to content

用户对象

ABetterChoice 的每一次分组都基于一个用户对象。它包含两类信息:

  • 决定调用落在哪个分组的 unit_id
  • 决定调用满足哪些受众规则的可选属性

本页描述如何在 SDK 与 HTTP API 间正确构造用户对象。

下文 Go 与 HTTP 部分代表今天已正式可用的接入方式。iOS、Android、JavaScript、C++ 部分是 形态预览,这些 SDK 在 Settings → SDK&Key 下都是 Coming soon

unit_id

unit_id 是用来确定实验随机化粒度的稳定字符串。平台保证同一 unit_id 在同一实验生命周期里 始终落在同一个分组

选哪种 ID何时用
用户 ID实验对比的是登录用户,且你有稳定的内部 ID。
会话 ID登录前的链路,还没有用户 ID。
设备 / 安装 ID移动端 App,希望分组跟着安装走。

在服务端或首次启动时构造一次并复用。不要把 PII 拼进 unit_id(如 user@example.com:1), 它会泄漏到曝光日志里。

go
ctx := abc.NewUserContext("user_id_1")        // Go
objective-c
expOptions.unitId = @"user_id_1";              // iOS
javascript
abc.init({ projectId, unitId: "user_id_1", ... }) // JavaScript

切换 unit_id

当一次会话内 unit_id 会变(用户登录、切账号),客户端 SDK 提供 switchUnitId。SDK 会为新 unit_id 重新拉取分组:

java
mAbcExpSDK.switchUnitId("otherUnitID", listener);    // Android
javascript
abc.switchUnitId("other_unit_id");                    // JavaScript

服务端 SDK 不需要 switch —— 每次请求都可以构造自己的用户上下文,unit_id 本就随请求变。

属性(profiles)

属性让实验或开关只命中部分 unit_id(例如 country == "US" AND app_version >= 1.3.0)。 在调用处组装属性集,SDK 或 HTTP 会把它带上:

go
ctx := abc.NewUserContextWithAttrs("user_id_1", map[string]string{
    "country":     "US",
    "app_version": "1.3.0",
})
javascript
abc.init({
  projectId, unitId, secretKey,
  attributes: { country: "US", app_version: "1.3.0" },
});

HTTP API 把属性放进请求体的 profiles map:

json
{
  "project_id": "6666",
  "unit_id": "user_id_1",
  "profiles": { "country": { "user_attrs": ["US"] }, "age": { "user_attrs": ["18"] } }
}

今天的内置属性包括 countryapp_versionmedia_sourceos_platformram_totalfirst_install_versiontime_since_joinuser_type。自定义属性在控制台 Audiences → Attributes 中创建,详见 受众

属性类型

类型控制台标签比较
StringString等值、IN、NOT IN、正则。
NumberNumber等值、范围、IN、NOT IN。
VersionVersion语义化版本比较(>=<=)。

HTTP API 只接受字符串属性值 —— 数字与布尔在发送前先转字符串("18""true")。

粘性分组

平台对 (unit_id, layer_or_experiment_seed) 做哈希决定分组。哈希是确定性的,所以:

  • 只要实验流量分配与盐值不变,同一 unit_id 始终在同一组;
  • 在同一项目里增减其他实验,不会让该 unit_id 在本实验的分组发生迁移;
  • 修改层的 % of global traffic 让单元跨过命中 / 未命中边界,详见 层域说明