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()
相关推荐
lx1885486989628 分钟前
Redis大Key阻塞:单线程CPU100%的致命陷阱
数据库·redis·缓存
IT策士31 分钟前
Redis 从入门到精通:位图、HyperLogLog、GEO
数据库·redis·缓存
IT策士1 小时前
Redis 从入门到精通:Python 操作 Redis 进阶
数据库·redis·python
布局呆星1 小时前
Spring Boot + Redis 缓存实战:@Cacheable、序列化踩坑、缓存一致性,一次讲透
spring boot·redis·缓存
Devin~Y1 小时前
大厂 Java 面试实战:从 Spring Boot 微服务到 AI RAG 音视频平台全链路解析
java·spring boot·redis·spring cloud·微服务·rag·spring ai
正经教主2 小时前
【docker基础】Redis的docker部署
redis·docker·容器
闪电悠米2 小时前
黑马点评-Redis 消息队列-04_stream_seckill_order
数据库·redis·分布式·缓存·oracle·junit·lua
成为你的宁宁2 小时前
【基于 Prometheus Operator 实现 K8s 环境下 Redis Cluster 集群监控部署】
redis·kubernetes·prometheus
bmjIjFNC82 小时前
Redis分布式锁进第九十一篇
数据库·redis·分布式
维尔康3 小时前
【无标题】
redis