如何计算Laravel中Server(等价Post)的评分并生成Top10榜单
解决方案:Server评分计算与Top10榜单实现
1. 修正模型关联错误
你的ServerUserLike模型里的server()关联写法有误,一条点赞记录属于单个Server,应该用belongsTo而非hasMany:
public function server() { return $this->belongsTo(Server::class); }
2. 批量统计单Server点赞数
无需单独查询单Server和总点赞数,直接用分组查询一次性统计所有Server的点赞数据,效率更高:
// 统计每个Server的点赞数 $serverLikeStats = DB::table('server_user_likes') ->select('server_id', DB::raw('count(*) as like_count')) ->groupBy('server_id') ->get();
3. 选择适合动态场景的评分算法
由于数据动态增长,普通的点赞数排序会导致新Server因少量点赞就占据高位,推荐两种适合的算法:
算法一:贝叶斯平均评分
平衡全局平均点赞数与单Server点赞数,避免极端情况,公式为:
$score = \frac{C \times m + n}{C + n}$
- $C$:调整系数(建议取全局平均点赞数或Server点赞数的中位数)
- $m$:所有Server的平均点赞数
- $n$:当前Server的点赞数
Laravel实现(直接在数据库层面计算):
// 计算全局基础数据 $totalServers = Server::count(); $totalLikes = DB::table('server_user_likes')->count(); $averageLikes = $totalServers > 0 ? $totalLikes / $totalServers : 0; // 取全局平均作为调整系数C $C = $averageLikes; // 计算Top10 Server $topServers = Server::leftJoin('server_user_likes', 'servers.id', '=', 'server_user_likes.server_id') ->select([ 'servers.*', DB::raw('COUNT(server_user_likes.id) AS like_count'), DB::raw('(' . $C . ' * ' . $averageLikes . ' + COUNT(server_user_likes.id)) / (' . $C . ' + COUNT(server_user_likes.id)) AS score') ]) ->groupBy('servers.id') ->orderBy('score', 'DESC') ->limit(10) ->get();
算法二:威尔逊得分
更严谨的统计模型,基于置信区间计算得分,适合点赞/无点赞的二项分布场景,能有效过滤样本量小的Server:
// 定义威尔逊得分计算函数 function calculateWilsonScore(int $likeCount): float { $z = 1.96; // 95%置信区间对应的Z值 $n = $likeCount; if ($n === 0) return 0; $p = 1; // 仅统计点赞,点赞率为1 $numerator = $p + ($z**2)/(2*$n) - $z*sqrt(($p*(1-$p))/$n + ($z**2)/(4*$n**2)); $denominator = 1 + ($z**2)/$n; return $numerator / $denominator; } // 获取所有Server的点赞数并计算得分,再取Top10 $serverLikes = DB::table('server_user_likes') ->select('server_id', DB::raw('count(*) as like_count')) ->groupBy('server_id') ->get() ->map(function ($item) { $item->score = calculateWilsonScore($item->like_count); return $item; }) ->sortByDesc('score') ->take(10) // 关联Server详情(可选) ->each(function ($item) { $item->server = Server::find($item->server_id); });
4. 性能优化建议
针对动态增长的海量数据,建议:
- 缓存榜单:用Redis缓存Top10结果,每隔固定时间(如10分钟)刷新一次,避免频繁计算
- 数据库索引:确保
server_user_likes表的server_id索引生效(你已添加,无需改动) - 异步计算:如果数据量极大,可将评分计算逻辑放入队列异步执行,不阻塞请求
内容的提问来源于stack exchange,提问作者CARSAR
相关产品推荐
相关产品推荐

