PHP 使用 Redis ZSET 与 Hash 实现文章热度和点赞排行
利用 PHP 操作 Redis 中的 ZSET(有序集合)与 Hash(哈希表),可以低成本地实现实时的文章热度及点赞排行榜。该方案将统计指标存储在内存中,通过反向排序获取 Top N 结果,并在详情缺失时回源 MySQL,兼顾了读取性能与数据一致性。
核心原理与准备
排行榜的核心在于“分值”与“成员”的映射。在本场景中:
- Hash (键:
newsId-{ID}):存储文章的静态简介信息(如标题、作者、创建时间),用于前端快速展示。 - ZSET (键:
hot/good):分别用于存储热度值和点赞数。ZSET 会自动根据分数对成员进行升序排列,配合zrevrange即可轻松获取 Top N。
第1步:初始化文章基础信息与排行榜
在应用启动或定时任务中,需将所有文章的详细信息同步至 Redis,并初始化排序用的分值字段(初始化为0)。
// 所有新闻页入口
public function news()
{
$redis = new Redis();
// 获取所有文章列表
$list = News::select();
foreach ($list as &$row){
// 1. 存入 Hash 散列,用于获取文章摘要等基本信息
$redis->handler()->hmset('newsId-'.$row->id, array(
'id' => $row->id,
'title' => $row->title,
'name' => $row->name,
'create_time' => $row->create_time
));
// 2. 初始化 ZSET 分值,确保后续操作不报错
$redis->zAdd('hot', 0, 'newsId-'.$row->id);
$redis->zAdd('good', 0, 'newsId-'.$row->id);
}
return json($list);
}执行上述逻辑后,Redis 中的数据状态如下:
通过 $redis->zRange('hot','0','-1',true) 可查看当前所有文章在排行榜中的排序情况,初始状态下各文章分值均为 0。
第2步:实现热度与点赞的动态增长
在实际业务中,用户访问文章或点击点赞按钮时,需原子性地增加对应 ZSET 的分值。这里直接使用 zIncrBy 方法(原文代码误写为 zIncRby,已修正)来实现累加。
查看文章详情(增加热度)
$redis = new Redis();
$param = $this->request->param();
$news_id = $param['news_id'];
// 正常从 MySQL 获取文章内容返回前端
$list = News::where('id', $news_id)->find();
// Redis 中该文章的热度分值 +1
$redis->zIncrBy('hot', 1, 'newsId-'.$news_id);
return json($list);点赞操作(增加赞数)
public function newsGoods()
{
$redis = new Redis();
$param = $this->request->param();
$news_id = $param['news_id'];
// Redis 中该文章的点赞分值 +1
$redis->zIncrBy('good', 1, 'newsId-'.$news_id);
}第3步:查询排行榜并展示详情
当需要展示“热门文章”或“热门点赞”列表时,利用 ZSET 的特性可以快速拿到 Top N 的 ID 列表。由于 Hash 数据可能因淘汰机制丢失,因此增加了“回源检测”逻辑。
获取热度 Top N 排行
// 访问热度排行接口
public function newsHot()
{
$redis = new Redis();
// 获取热度最高的前 3 名,返回结果为索引对应的 Member 字符串
$rank = $redis->handler()->zrevrange('hot', 0, 2);
$resultList = [];
foreach ($rank as $memberKey) {
// 尝试从 Hash 中获取文章详情
$detail = $redis->hGetAll($memberKey);
if (!$detail) {
// 如果缓存中没有,说明 Hash 过期或被清理,需从数据库查补
// 注意:这里假设 Key 格式为 'newsId-数字',需提取纯数字 ID
$id = explode('-', $memberKey)[1];
$detail = Db::name('news')->where('id', $id)->find();
}
$resultList[] = $detail;
}
dump($resultList);
}结果说明:若某篇文章(如 ID 2)的 Hash 数据已被移除,系统会自动降级查询数据库并填充数据,保证排行页面的完整性。
获取点赞 Top N 排行
点赞排行的逻辑与热度排行完全一致,仅更换 ZSET 的键名即可:
// 点赞热度排行
public function newsGood()
{
$redis = new Redis();
// 获取点赞数最高的前 3 名
$rank = $redis->handler()->zrevrange('good', 0, 2);
$resultList = [];
foreach ($rank as $memberKey) {
$detail = $redis->hGetAll($memberKey);
if (!$detail) {
$id = explode('-', $memberKey)[1];
$detail = Db::name('news')->where('id', $id)->find();
}
$resultList[] = $detail;
}
dump($resultList);
}总结
本方案展示了如何在 ThinkPHP/PHP 环境中,通过 HMSET 维护元数据、ZADD/ZINCRBY 维护实时排序权重的完整闭环。这种模式避免了每次查看排行都全表扫描数据库的性能瓶颈。
以上就是基于 PHP 操作 Redis ZSET 与 Hash 实现文章热度和点赞排行的详细内容,更多关于 PHP 高性能排行榜的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









