redis排序,分数相同的时候自定义排序规则

我们知道redis的zset是一个很好的排序工具,他会以member - score 的形式来排序,但是,当分数相同的时候,是按照member的字典序来排的,这样就有点不友好了,比如,我们要求当score相同时,先达到的排在前面,也就是最后更新时间小的排在前面。

针对这样的需求,我们必须将更新时间整合到score里面去。
我们知道score可以是整形和双精度浮点型。
要按照updatetime从小到大排序,我们可以用一个MAX-updatetime
而且,为了便于拆分真实score和辅助的数据,我们需要一个分隔符,网上有人说按照MAX-updatetime时间戳位数来分割,实际上不准,这取决于你的MAX大小。

我的做法是:

const MAX = 9999999999;// 十位

public static function updateRank($userId, $score)
{
    $key1 = "test";
    if (!Redis::exists($key1)) {
        $createScore = self::createScore(null, $score);
        Redis::zadd($key1, $createScore, $userId);
        Redis::expire($key1, 86400);
    } else {
        $source = Redis::zscore($key1, $userId);
        $createScore = self::createScore($source, $score);
        Redis::zadd($key1, $createScore, $userId);
    }

    return true;
}

public static function createScore($source, $socre){
    if(is_null($source) || $source === false){
        $score = $socre . '.' . strval( round(self::MAX - time(), 0) );
    }else{
        $arr = explode('.', $source);
        $score = intval($socre + $arr[0]) . '.' . strval( round(self::MAX - time(), 0) );
    }

    return $score;
}

最终的存储结果为:15.570245535
注意,你的真实的score尽量取整,因为小数点的精度已经很高了,不能再增加小数位的长度,但是整数位可以加到很大,基本可以满足需求。

然后取出来的时候

$temp = floatval($score);// 15.8423434494xxxxxxxx
$head = intval($temp);
$dot = ($temp - $head) * pow(10, 10);
$updatetime = round(Read3Service::MAX - $dot, 0);

MAX取值不能过大,会导致整数溢出,结果混乱。

关于整型的溢出,可以参考:https://blog.csdn.net/raoxiaoya/article/details/103693482

发布了412 篇原创文章 · 获赞 25 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/raoxiaoya/article/details/103585641