PHP 使用 Redis ZSET 与 Hash 实现文章热度和点赞排行

小石头
小石头
发布时间:2026-10-16 | 5人浏览过
原创

利用 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 高性能排行榜的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表