redis实现排行榜功能

实现一段 "开箱即用" 的 Python 脚本,只用 Redis 原生 Sorted Set(zset) 实现:

  • 实时积分榜(可扩展到任何带分数的排行榜)
  • 支持 并列排名 (相同分数同榜)、获取 TopN查询用户所在页
  • 支持 分数更新用户淘汰分页翻页
  • 全部封装成函数,复制即运行。

leaderboard_demo.py

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
纯 Redis Sorted Set 实现排行榜
功能:更新分数、TopN、分页、并列排名、查用户排名
"""
import redis
from math import ceil

# ----------- 配置 -----------
REDIS_CFG = dict(host="127.0.0.1", port=6379, db=0, decode_responses=True)
KEY = "game:score_rank"          # 排行榜 key
PAGE_SIZE = 10                   # 翻页大小
# ----------------------------


class LeaderBoard:
    def __init__(self, key: str, r: redis.Redis):
        self.key = key
        self.r = r

    # 更新/新增分数(可增量)
    def set_score(self, user: str, score: int, incr: bool = False):
        if incr:
            return int(self.r.zincrby(self.key, score, user))
        self.r.zadd(self.key, {user: score})
        return score

    # 删除用户
    def remove(self, *users):
        return self.r.zrem(self.key, *users)

    # 获取 TopN(含分数)
    def top(self, n: int, with_scores=True):
        """
        返回 [(user, score), ...]  分数从高到低
        """
        return self.r.zrevrange(self.key, 0, n - 1, withscores=with_scores)

    # 获取用户排名(分数相同并列,排名从 1 开始)
    def rank_of(self, user):
        """
        并列排名做法:先拿分数,再统计 > 该分数的人数
        """
        score = self.r.zscore(self.key, user)
        if score is None:
            return None
        # zrevrangebyscore 闭区间,+inf 到 (score+1) 开区间
        rank = self.r.zcount(self.key, f"({score}", "+inf") + 1
        return int(rank)

    # 分页读取(闭区间,左右都含)
    def page(self, page: int, page_size: int = PAGE_SIZE, with_scores=True):
        start = (page - 1) * page_size
        stop = start + page_size - 1
        return self.r.zrevrange(self.key, start, stop, withscores=with_scores)

    # 总页数
    def total_pages(self, page_size: int = PAGE_SIZE):
        total = self.r.zcard(self.key)
        return ceil(total / page_size) if total else 1

    # 打印排行榜(方便看)
    def print_top(self, n: int = 20):
        data = self.top(n)
        print(f"-------- 前 {n} 名 --------")
        for rank, (user, score) in enumerate(data, 1):
            print(f"{rank:>2} | {user:<10} | {score}")


# ----------------- 演示 -----------------
def main():
    r = redis.Redis(**REDIS_CFG)
    lb = LeaderBoard(KEY, r)

    # 1. 模拟 30 个用户写分
    import random
    random.seed(42)
    users = [f"user{i:02d}" for i in range(1, 31)]
    for u in users:
        lb.set_score(u, random.randint(100, 1000))

    # 2. 展示 Top10
    lb.print_top(10)

    # 3. 查某个用户
    who = "user07"
    score = r.zscore(KEY, who)
    rank = lb.rank_of(who)
    print(f"\n{who} 分数={score}  并列排名={rank}")

    # 4. 翻页示例
    page = 2
    print(f"\n第 {page} 页(每页 {PAGE_SIZE}):")
    for idx, (user, score) in enumerate(lb.page(page), 1):
        real_rank = (page - 1) * PAGE_SIZE + idx
        print(f"{real_rank:>2} | {user:<10} | {score}")

    # 5. 更新分数 & 再看榜
    print("\n--- user07 暴击 +1000 ---")
    lb.set_score("user07", 1000, incr=True)
    lb.print_top(10)


if __name__ == "__main__":
    main()
相关推荐
Ahtacca3 小时前
Redis 五大常用数据类型详解及 Java 客户端(RedisTemplate)操作实战
java·数据库·redis·学习·缓存
rchmin6 小时前
Redis集群扩容数据迁移方案分析
redis·缓存
最贪吃的虎6 小时前
Redis 除了缓存,还能干什么?
java·数据库·redis·后端·缓存
哈里谢顿16 小时前
redis常见问题分析
redis
MySQL实战17 小时前
Redis 7.0 新特性之maxmemory-clients:限制客户端内存总使用量
数据库·redis
蜂蜜黄油呀土豆18 小时前
Redis 底层实现深度解析:从 ListPack 到哈希表扩容
数据结构·redis·zset·sds·listpack·哈希表扩容
斯普信云原生组18 小时前
Redis 阈值超限及影响分析
redis·spring·bootstrap
程序员JerrySUN19 小时前
OP-TEE + YOLOv8:从“加密权重”到“内存中解密并推理”的完整实战记录
android·java·开发语言·redis·yolo·架构
此生只爱蛋20 小时前
【Redis】数据类型补充
数据库·redis·缓存