本文目录导读:

在 PHP 项目中,Redis 的有序集合(Sorted Set,简称 ZSet)的排序主要依赖于分值(Score),你可以通过操作分值来控制元素的排序顺序。
以下是具体的实现方式和核心命令:
核心排序机制
Redis 的 ZSet 会根据分值从小到大进行排序,所有成员(Member)都必须关联一个分数(Score),Redis 使用跳表(Skip List)来实现这个有序结构。
常用排序操作命令
1 添加元素(设置分数)
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// ZADD key score member [score member ...]
// 添加或更新元素
$redis->zAdd('leaderboard', 100, 'player1');
$redis->zAdd('leaderboard', 200, 'player2');
$redis->zAdd('leaderboard', 50, 'player3');
?>
2 获取排序后的元素
<?php
// 获取所有元素,按分数从小到大
$result = $redis->zRange('leaderboard', 0, -1);
print_r($result);
// 输出: Array([0] => player3 [1] => player1 [2] => player2)
// 获取所有元素,按分数从大到小
$result = $redis->zRevRange('leaderboard', 0, -1);
print_r($result);
// 输出: Array([0] => player2 [1] => player1 [2] => player3)
// 带分数返回
$result = $redis->zRange('leaderboard', 0, -1, true);
print_r($result);
// 输出: Array(['player3'] => 50 ['player1'] => 100 ['player2'] => 200)
?>
3 获取排名
<?php
// 从小到大的排名(排名从0开始)
$rank = $redis->zRank('leaderboard', 'player1');
echo $rank; // 输出: 1 (因为player3是第0名)
// 从大到小的排名(排名从0开始)
$revRank = $redis->zRevRank('leaderboard', 'player1');
echo $revRank; // 输出: 1 (因为player2是第0名)
?>
自定义排序需求
1 按时间排序
<?php
// 使用时间戳作为分数,最新的排前面
$articleId = 1001;
$score = time(); // 当前时间戳
$redis->zAdd('news_timeline', $score, $articleId);
// 获取最新的10篇文章
$latestArticles = $redis->zRevRange('news_timeline', 0, 9);
?>
2 按复合排序(分数 + 时间戳)
<?php
// 场景:按点赞数排序,相同点赞数时按时间排序
// 使用公式:score = 点赞数 * 10^10 + 时间戳
$likes = 100;
$timestamp = time();
$score = $likes * pow(10, 10) + $timestamp;
$redis->zAdd('articles_ranking', $score, 'article:123');
// 获取排名靠前的数据
$topArticles = $redis->zRevRange('articles_ranking', 0, 9, true);
?>
批量操作与范围查询
<?php
// 获取分数在指定范围内的元素
$results = $redis->zRangeByScore('leaderboard', 50, 150);
print_r($results);
// 输出: Array([0] => player3 [1] => player1)
// 获取分数在指定范围内,从大到小排序
$results = $redis->zRevRangeByScore('leaderboard', 50, 150);
print_r($results);
// 输出: Array([0] => player1 [1] => player3)
// 获取分数区间内的元素数量
$count = $redis->zCount('leaderboard', 0, 100);
echo $count; // 输出: 2 (player3和player1)
?>
更新分数与排名
<?php
// 增加某个元素的分数
$redis->zIncrBy('leaderboard', 10, 'player1');
// player1的分数从100变为110
// 删除元素
$redis->zRem('leaderboard', 'player3');
// 获取集合大小
$size = $redis->zCard('leaderboard');
echo $size; // 输出: 2
?>
实际应用示例:游戏排行榜
<?php
class GameLeaderboard {
private $redis;
private $key;
public function __construct($key) {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
$this->key = $key;
}
// 更新玩家分数
public function updateScore($player, $score) {
return $this->redis->zAdd($this->key, $score, $player);
}
// 获取排行榜前N名
public function getTopPlayers($n = 10) {
return $this->redis->zRevRange($this->key, 0, $n - 1, true);
}
// 获取玩家排名
public function getPlayerRank($player) {
$rank = $this->redis->zRevRank($this->key, $player);
return $rank !== false ? $rank + 1 : null;
}
// 获取周围玩家(上下3名)
public function getNearbyPlayers($player, $range = 3) {
$rank = $this->redis->zRevRank($this->key, $player);
if ($rank === false) return null;
$start = max(0, $rank - $range);
$end = min($this->redis->zCard($this->key) - 1, $rank + $range);
return $this->redis->zRevRange($this->key, $start, $end, true);
}
}
?>
注意事项
- 分数精度:分数使用双精度浮点数,注意大数字的精度问题
- 性能优化:对于大型有序集合,使用
zRangeByScore带上 LIMIT 参数来分页 - 内存管理:有序集合占用内存较大,注意设置过期时间
- 分数相同:当分数相同时,按字典序排序
通过灵活运用这些命令和技巧,你可以在 PHP 项目中高效地实现各种排序需求。