PHP项目怎么实现热度排序?

wen java案例 5

本文目录导读:

PHP项目怎么实现热度排序?

  1. 方案一:基于固定公式的简单排序(适合MVP或中小型项目)
  2. 方案二:基于对数函数的Hacker News风格算法(适合社区/新闻站)
  3. 方案三:使用Redis实现实时热度排序(适合高并发)
  4. 方案四:定时离线计算(适合复杂逻辑、大数据量)
  5. 总结建议

在PHP项目中实现热度排序,通常需要结合时效性用户行为来设计算法,常见的方案有两种:基于固定公式的权重排序(适合中小型项目)和基于对数衰减的分数计算型平台)。

下面提供几种核心实现思路和对应的PHP代码示例。


核心思想

热度 = 用户行为得分 × 时间衰减因子

  • 用户行为:浏览量、点赞、评论、收藏、分享等,不同行为赋予不同权重。
  • 时间衰减:越新的内容,热度加成越高;越旧的内容,得分慢慢变低。

基于固定公式的简单排序(适合MVP或中小型项目)

这种方案直接在SQL查询中计算得分,适合数据量不大的场景。

数据库表结构示例

CREATE TABLE articles (
    id INT PRIMARY KEY AUTO_INCREMENT,VARCHAR(255),
    views INT DEFAULT 0,
    likes INT DEFAULT 0,
    comments INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

PHP + MySQL 代码实现

<?php
// 定义行为权重
define('WEIGHT_VIEW', 1);
define('WEIGHT_LIKE', 5);
define('WEIGHT_COMMENT', 10);
// 定义时间衰减参数(半衰期:3600秒 = 1小时)
define('HALF_LIFE', 3600);
function getHotArticles($pdo, $page = 1, $pageSize = 20) {
    $offset = ($page - 1) * $pageSize;
    $now = time();
    $sql = "SELECT id, title, 
            (
                (views * :weight_view + likes * :weight_like + comments * :weight_comment) 
                / POWER(2, (:now - UNIX_TIMESTAMP(created_at)) / :half_life)
            ) AS hot_score
            FROM articles 
            ORDER BY hot_score DESC 
            LIMIT :offset, :pageSize";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([
        ':weight_view'    => WEIGHT_VIEW,
        ':weight_like'    => WEIGHT_LIKE,
        ':weight_comment' => WEIGHT_COMMENT,
        ':half_life'      => HALF_LIFE,
        ':now'            => $now,
        ':offset'         => $offset,
        ':pageSize'       => $pageSize
    ]);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

说明

  • 公式:热度 = (权重之和) / 2^((当前时间-发布时间)/半衰期)
  • 每经过一个半衰期,热度权重减半。

基于对数函数的Hacker News风格算法(适合社区/新闻站)

Hacker News 的经典热度算法更侧重于爆发性早期推荐

算法公式

热度 = (点赞数 - 踩数 + 1) / ((当前时间 - 发布时间) / 3600 + 2)^1.5
  • 幂次1.5控制时间衰减的速度(越老衰减越快)。

PHP实现

<?php
function getHackerNewsScore($upvotes, $downvotes, $postTime) {
    $score = ($upvotes - $downvotes);
    if ($score < 0) $score = 0; // 防止负分
    $ageHours = (time() - $postTime) / 3600;
    if ($ageHours < 0) $ageHours = 0; // 防止未来时间
    // 核心公式
    return ($score + 1) / pow(($ageHours + 2), 1.5);
}
// 查询时直接计算
function getHackerNewsHotArticles($pdo) {
    $sql = "SELECT id, title, upvotes, downvotes, created_at,
            ((upvotes - downvotes + 1) / POW((UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(created_at))/3600 + 2, 1.5)) AS hot_score
            FROM articles
            ORDER BY hot_score DESC
            LIMIT 30";
    return $pdo->query($sql)->fetchAll();
}

使用Redis实现实时热度排序(适合高并发)

如果项目量较大,直接在MySQL里算会拖慢查询,用Redis的 Sorted Set 可以实时更新热度。

行为发生时更新Redis

<?php
// 用户点赞某篇文章
$redis->zIncrBy('hot_articles', 5, 'article:123'); // 5 = 点赞权重
// 某文章被浏览
$redis->zIncrBy('hot_articles', 1, 'article:123'); // 1 = 浏览权重
// 时间衰减(定期执行)
$redis->zAdd('hot_articles', ['CH' => true], 'article:123', $newScore);

定时任务进行时间衰减

可以使用Laravel的Task Scheduling或crontab,每分钟执行一次衰减:

<?php
// 对Sorted Set中的所有元素执行时间衰减
public function decayHotScores() {
    // 每个元素分数乘以衰减因子 0.95(每5分钟衰减5%)
    $redis->zInterstore('hot_articles_temp', ['hot_articles'], [0.95]);
    $redis->rename('hot_articles_temp', 'hot_articles');
}

获取热度排序

$hotArticles = $redis->zRevRange('hot_articles', 0, 19, true); // 前20名

定时离线计算(适合复杂逻辑、大数据量)

如果权重、算法经常变,或数据量极大,可以用定时脚本(如Laravel Job、cron任务)在后台算出热度并存入数据库缓存字段。

建立一个缓存字段

ALTER TABLE articles ADD COLUMN hot_score DECIMAL(10,4) DEFAULT 0;

定时脚本更新

<?php
// 每10分钟执行一次
function recalculateScores() {
    $articles = Article::all();
    foreach ($articles as $article) {
        $age = time() - $article->created_at->timestamp;
        $score = ($article->views * 1 + $article->likes * 5 + $article->comments * 10)
               / pow(($age / 3600 + 2), 1.5);
        $article->hot_score = $score;
        $article->save();
    }
}

查询时直接 ORDER BY hot_score DESC,速度极快。


总结建议

项目规模 建议方案 原因
小型(日活<1000) MySQL公式 简单、无额外依赖
中型社区/新闻站 方案二 + 方案四缓存 逻辑清晰,速度快
高并发、实时性强 Redis Sorted Set 避免数据库压力
算法复杂且多变 离线计算 灵活易维护

关于时间衰减的调整建议:

  • 电影、知识类:半衰期可以设为7天(衰减慢)
  • 短视频、新闻:半衰期设为30分钟(衰减快)
  • 电商商品:可以按绝对时间分段(24小时内加权,之后逐步减弱)

你可以根据产品的核心指标(比如更看重“新”还是“热”)来调节权重和时间衰减系数。

抱歉,评论功能暂时关闭!