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()
相关推荐
A.说学逗唱的Coke8 分钟前
【人工智能专题】Redis 杀进 AI 数据层:向量搜索、语义缓存与 Agent 记忆工程从入门到踩坑
人工智能·redis·缓存
XiYang-DING1 小时前
地图城市缓存优化:ApplicationReadyEvent + Caffeine + Redis + Redisson 分布式锁
redis·分布式·缓存
爱和冰阔落3 小时前
【Linux】多线程打印为什么会乱?pthread 创建、等待、退出、取消与分离全实战
linux·运维·c++·redis
一只小bit5 小时前
Redis哨兵机制、主从复制与集群搭建与维护
数据库·redis·bootstrap
智购科技无人售货机厂家12 小时前
2026自动售货机制冷系统维护指南:从散热器清洁到压缩机换油的工程实践~YH
运维·redis·物联网·缓存·架构
2601_9621741716 小时前
Redis 简介
数据库·redis·wpf
garmin Chen20 小时前
redis面试题
java·数据库·redis·缓存
2601_9621819621 小时前
Redis Redis介绍、安装 - Redis客户端
数据库·redis·postman
程序员夏洛1 天前
Redis 中如何实现分布式锁?
数据库·redis·分布式
程序员夏洛1 天前
Redis 的 Red Lock 是什么?你了解吗?
数据库·redis·缓存