A/B测试 #

A/B测试概述 #

A/B测试允许你比较不同搜索配置的效果,以数据驱动的方式优化搜索体验。

应用场景 #

  • 比较不同的排名策略
  • 测试新的索引配置
  • 评估搜索UI变化
  • 优化转化率

创建A/B测试 #

通过Dashboard创建 #

  1. 进入Dashboard
  2. 选择应用
  3. 点击"A/B Testing"
  4. 点击"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查看 #

  1. 进入A/B Testing页面
  2. 点击测试名称
  3. 查看详细指标

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