跳到主要内容

CmsKit 热度计算系统详解

本文档详细说明热度指数 (HotIndex) 的计算规则、应用场景和优化策略


📊 概述

定义

热度指数 (HotIndex) 是衡量内容受欢迎程度的综合指标,用于:

  1. 热门排序 - 实时展示平台热点内容
  2. 推荐排序 - 作为个性化推荐的质量信号
  3. 搜索排序 - MeiliSearch 搜索结果的排序权重
  4. 编辑特选 - 参考热度选择精选内容

🧮 计算公式

核心算法

HotIndex = (InteractionScore × 权重) + (RecencyScore × 权重) + (QualityScore × 权重)

其中:

1️⃣ 互动信号得分 (InteractionScore)

InteractionScore = (点赞数 × 1.0)
+ (评论数 × 2.0)
+ (书签数 × 1.5)
+ (浏览数 × 0.1)

权重说明:

互动类型权重说明
点赞1.0基础互动信号
评论2.0高质量互动,表示用户深度参与
书签1.5用户主动保存,表示价值评估
浏览0.1低价值信号,数量大但质量低

2️⃣ 新近度得分 (RecencyScore)

RecencyScore = 10 × exp(-λ × DaysOld)

其中:

  • λ = 0.05 (衰减系数)
  • DaysOld = 从发布到现在的天数
  • exp() = 指数函数

示例计算:

发布时间DaysOldRecencyScore说明
1小时前0.049.98最新内容权重最高
1天前19.51一天衰减到 95%
7天前77.07一周衰减到 71%
30天前302.23一月衰减到 22%
90天前900.11三月基本无权重

时间衰减曲线:

热度权重

10│ ╱╲ ← 新内容高峰
9│ ╱ ╲
8│╱ ╲
7│ ╲ ← 一周后跌至7
6│ ╲
5│ ╲ ← 递减趋势
4│ ╲
3│ ╲
2│ ╰─ ← 一月后保持低值
1│
0└────────────────► 时间(天)
0 7 14 21 28

3️⃣ 质量得分 (QualityScore)

QualityScore = (AvgRating × 2.0)
+ (CommentSentiment × 1.0)
+ (EarlyEngagement × 0.5)

子指标:

子指标权重计算方法说明
平均评分2.0(总星数 ÷ 评分数) × 2用户显式反馈
评论情感1.0(正面评论数 - 负面评论数) / 总评论数NLP情感分析
早期互动0.5(首24小时互动数 / 总互动数) × 10初期反应速度

最终公式

HotIndex = (InteractionScore × 0.4)
+ (RecencyScore × 0.4)
+ (QualityScore × 0.2)

权重分配:

  • 🔥 互动信号: 40% - 用户参与度最重要
  • ⏰ 新近度: 40% - 新内容不能被淹没
  • ⭐ 质量得分: 20% - 质量过滤,防止低质刷屏

📈 计算示例

场景: 新发布文章的热度演化

初始数据 (发布时刻):

发布时间: 2026-05-10 10:00:00
初始数据:
- 浏览数: 10
- 点赞数: 0
- 评论数: 0
- 书签数: 0
- 评分: 无

计算:

InteractionScore = 0×1.0 + 0×2.0 + 0×1.5 + 10×0.1 = 1.0
RecencyScore = 10 × exp(-0.05 × 0) = 10
QualityScore = 0 + 0 + 0 = 0

HotIndex_T0 = (1.0 × 0.4) + (10 × 0.4) + (0 × 0.2)
= 0.4 + 4.0 + 0
= 4.4

1小时后的演化

实时更新数据 (11:00):

- 浏览数: 500
- 点赞数: 45
- 评论数: 12
- 书签数: 8
- 平均评分: 4.5 (10个用户)
- 早期互动占比: 95%

计算:

InteractionScore = 45×1.0 + 12×2.0 + 8×1.5 + 500×0.1
= 45 + 24 + 12 + 50
= 131

RecencyScore = 10 × exp(-0.05 × (1/24)) ≈ 9.98 ← 衰减微小

QualityScore = 4.5×2.0 + (12-0)/12×1.0 + 95%×0.5
= 9.0 + 1.0 + 0.475
= 10.475

HotIndex_T1 = (131 × 0.4) + (9.98 × 0.4) + (10.475 × 0.2)
= 52.4 + 3.99 + 2.095
= 58.485

结论: 一小时内热度从 4.4 增长到 58.485,增长约13倍


7天后的稳定状态

数据累计 (7天后):

- 总浏览: 50,000
- 总点赞: 2,000
- 总评论: 500
- 总书签: 300
- 平均评分: 4.7

计算:

InteractionScore = 2000×1.0 + 500×2.0 + 300×1.5 + 50000×0.1
= 2000 + 1000 + 450 + 5000
= 8,450

RecencyScore = 10 × exp(-0.05 × 7) ≈ 7.07 ← 衰减到71%

QualityScore = 4.7×2.0 + 1.0 + 0.3
= 9.4 + 1.0 + 0.3
= 10.7

HotIndex_T7 = (8450 × 0.4) + (7.07 × 0.4) + (10.7 × 0.2)
= 3380 + 2.83 + 2.14
= 3384.97

结论: 尽管互动数据增长10倍,但由于时间衰减,热度只增长58倍,证明新近度调节有效。


🔄 更新策略

计算触发点

触发事件更新频率说明
新互动(点赞/评论/书签)实时用户互动立即反映
审批通过实时发布时初始化热度
定时批量更新每5分钟处理时间衰减、聚合数据
MeiliSearch同步每5分钟搜索排序权重更新

实现方式

方式1: 事件驱动 (推荐)

// 用户点赞时
public async Task LikeArticleAsync(Guid articleId, Guid userId)
{
var like = await _userLikeService.CreateAsync(articleId, userId);

// 实时更新热度
await _articleHotIndexService.UpdateHotIndexAsync(articleId);

// 发送热度更新事件
await _eventBus.PublishAsync(new ArticleHotIndexUpdatedEvent
{
ArticleId = articleId,
NewHotIndex = article.HotIndex
});
}

方式2: 后台任务 (定期批量)

// 每5分钟执行一次
public async Task RecalculateHotIndexesAsync()
{
var articles = await _articleRepository.GetRecentArticlesAsync(days: 30);

foreach (var article in articles)
{
var hotIndex = await _hotIndexService.CalculateAsync(article.Id);
article.HotIndex = hotIndex;
article.HotIndexUpdateTime = DateTime.UtcNow;
}

await _unitOfWork.SaveChangesAsync();
}

🎯 应用场景

1. 热门排序

API 端点:

GET /api/cms/articles/hot-rank-article-list?days=7&limit=20

查询逻辑:

SELECT TOP 20 *
FROM cms_article
WHERE IsDeleted = 0
AND AuditStatus = 2 -- Approved
AND PrivacyType = 0 -- Public
AND CreateTime >= DATEADD(DAY, -7, GETDATE())
ORDER BY HotIndex DESC

2. 推荐排序信号

推荐系统多信号融合:

RecommendationScore = (UserInteractionSignal × 0.5)
+ (HotIndexSignal × 0.3)
+ (ContentQualitySignal × 0.2)

3. 搜索排序权重

MeiliSearch 文档配置:

var settings = new IndexSettings
{
RankingRules = new[]
{
"typo",
"words",
"proximity",
"attribute",
"sort",
"exactness",
"hotIndex:desc" // ← 热度作为排序规则
}
};

🚀 性能优化

优化1: 缓存策略

Redis 缓存:

var cacheKey = $"article:hotindex:{articleId}";
var cachedHotIndex = await _redis.GetAsync<double>(cacheKey);

if (cachedHotIndex == null)
{
var hotIndex = await _hotIndexService.CalculateAsync(articleId);
await _redis.SetAsync(cacheKey, hotIndex, TimeSpan.FromHours(1));
}

// 互动时标记缓存失效
await _redis.DeleteAsync($"article:hotindex:{articleId}");

优化2: 批量计算

避免单条计算瓶颈:

// ❌ 低效: N+1查询
foreach (var article in articles)
{
article.HotIndex = await _hotIndexService.CalculateAsync(article.Id);
}

// ✅ 高效: 一次查询所有交互数据
var interactionData = await _interactionRepository
.GetBatchInteractionStatsAsync(articleIds);

var hotIndexes = articles.Select(a =>
_hotIndexService.Calculate(a, interactionData[a.Id])
).ToList();

优化3: 增量更新

只更新变化的数据:

// 仅在互动数据显著变化时更新
if (Math.Abs(newHotIndex - oldHotIndex) > 0.5) // 变化>0.5才更新
{
article.HotIndex = newHotIndex;
article.HotIndexUpdateTime = DateTime.UtcNow;
await _articleRepository.UpdateAsync(article);
}

⚙️ 参数调优

场景1: 促进新内容发现

目标: 让新内容尽快获得展示机会

参数调整:

λ (衰减系数) = 0.02 // 降低衰减速度,新内容权重保持更久
新近度权重 = 50% // 提升新近度在总权重中的占比

场景2: 强化用户互动

目标: 鼓励用户评论、书签等深度互动

参数调整:

评论权重 = 3.0 // 提升评论权重(从2.0)
书签权重 = 2.0 // 提升书签权重(从1.5)
互动权重 = 50% // 增加互动得分的总权重

场景3: 打击刷屏

目标: 防止机器人刷屏,保证内容质量

参数调整:

点赞权重 = 0.5 // 降低点赞权重
评论情感权重 = 2.0 // 重视评论质量(情感分析)
早期互动占比 = 0.8 // 严格要求初期互动速度

📋 监控指标

关键指标

指标目标值监控周期
平均热度指数50-150每小时
热度分布P95< 500每天
新内容首日热度增长> 5x每日
7天衰减率70%每周
热度排序稳定性> 95%每天

监控 SQL

-- 热度分布统计
SELECT
COUNT(*) AS TotalArticles,
MIN(HotIndex) AS MinHotIndex,
AVG(HotIndex) AS AvgHotIndex,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY HotIndex) AS P95HotIndex,
MAX(HotIndex) AS MaxHotIndex
FROM cms_article
WHERE IsDeleted = 0 AND AuditStatus = 2

-- 新内容热度增长
SELECT
Id,
Title,
CreateTime,
HotIndex,
(SELECT COUNT(*) FROM cms_user_like WHERE SubjectId = ca.Id) AS LikeCount,
(SELECT COUNT(*) FROM cms_comment WHERE SubjectId = ca.Id) AS CommentCount
FROM cms_article ca
WHERE CreateTime >= DATEADD(DAY, -1, GETDATE())
ORDER BY HotIndex DESC

🔍 常见问题

Q1: 为什么我的文章发布后热度不增长?

A: 检查以下几点:

  1. 文章是否通过审核 (AuditStatus = Approved)
  2. 文章隐私设置是否为公开 (PrivacyType = Public)
  3. 是否有用户互动(点赞/评论/书签)
  4. 热度计算服务是否正常运行

Q2: 为什么新文章突然热度下降?

A: 这是正常的时间衰减表现。热度随时间指数衰减,7天后衰减到70%。如果想保持热度,需要不断获得新的用户互动。

Q3: 热度可以手动修改吗?

A: 不建议手动修改。如需特殊处理(如编辑精选),应该使用 EditorIndex 字段而不是 HotIndex

Q4: 如何防止热度刷屏?

A: 系统内置防护机制:

  • 同一用户点赞同一文章仅计算一次
  • 评论权重高于点赞,但需要通过审核
  • 可配置权重降低点赞的影响

📚 相关文档


最后更新: 2026-05-10