自定义排名 #

排名机制回顾 #

默认排名公式 #

text
排名 = typo → geo → words → filters → proximity → attribute → exact → custom

排名顺序 #

排名按顺序比较,前面的维度优先级更高:

text
记录A: typo=0, words=2, custom=100
记录B: typo=0, words=1, custom=200

结果: A排在B前面(因为words维度A更高)

自定义排名配置 #

基本设置 #

javascript
await index.setSettings({
  customRanking: [
    'desc(rating)',      // 评分降序
    'desc(popularity)',  // 人气降序
    'asc(price)'         // 价格升序
  ]
});

排名方向 #

方向 说明 使用场景
desc 降序 评分、人气、销量
asc 升序 价格、距离

业务排名策略 #

电商场景 #

javascript
await index.setSettings({
  customRanking: [
    'desc(qualityScore)',   // 质量分
    'desc(salesCount)',     // 销量
    'desc(rating)',         // 评分
    'asc(price)'            // 价格
  ]
});

内容场景 #

javascript
await index.setSettings({
  customRanking: [
    'desc(freshness)',      // 新鲜度
    'desc(engagement)',     // 参与度
    'desc(viewCount)'       // 浏览量
  ]
});

用户场景 #

javascript
await index.setSettings({
  customRanking: [
    'desc(lastActiveAt)',   // 最近活跃
    'desc(followers)',      // 粉丝数
    'desc(posts)'           // 发帖数
  ]
});

质量分数计算 #

综合质量分 #

javascript
// 数据准备时计算质量分数
function calculateQualityScore(product) {
  const ratingScore = product.rating * 20;           // 0-100
  const salesScore = Math.min(product.salesCount / 100, 100);
  const reviewScore = Math.min(product.reviewCount / 10, 100);
  const stockScore = product.inStock ? 100 : 0;
  
  return {
    ...product,
    qualityScore: (ratingScore + salesScore + reviewScore + stockScore) / 4
  };
}

// 索引数据
const productsWithScore = products.map(calculateQualityScore);
await index.saveObjects(productsWithScore);

新鲜度分数 #

javascript
function calculateFreshness(publishedAt) {
  const now = Date.now();
  const age = now - publishedAt;
  const dayAge = age / (1000 * 60 * 60 * 24);
  
  // 指数衰减
  const halfLife = 7; // 7天半衰期
  return 100 * Math.exp(-0.693 * dayAge / halfLife);
}

// 数据
{
  "publishedAt": 1710432000,
  "freshness": 85.5
}

参与度分数 #

javascript
function calculateEngagement(content) {
  const viewWeight = 0.3;
  const likeWeight = 0.4;
  const commentWeight = 0.3;
  
  const viewScore = Math.min(content.viewCount / 1000, 100);
  const likeScore = Math.min(content.likeCount / 100, 100);
  const commentScore = Math.min(content.commentCount / 50, 100);
  
  return viewScore * viewWeight + 
         likeScore * likeWeight + 
         commentScore * commentWeight;
}

排名规则 #

创建排名规则 #

javascript
await index.saveRule({
  objectID: 'promo-rule',
  condition: {
    pattern: 'sale',
    anchoring: 'contains'
  },
  consequence: {
    params: {
      filters: 'onSale:true',
      optionalFilters: ['brand:Apple<score=2>']
    }
  }
});

规则示例 #

javascript
// 促销规则
{
  objectID: 'promo-apple',
  condition: { pattern: 'apple', anchoring: 'contains' },
  consequence: {
    params: {
      optionalFilters: ['brand:Apple<score=5>']
    }
  }
}

// 新品规则
{
  objectID: 'new-arrivals',
  condition: { pattern: 'new', anchoring: 'contains' },
  consequence: {
    params: {
      filters: 'isNew:true',
      optionalFilters: ['createdAt:>1710000000<score=3>']
    }
  }
}

可选过滤器 #

基本用法 #

javascript
const results = await index.search('phone', {
  optionalFilters: ['brand:Apple<score=2>']
});

// Apple品牌的结果排名更高,但不排除其他品牌

评分权重 #

javascript
// 更高的score值意味着更高的排名提升
optionalFilters: [
  'brand:Apple<score=5>',
  'brand:Samsung<score=3>',
  'brand:Google<score=1>'
]

组合使用 #

javascript
const results = await index.search('laptop', {
  filters: 'inStock:true',
  optionalFilters: [
    'brand:Apple<score=3>',
    'rating:>4.5<score=2>',
    'price:<1000<score=1>'
  ]
});

动态排名 #

基于时间的排名 #

javascript
// 数据中包含时间戳
{
  "name": "Product",
  "createdAt": 1710432000,
  "boostUntil": 1712505600  // 提升截止时间
}

// 搜索时检查
function searchWithTimeBoost(query) {
  const now = Math.floor(Date.now() / 1000);
  
  return index.search(query, {
    optionalFilters: [`boostUntil:>${now}<score=5>`]
  });
}

基于用户行为 #

javascript
// 个性化排名
async function personalizedSearch(query, userId) {
  const userPreferences = await getUserPreferences(userId);
  
  const optionalFilters = userPreferences.brands.map(brand => 
    `brand:${brand}<score=3>`
  );
  
  return index.search(query, {
    optionalFilters,
    enablePersonalization: true,
    userToken: userId
  });
}

排名调试 #

获取排名信息 #

javascript
const results = await index.search('iphone', {
  getRankingInfo: true
});

results.hits.forEach(hit => {
  console.log(hit.name, hit._rankingInfo);
});

排名信息字段 #

javascript
{
  "_rankingInfo": {
    "nbTypos": 0,
    "firstMatchedWord": 0,
    "proximityDistance": 1,
    "userScore": 100,
    "geoDistance": 0,
    "geoPrecision": 1,
    "nbExactWords": 1,
    "words": 1,
    "filters": 1
  }
}

排名分析工具 #

javascript
class RankingAnalyzer {
  constructor(index) {
    this.index = index;
  }
  
  async analyze(query) {
    const results = await this.index.search(query, {
      getRankingInfo: true,
      hitsPerPage: 20
    });
    
    return results.hits.map((hit, index) => ({
      position: index + 1,
      name: hit.name,
      score: hit._rankingInfo.userScore,
      details: hit._rankingInfo
    }));
  }
  
  compare(query, expectedOrder) {
    const results = await this.analyze(query);
    const actualOrder = results.map(r => r.name);
    
    return {
      expected: expectedOrder,
      actual: actualOrder,
      match: JSON.stringify(expectedOrder) === JSON.stringify(actualOrder)
    };
  }
}

排名优化案例 #

案例1:电商促销 #

javascript
// 需求:促销商品优先展示
// 方案:使用可选过滤器

async function searchWithPromo(query) {
  return index.search(query, {
    optionalFilters: [
      'onSale:true<score=10>',
      'discount:>20<score=5>'
    ]
  });
}

案例2:新品优先 #

javascript
// 需求:新品排在前面
// 方案:预计算新鲜度分数

// 数据准备
function prepareProduct(product) {
  const now = Date.now();
  const age = now - product.createdAt;
  const dayAge = age / (1000 * 60 * 60 * 24);
  
  return {
    ...product,
    freshness: Math.max(0, 100 - dayAge)
  };
}

// 排名设置
customRanking: ['desc(freshness)', 'desc(rating)']

案例3:个性化推荐 #

javascript
// 需求:根据用户偏好排名
// 方案:使用个性化API

async function personalizedSearch(query, userId) {
  return index.search(query, {
    enablePersonalization: true,
    userToken: userId,
    personalizationImpact: 50
  });
}

排名最佳实践 #

1. 预计算复杂分数 #

javascript
// ✅ 推荐:预先计算
{
  "qualityScore": 85,
  "freshness": 90
}

// ❌ 避免:运行时计算
// customRanking: ['desc(rating * salesCount)']  // 不支持

2. 合理设置排名顺序 #

javascript
// ✅ 推荐:按业务重要性排序
customRanking: [
  'desc(qualityScore)',  // 最重要
  'desc(popularity)',    // 次重要
  'asc(price)'           // 最后考虑
]

3. 使用可选过滤器 #

javascript
// ✅ 推荐:使用可选过滤器提升特定结果
optionalFilters: ['brand:Apple<score=5>']

// ❌ 避免:使用过滤器排除结果
filters: 'brand:Apple'  // 会排除其他品牌

4. 定期优化 #

javascript
// 分析搜索数据,优化排名
async function optimizeRanking() {
  const analytics = await getSearchAnalytics();
  
  // 找出点击率低的搜索词
  const lowCTR = analytics.filter(a => a.ctr < 0.1);
  
  // 分析原因,调整排名
  // ...
}

总结 #

自定义排名要点:

要点 说明
配置 customRanking设置
方向 desc降序,asc升序
质量分 预计算综合分数
规则 动态调整排名
可选过滤 提升特定结果
调试 getRankingInfo参数

接下来,让我们学习 搜索建议

最后更新:2026-03-28