目录

实时积分排行榜

需求

设计实现

更多思考


大家好,我是鱼皮,暑假快到了,我的老弟小阿巴听说我家有很多好康的,就跑来找我玩。

结果我摆出了几个以前开发过的小系统,准备在这段时间带着小阿巴多做些作品,学习编程项目的设计思路。这样等他开学了,就可以更轻松地跟着老师做做项目了。

今天,就先带他做一个很常见的小功能:用户实时积分排行榜。

实时积分排行榜

需求

先描述下需求,在我的编程导航项目中,为了鼓励大家共同维护网站,用户可以通过推荐资源、积极评论、举报违规资源等方式获取积分。

为了进一步激励大家,网站需要提供一个用户积分排行榜,分为 实时总积分榜 、 周榜 和 月榜,均 只取前 10 名 。所有用户都能够查看当前排行榜,以及查看自己的 实时 总积分排名,后续管理员就可以给上榜用户颁发奖品了。

效果如下图:

点击 我的排名 按钮,可以查看自己的实时排名:

本文篇幅有限,先仅讨论 实时总积分榜 的设计实现。

听了需求后,小阿巴爽朗一笑:这有啥难的?且让我设计一波,再给你娓娓道来。

设计实现

先看下数据库的结构,总共有 2 个表:用户表 和 用户积分表

用户表存储了用户信息,以及用户的总积分(实时更新),也就是说总积分榜需要的数据可以直接从这里取到,不需要再去计算。

用户表内容:

用户 id 用户名 积分(score)
1 小阿巴 10
2 李鱼皮 1000
3 小李 100
......
100 李老热 66

如果要取前 10 名,只需要把所有用户的信息先取出来,再排个序就好啦,写 SQL 语句查询的话就是:

select * from `user` order by score;

然后如果要取自己的总排名,就对查到的有序数据进行一次遍历,找到自己所在的位置下标就行,伪代码如下:

// 从数据库查询全部用户列表
list = getAllDataList()
for(i = 0; i < total; i++) {// 找到自己的位置if(list[i].id == '我的id') {return i + 1;}
}

小阿巴得意到:这不就实现总积分榜了么?你这需求太简单,啧啧。

我笑到:还不错,总积分榜的思路是正确的,起码知道要对所有的数据进行排序。但如果用户数特别多呢?比如几十万个,你只需要查自己的总排名,还需要把全部的数据都做一个排序么?

小阿巴陷入沉思,想了半天,没想出来。

于是我提示到:假如在一次考试中你想知道自己的排名,是不是只需要知道有多少人的分数比自己高就行了,不用去管其他人排第几对吧?

小阿巴一拍脑袋:对啊,我只需要先查出自己的分数,然后统计分数大于我的用户数量,不就知道自己的排名了?

先用 SQL 语句查出用户的分数:

/* 只取需要的列 */
select score as myScore
from `user`
where id = "用户 id";

然后再用 SQL 语句统计分数大于该用户分数的数量:

select count(*) from `user`
where score > myScore;

最后只需要将该查询结果加 1,就是自己的排名啦~

小阿巴感叹到:原来转换一点点思路,就能省去多余的排序带来的性能开销,起飞~

更多思考

鱼皮:先别起飞,其实对于一般用户量的系统,上面的方案就已经足够了。下面让我们加大难度,假如用户数再多一点点呢,比如说一亿个,怎么实时获取前 10 名呢?

小阿巴:还真是 “亿点点”,就您那破编程导航还想着有一亿个用户?

鱼皮:少废话,梦想还是要有的,万一有亿个用户呢?快想想系统怎么做!

小阿巴:且不说对一亿个数据排序有多慢,能不能存的下都是个问题啊。。。啊,等等,这难道就是面试常见的 Top N 问题!

鱼皮:不错,我面试的时候被问过好几次 Top N 问题,如何从海量数据中找出前 N 个数呢?

小阿巴:这我完全不懂啊,算法不会,真要命。

鱼皮:其实 Top N 问题的核心在于保证空间和时间复杂度,先要考虑数据能存入内存运算,在怎样算得更快。

通常 Top N 问题有下列几种解决方案。

Top N 解决方案

全部排序

直接对所有数据进行排序(快排等),缺点是需要将数据一次性加载到内存中。

局部淘汰

内存中维护一个大小为 N 的容器,再让剩余的数一个个进入容器,并淘汰容器内的最小值。最终容器内剩下的数就是前 N 名。优点是能节省内存,缺点是太慢了。

分治

把数据分为多个小组,小组内先分别选出前 N 名小组长,最后再让这些小组长同台竞技,选出最终的前 N 名。

哈希预处理

假如数据重复度很高,可以通过 hash 的方式,去掉很多重复数据。比如 1 亿个数据里,一半是 0,一半是 1,那么取前 10 名时,可以直接淘汰掉另一半为 0 的数据。

但是预处理本身也需要时间和空间,这就需要我们对数据的重复度有一个清晰的判断,否则自作聪明、适得其反。

小根堆

面试算法中的高频考点 —— 堆排序,可以先取前 N 个数组成小根堆,堆顶始终是最小值。然后遍历后续数字,大于堆顶就替换掉堆顶并调整最小堆结构。该算法时间复杂度和空间复杂度(为 N,常数)都不错,所以必须要掌握。

但是具体选择哪种方案呢?还是要结合我们实际的项目和业务场景来分析。

实际解决

由于我们的数据库来记录积分,所以当用户量级很大时,首先要 分库分表 ,通常是水平分表,根据一定规则(比如 id)把用户数据行分批存储在多个数据表中。

分表

然后就和大数据 Map / Reduce 处理机制一样了,可以采用 分治 的方式 并行计算 每个表的前 10 名(map),都计算好后,再汇总到一起计算最终的前 10 名(reduce)。

一次大数据并行处理过程

用这种方式,别说 1 亿了,2 亿、3 亿的计算模式都是一样的,加机器水平扩容就好了~

所以遇到 Top N 问题的时候,大家可以先答一下上面的几种方案,再结合具体的场景分析,分治和最小堆是我觉得相对 核心 的点。

Redis

最后,对于实时排行榜的设计,肯定很多背过八股文面试题的朋友在第一时间会想到使用 Redis 的有序集合 zset,的确也是一种方案,但也要结合场景去分析利弊,不要秒答。

使用基于内存的 Redis zset 的确运算更快,且天然支持排序、使用方便。但数据量大时同样面临数据更新、维护、同步、持久化存储等问题,而且对于我们这种实时性要求不高的需求来说,有些大材小用了哈哈。

zset 数据结构

带老弟做个实时排行榜相关推荐

  1. 2020年CSDN博客之星实时排行榜——热门有你

    我根据C#抓取了博客之星页面的数据,做一个实时排行榜,数据截止 2021年01月23日 10:20 拉票太难了!大家有余票的,支持下我啊!编号150号: 支持点我投票. 排名 博主 票数 投票 1 博 ...

  2. 用20块的摄像头(不带fifo的OV7670)做WiFi实时传图小车

    博客地址 用20块的摄像头(不带fifo的OV7670)做WiFi实时传图小车 – Infinite's Blog 零.导读 在这篇文章中,你将看到如下内容: OV7670 QVGA配置的注意事项: ...

  3. 用 Redis 搞定游戏中的实时排行榜,附源码!

    原文:segmentfault.com/a/1190000019139010 1. 前言 前段时间刚为项目(手游)实现了一个实时排行榜功能, 主要特性: 实时全服排名 可查询单个玩家排名 支持双维排序 ...

  4. 给孩子讲100个科学道理,不如带他做这些趣味实验!

    ▲ 数据汪特别推荐 点击上图进入玩酷屋 玩具和学习看似是两个对立的东西,孩子天性爱玩,家长却希望孩子能多学习. 不一定非要啃课本才能汲取知识,有时候,在轻松有趣的游戏中也能学到课堂上学不到的知识. 让 ...

  5. 春节特惠活动┃给孩子讲100个科学道理,不如带他做这些趣味实验!

    ▲ 数据汪特别推荐 点击上图进入玩酷屋 玩具和学习看似是两个对立的东西,孩子天性爱玩,家长却希望孩子能多学习. 不一定非要啃课本才能汲取知识,有时候,在轻松有趣的游戏中也能学到课堂上学不到的知识. 让 ...

  6. 我和小美的撸码日记(1)之软件也需靠脸吃饭,带您做张明星脸(附后台经典框架 DEMO 下载)...

    众所周知程序员得靠技术吃饭,但是真的光靠技术就够了吗?Teacher苍,一位德艺双馨的艺术家,论技术她自然是炉火纯青,我觉得她桃李遍天下的原因不仅限于些,试想如果Teacher苍长得跟凤姐一样再带点乡 ...

  7. 百度SEO站群Emlog最新付费模板带会员 做资源网不错

    百度SEO站群Emlog最新付费模板带会员 做资源网不错 打开emlog后台导入模板即可使用,拿去做资源网不错~ 下载地址: http://www.bytepan.com/Z4J0oKiDLII

  8. 雷军正式入驻B站,或为小米新品直播带货做准备

    伴随着小米10超大杯的消息愈发火热,雷军也在加紧为其花式预热.昨天,雷军还发布微博称:"有朋友问我,最近流行直播带货和演讲,你怎么看?"疑似为其直播带货做铺垫. 众所周知,目前数码 ...

  9. 如何在完全不懂服务器开发的情况下做一个实时联网对战的微信小游戏

    微信小游戏即将开放?有我们在,你还赶得上! 根据微信官方对外公开的消息,微信小游戏的脚步越来越接近了.它的开发者资格门槛和使用者门槛都很低,以后必将引爆一波"全民开发小游戏"浪潮. ...

最新文章

  1. Java之关于面向对象
  2. 将数字字符串转换成逗号分隔的数字串,即从右边开始每三个数字用逗号分隔
  3. Redis:22---客户端API:client、monitor)
  4. react 项目总结
  5. C++ WINDOWS下 wchar_t *和char * 相互转化总结篇
  6. 阿里资深技术专家崮德:8 个影响我职业生涯的重要技能
  7. 常见的SQL笔试题和面试题:SQL经典50题
  8. CloudCC:2017年下半年企业移动CRM市场风向窥测
  9. JavaScript之this,new,delete,call,apply
  10. poj3204Ikki's Story I - Road Reconstruction(最大流求割边)
  11. .NET 2.0中的企业库异常处理块
  12. 字符数组的ss.toString()和new String(ss)的问题
  13. Java编写网络爬虫
  14. 3559A对接IMX577 4lane 12M
  15. 解决centos 7 打开php文件直接下载问题
  16. ddl是什么意思网络语_ddl是什么意思(网络语ddl是什么梗)
  17. 腾讯发布区块链产业加速器,生态共创助力新基建建设
  18. 创文明城市在路上,信息报送有高招
  19. office word 自动生成目录 以及多级列表级别的设置
  20. BLAST中的E值(E-value)

热门文章

  1. 公众平台返回原始数据为: 错误代码-40164
  2. 大数据应用之双色球算奖平台总体设计数据规模估算篇 - 张子良
  3. python将模块转变成whl文件
  4. 新兴国家战略级安全话题-软件供应链安全
  5. 开机手动启动 MySQL 服务
  6. requests.exceptions.SSLError: HTTPSConnectionPool
  7. Android 性能优化 - 彻底解决内存抖动
  8. UML与软件工程专题集锦
  9. js禁止鼠标滑轮_javascript实现禁止鼠标滚轮事件
  10. 实习日志(编写电商系统)