A/B测试 #
A/B测试概述 #
A/B测试允许你比较不同搜索配置的效果,以数据驱动的方式优化搜索体验。
应用场景 #
- 比较不同的排名策略
- 测试新的索引配置
- 评估搜索UI变化
- 优化转化率
创建A/B测试 #
通过Dashboard创建 #
- 进入Dashboard
- 选择应用
- 点击"A/B Testing"
- 点击"Create A/B Test"
通过API创建 #
javascript
const client = algoliasearch('APP_ID', 'ADMIN_KEY');
await client.initAbTest({
name: 'Price Ranking Test',
variants: [
{
index: 'products',
trafficPercentage: 50,
description: 'Control - Default ranking'
},
{
index: 'products_price_asc',
trafficPercentage: 50,
description: 'Variant - Price ascending',
customSearchParameters: {
customRanking: ['asc(price)']
}
}
],
endAt: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60 // 7天后结束
});
A/B测试配置 #
变体配置 #
javascript
{
variants: [
{
index: 'products', // 索引名称
trafficPercentage: 50, // 流量百分比
description: 'Control group' // 描述
},
{
index: 'products_variant',
trafficPercentage: 50,
description: 'Test group',
customSearchParameters: { // 自定义搜索参数
customRanking: ['desc(rating)'],
hitsPerPage: 20
}
}
]
}
流量分配 #
javascript
// 70%控制组,30%实验组
variants: [
{ index: 'products', trafficPercentage: 70 },
{ index: 'products_variant', trafficPercentage: 30 }
]
// 多变体测试
variants: [
{ index: 'products', trafficPercentage: 50 },
{ index: 'products_variant_a', trafficPercentage: 25 },
{ index: 'products_variant_b', trafficPercentage: 25 }
]
测试时长 #
javascript
// 设置结束时间
endAt: Math.floor(Date.now() / 1000) + 14 * 24 * 60 * 60 // 14天
// 最小持续时间:1小时
// 最大持续时间:90天
管理A/B测试 #
获取测试列表 #
javascript
const abTests = await client.getAbTests();
console.log(abTests.abtests);
获取测试详情 #
javascript
const abTest = await client.getAbTest(123);
console.log(abTest);
停止测试 #
javascript
await client.stopAbTest(123);
删除测试 #
javascript
await client.deleteAbTest(123);
测试指标 #
自动追踪指标 #
| 指标 | 说明 |
|---|---|
| Search Count | 搜索次数 |
| User Count | 用户数 |
| No Results Rate | 无结果率 |
| Click Through Rate | 点击率 |
| Conversion Rate | 转化率 |
| Average Click Position | 平均点击位置 |
自定义指标 #
javascript
// 发送转化事件
index.sendEvents([
{
eventType: 'conversion',
eventName: 'Purchase',
index: 'products',
userToken: 'user-123',
objectIDs: ['prod-001']
}
]);
点击分析 #
启用点击分析 #
javascript
// 搜索时启用
const results = await index.search('iphone', {
clickAnalytics: true
});
// 结果包含queryID
console.log(results.queryID);
发送点击事件 #
javascript
// 用户点击结果时
index.sendEvents([
{
eventType: 'click',
eventName: 'Product Clicked',
index: 'products',
userToken: 'user-123',
objectIDs: ['prod-001'],
queryID: results.queryID,
positions: [1] // 点击位置
}
]);
发送转化事件 #
javascript
// 用户完成转化时
index.sendEvents([
{
eventType: 'conversion',
eventName: 'Purchase',
index: 'products',
userToken: 'user-123',
objectIDs: ['prod-001'],
queryID: results.queryID
}
]);
测试示例 #
排名策略测试 #
javascript
// 测试:评分排序 vs 销量排序
await client.initAbTest({
name: 'Ranking Strategy Test',
variants: [
{
index: 'products',
trafficPercentage: 50,
description: 'Rating ranking'
},
{
index: 'products_sales',
trafficPercentage: 50,
description: 'Sales ranking'
}
],
endAt: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60
});
分页大小测试 #
javascript
// 测试:10条/页 vs 20条/页
await client.initAbTest({
name: 'Hits Per Page Test',
variants: [
{
index: 'products',
trafficPercentage: 50,
customSearchParameters: {
hitsPerPage: 10
}
},
{
index: 'products',
trafficPercentage: 50,
customSearchParameters: {
hitsPerPage: 20
}
}
],
endAt: Math.floor(Date.now() / 1000) + 14 * 24 * 60 * 60
});
过滤器测试 #
javascript
// 测试:默认过滤库存商品
await client.initAbTest({
name: 'In-Stock Filter Test',
variants: [
{
index: 'products',
trafficPercentage: 50,
description: 'Show all products'
},
{
index: 'products',
trafficPercentage: 50,
description: 'Show in-stock only',
customSearchParameters: {
filters: 'inStock:true'
}
}
],
endAt: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60
});
分析结果 #
Dashboard查看 #
- 进入A/B Testing页面
- 点击测试名称
- 查看详细指标
API获取结果 #
javascript
const abTest = await client.getAbTest(123);
const control = abTest.variants[0];
const variant = abTest.variants[1];
console.log('Control CTR:', control.clickThroughRate);
console.log('Variant CTR:', variant.clickThroughRate);
// 判断统计显著性
if (abTest.significance > 0.95) {
console.log('结果具有统计显著性');
}
结果解读 #
javascript
function analyzeResults(abTest) {
const control = abTest.variants[0];
const variant = abTest.variants[1];
const ctrDiff = variant.clickThroughRate - control.clickThroughRate;
const ctrPercentChange = (ctrDiff / control.clickThroughRate) * 100;
const convDiff = variant.conversionRate - control.conversionRate;
const convPercentChange = (convDiff / control.conversionRate) * 100;
return {
clickThroughRate: {
control: control.clickThroughRate,
variant: variant.clickThroughRate,
difference: ctrDiff,
percentChange: ctrPercentChange
},
conversionRate: {
control: control.conversionRate,
variant: variant.conversionRate,
difference: convDiff,
percentChange: convPercentChange
},
significance: abTest.significance,
recommendation: getRecommendation(abTest)
};
}
function getRecommendation(abTest) {
if (abTest.significance < 0.9) {
return '继续测试,样本量不足';
}
const control = abTest.variants[0];
const variant = abTest.variants[1];
if (variant.conversionRate > control.conversionRate * 1.05) {
return '建议采用变体方案';
} else if (variant.conversionRate < control.conversionRate * 0.95) {
return '建议保持原方案';
} else {
return '两个方案效果相近';
}
}
最佳实践 #
1. 明确测试目标 #
javascript
// ✅ 明确目标:提高转化率
// 测试:价格排序 vs 评分排序
// ❌ 目标不明确
// 同时测试多个变量
2. 单变量测试 #
javascript
// ✅ 只改变一个变量
customSearchParameters: {
hitsPerPage: 20 // 只改变每页数量
}
// ❌ 改变多个变量
customSearchParameters: {
hitsPerPage: 20,
customRanking: ['desc(rating)'],
filters: 'inStock:true'
}
3. 足够的样本量 #
javascript
// 建议:
// - 至少1000次搜索/天
// - 至少运行7天
// - 确保统计显著性 > 95%
4. 避免干扰 #
javascript
// 测试期间避免:
// - 修改索引配置
// - 运行多个相关测试
// - 进行促销活动
A/B测试工具类 #
javascript
class ABTestManager {
constructor(client) {
this.client = client;
}
async createTest(config) {
return await this.client.initAbTest({
name: config.name,
variants: config.variants,
endAt: Math.floor(Date.now() / 1000) + config.duration * 24 * 60 * 60
});
}
async listTests() {
return await this.client.getAbTests();
}
async getTest(testId) {
return await this.client.getAbTest(testId);
}
async stopTest(testId) {
return await this.client.stopAbTest(testId);
}
async analyzeTest(testId) {
const test = await this.getTest(testId);
return this.calculateResults(test);
}
calculateResults(test) {
const results = {
testName: test.name,
status: test.status,
variants: []
};
test.variants.forEach((variant, index) => {
results.variants.push({
index: index + 1,
indexName: variant.index,
trafficPercentage: variant.trafficPercentage,
searchCount: variant.searchCount,
userCount: variant.userCount,
clickThroughRate: variant.clickThroughRate,
conversionRate: variant.conversionRate,
noResultRate: variant.noResultRate
});
});
if (test.variants.length >= 2) {
const control = test.variants[0];
const variant = test.variants[1];
results.comparison = {
ctrImprovement: this.calculateImprovement(
control.clickThroughRate,
variant.clickThroughRate
),
conversionImprovement: this.calculateImprovement(
control.conversionRate,
variant.conversionRate
),
significance: test.significance
};
}
return results;
}
calculateImprovement(control, variant) {
if (control === 0) return 0;
return ((variant - control) / control) * 100;
}
}
总结 #
A/B测试要点:
| 要点 | 说明 |
|---|---|
| 创建 | initAbTest方法 |
| 变体 | index, trafficPercentage |
| 指标 | CTR, 转化率, 无结果率 |
| 点击分析 | clickAnalytics, sendEvents |
| 最佳实践 | 单变量、足够样本、明确目标 |
接下来,让我们学习 分析与统计。
最后更新:2026-03-28