某海量用户网站,用户拥有积分,积分可能会在使用过程中随时更新。现在要为该网站设计一种算法,在每次用户登录时显示其当前积分排名。用户最大规模为2亿;积分为非负整数,且小于100万。

news/2024/5/20 6:27:19/文章来源:https://blog.csdn.net/zy_dreamer/article/details/9138199

http://www.mianwww.com/html/2012/11/17432.html

PS: 据说这是迅雷的一道面试题,不过问题本身具有很强的真实性,所以本文打算按照真实场景来考虑,而不局限于面试题的理想环境。
存储结构
首先,我们用一张用户积分表user_score来保存用户的积分信息。

表结构:

示例数据:

下面的算法会基于这个基本的表结构来进行。
算法1:简单SQL查询
首先,我们很容易想到用一条简单的SQL语句查询出积分大于该用户积分的用户数量:
select 1 + count(t2.uid) as rankfrom user_score t1, user_score t2where t1.uid = @uid and t2.score > t1.score
对于4号用户我们可以得到下面的结果:

算法特点

优点:简单,利用了SQL的功能,不需要复杂的查询逻辑,也不引入额外的存储结构,对小规模或性能要求不高的应用不失为一种良好的解决方案。

缺点:需要对user_score表进行全表扫描,还需要考虑到查询的同时若有积分更新会对表造成锁定,在海量数据规模和高并发的应用中,性能是无法接受的。
算法2:均匀分区设计
在许多应用中缓存是解决性能问题的重要途径,我们自然会想能不能把用户排名用Memcached缓存下来呢?不过再一想发现缓存似乎帮不上什么忙,因为用户排名是一个全局性的统计性指标,而并非用户的私有属性,其他用户的积分变化可能会马上影响到本用户的排名。然而,真实的应用中积分的变化其实也是有一定规律的,通常一个用户的积分不会突然暴增暴减,一般用户总是要在低分区混迹很长一段时间才会慢慢升入高分区,也就是说用户积分的分布总体说来是有区段的,我们进一步注意到高分区用户积分的细微变化其实对低分段用户的排名影响不大。于是,我们可以想到按积分区段进行统计的方法,引入一张分区积分表score_range:

表结构:

数据示例:

表示[from_score, to_score)区间有count个用户。若我们按每1000分划分一个区间则有[0, 1000), [1000, 2000), …, [999000, 1000000)这1000个区间,以后对用户积分的更新要相应地更新score_range表的区间值。在分区积分表的辅助下查询积分为s的用户的排名,可以首先确定其所属区间,把高于s的积分区间的count值累加,然后再查询出该用户在本区间内的排名,二者相加即可获得用户的排名。

乍一看,这个方法貌似通过区间聚合减少了查询计算量,实则不然。最大的问题在于如何查询用户在本区间内的排名呢?如果是在算法1中的SQL中加上积分条件:
select 1 + count(t2.uid) as rankfrom user_score t1, user_score t2where t1.uid = @uid and t2.score > t1.score and t2.score < @to_score
在理想情况下,由于把t2.score的范围限制在了1000以内,如果对score字段建立索引,我们期望本条SQL语句将通过索引大大减少扫描的user_score表的行数。不过真实情况并非如此,t2.score的范围在1000以内并不意味着该区间内的用户数也是1000,因为这里有积分相同的情况存在!二八定律告诉我们,前20%的低分区往往集中了80%的用户,这就是说对于大量低分区用户进行区间内排名查询的性能远不及对少数的高分区用户,所以在一般情况下这种分区方法不会带来实质性的性能提升。

算法特点

优点:注意到了积分区间的存在,并通过预先聚合消除查询的全表扫描。

缺点:积分非均匀分布的特点使得性能提升并不理想。
算法3:树形分区设计
均匀分区查询算法的失败是由于积分分布的非均匀性,那么我们自然就会想,能不能按二八定律,把score_range表设计为非均匀区间呢?比如,把低分区划密集一点,10分一个区间,然后逐渐变成100分,1000分,10000分 … 当然,这不失为一种方法,不过这种分法有一定的随意性,不容易把握好,而且整个系统的积分分布会随着使用而逐渐发生变化,最初的较好的分区方法可能会变得不适应未来的情况了。我们希望找到一种分区方法,既可以适应积分非均匀性,又可以适应系统积分分布的变化,这就是树形分区。

我们可以把[0, 1,000,000)作为一级区间;再把一级区间分为两个2级区间[0, 500,000), [500,000, 1,000,000),然后把二级区间二分为4个3级区间[0, 250,000), [250,000, 500,000), [500,000, 750,000), [750,000, 1,000,000),依此类推,最终我们会得到1,000,000个21级区间[0,1), [1,2) … [999,999, 1,000,000)。这实际上是把区间组织成了一种平衡二叉树结构,根结点代表一级区间,每个非叶子结点有两个子结点,左子结点代表低分区间,右子结点代表高分区间。树形分区结构需要在更新时保持一种不变量(Invariant):非叶子结点的count值总是等于其左右子结点的count值之和。

以后,每次用户积分有变化所需要更新的区间数量和积分变化量有关系,积分变化越小更新的区间层次越低。总体上,每次所需要更新的区间数量是用户积分变量的log(n)级别的,也就是说如果用户积分一次变化在百万级,更新区间的数量在二十这个级别。在这种树形分区积分表的辅助下查询积分为s的用户排名,实际上是一个在区间树上由上至下、由粗到细一步步明确s所在位置的过程。比如,对于积分499,000,我们用一个初值为0的排名变量来做累加;首先,它属于1级区间的左子树[0, 500,000),那么该用户排名应该在右子树[500,000, 1,000,000)的用户数count之后,我们把该count值累加到该用户排名变量,进入下一级区间;其次,它属于3级区间的[250,000, 500,000),这是2级区间的右子树,所以不用累加count到排名变量,直接进入下一级区间;再次,它属于4级区间的…;直到最后我们把用户积分精确定位在21级区间[499,000, 499,001),整个累加过程完成,得出排名!

虽然,本算法的更新和查询都涉及到若干个操作,但如果我们为区间的from_score和to_score建立索引,这些操作都是基于键的查询和更新,不会产生表扫描,因此效率更高。另外,本算法并不依赖于关系数据模型和SQL运算,可以轻易地改造为NoSQL等其他存储方式,而基于键的操作也很容易引入缓存机制进一步优化性能。进一步,我们可以估算一下树形区间的数目大约为200,000,000,考虑每个结点的大小,整个结构只占用几十M空间。所以,我们完全可以在内存建立区间树结构,并通过user_score表在O(n)的时间内初始化区间树,然后排名的查询和更新操作都可以在内存进行。一般来讲,同样的算法,从数据库到内存算法的性能提升常常可以达到10^5以上;因此,本算法可以达到非常高的性能。

算法特点

优点:结构稳定,不受积分分布影响;每次查询或更新的复杂度为积分最大值的O(log(n))级别,且与用户规模无关,可以应对海量规模;不依赖于SQL,容易改造为NoSQL或内存数据结构。

缺点:算法相对更复杂。
算法4:积分排名数组
算法3虽然性能较高,达到了积分变化的O(log(n))的复杂度,但是实现上比较复杂。另外,O(log(n))的复杂度只在n特别大的时候才显出它的优势,而实际应用中积分的变化情况往往不会太大,这时和O(n)的算法相比往往没有明显的优势,甚至可能更慢。

考虑到这一情况,仔细观察一下积分变化对排名的具体影响,可以发现某用户的积分从s变为s+n,积分小于s或者大于等于s+n的其他用户排名实际上并不会受到影响,只有积分在[s,s+n)区间内的用户排名会下降1位。我们可以用于一个大小为100,000,000的数组表示积分和排名的对应关系,其中rank[s]表示积分s所对应的排名。初始化时,rank数组可以由user_score表在O(n)的复杂度内计算而来。用户排名的查询和更新基于这个数组来进行。查询积分s所对应的排名直接返回rank[s]即可,复杂度为O(1);当用户积分从s变为s+n,只需要把rank[s]到rank[s+n-1]这n个元素的值增加1即可,复杂度为O(n)。

算法特点

优点:积分排名数组比区间树更简单,易于实现;排名查询复杂度为O(1);排名更新复杂度O(n),在积分变化不大的情况下非常高效。

缺点:当n比较大时,需要更新大量元素,效率不如算法3。
总结
上面介绍了用户积分排名的几种算法,算法1简单易于理解和实现,适用于小规模和低并发应用;算法3引入了更复杂的树形分区结构,但是O(log(n))的复杂度性能优越,可以应用于海量规模和高并发;算法4采用简单的排名数组,易于实现,在积分变化不大的情况下性能不亚于算法3。本问题是一个开放性的问题,相信一定还有其他优秀的算法和解决方案,欢迎探讨!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_878442.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux服务器做301跳转,网站seo怎么实现301跳转,linux服务器设置301重定向方法!

原标题&#xff1a;网站seo怎么实现301跳转,linux服务器设置301重定向方法! 在SEO优化中&#xff0c;这些已经存在可能已被收录的页面链接&#xff0c;既不能贸然的删除又不能放任不管&#xff0c;由于这跟网站的权重是挂钩的&#xff0c;以是这个时辰301定向就派上用场了。301…

WEB阶段6:过滤器监听器全局字符修改案例用户权限过滤案例装饰者模式过滤敏感词汇统计当前网站在线人数

过滤器&监听器&全局字符修改案例&用户权限过滤案例&装饰者模式过滤敏感词汇&统计当前网站在线人数 回顾 JSP的页面脚本元素 组成部分语法格式JSP代码片段<% Java代码 %>JSP声明<%! 声明全局变量 %>JSP脚本表达式<% 变量值 %>注释<…

扩展 jQuery EasyUI Datagrid 数据行鼠标悬停/离开事件(onMouseOver/onMouseOut)

客户需求&#xff1a; jQuery EasyUI Datagrid 用户列表鼠标悬停/离开数据行时显示人员头像&#xff08;onMouseOver/onMouseOut&#xff09; 如图所示&#xff0c;Datagrid 鼠标悬停/离开数据行时切换了不同的样式显示&#xff1a; 此时用谷歌开发者工具审查鼠标悬停行元素时…

推荐一款在线伪原创工具,很适合做seo的朋友

打开常用浏览器,360极速&#xff0c;UC&#xff0c;谷歌浏览器均可这里就打开谷歌做演示 浏览器中输入http://www.yzcopen.com/选着站长seo工具 找到第一行"文章伪原创"工具 复制自己的文章即可点击生成伪原创 伪原创文章对于各大搜索引擎来说&#xff0c;收录会很不…

分享一波我是怎么让一个新网站IP量一天翻15倍的,腾讯云:DDOS攻击

一直想写一篇文章&#xff0c;和大家分享一下我的一个在线工具网站如何将网站的日IP访问量做到一天翻15倍的技巧。现在想想是时候可以分享一些了&#xff01;正如标题所说&#xff0c;在一定时间内做一个日IP访问量一天翻15倍的的网站有可能吗&#xff1f;当然有可能了。这也是…

查看当前网站的cookie的两种快捷方法

1.在浏览器的地址栏输入&#xff1a;javascript:alert(document.cookie) (不区分大小写)&#xff0c;就会弹出你在当前网页登录的cookie信息。 注意&#xff1a;你把以上复制进入地址栏后会发现&#xff0c;“javascript”字符串消失不见&#xff0c;不管“javascript”里面哪…

大型网站后台架构的演变

随着用户访问量的不断增加&#xff0c;网站的后台也会不断变化以应对需求。本文主要从一个小型网站到大型网站的过度与变化来陈述。 1.1 网站后台架构 主要指由web server 、应用服务器、数据库、存储、监控等组成的网站后台系统。 1.2 架构演变 个人站点后台架构。如图2-1…

大型网站的高可用分析

本文主要分析网站的高可用性&#xff0c;从应用需求、用户角度展开分析。 1.1 高可用性 “高可用性”(High Availability) 通常用来描述一个系统&#xff0c;经过特殊设计&#xff0c;减少停止服务的时间&#xff0c;从而使其服务保持高度的可使用性。 计算机系统的可靠性用…

大型网站后台架构的web server与缓存

网站的web server与缓存 1.1 Web server Webserver 用来解析HTTP协议。当web 服务器接收到一个HTTP请求时&#xff0c;会返回一个HTTP响应&#xff0c;例如送回一个HTML页面。为了处理一个请求&#xff0c;web服务器可以响应一个静态页面或者图片。进行页面跳转&#xff0c;…

大型网站的负载均衡器、db proxy和db

大型网站的负载均衡器、db proxy和db 本文主要分析网站后台架构中的负载均衡器&#xff0c;企业常用的硬件负载均衡器软件负载均衡器、数据库代理服务器和数据库。 1.1 负载均衡 在大型网站部署中&#xff0c;负载均衡至少有三层部署。第一层为web server或者缓存代理之上的…

大型网站的存储

本文主要论述一下常用的存储产品和技术。 1.1 存储 存储设备是网站后台架构中&#xff0c;最底层的部分。也是最重要的部分。因为一旦存储设备出现问题&#xff0c;将直接导致上层的数据层和应用层的服务停止。严重的存储设备的损坏以及不可恢复的数据丢失会给企业造成巨大的…

大型网站的监控、报警与故障转移

本章主要从大型网站的后台监控机制、报警机制和故障转移、服务切换等内容来论述。然后给出一个监控、报警和故障转移的解决方案。 1.1 监控预警 现代大型互联网公司主要有电子商务公司、社交网站公司和搜索引擎公司。在电子商务网站公司中&#xff0c;taobao.com的点击量在国…

【项目记录】移动端购物网站首页/登录页/注册页

1-1初始化 1&#xff09;vue create jingdong 勾选sass语法、哈希路由 删除git相关 2&#xff09;npm run serve启动 1-2目录简介 插件 Vetur高亮显示、Eslint校验语法 入口文件&#xff1a;main.js 1.创建一个APP实例 2.使用router 3.使用store&#xff08;属vuex&#xff0c;…

基于javaweb大棚蔬菜管理系统网站加后台

软件环境&#xff1a;eclipse2020 tomcat9.0 mysql5.5, jdk1.8 开发技术&#xff1a;java, jsp, servlet,layui,bootstrap&#xff0c;ajax 系统功能&#xff1a; 基础功能&#xff1a;登录注册 1、后台管理&#xff08;管理员端&#xff09; &#xff08;1&#xff09;用…

基于javaweb流浪动物救助网站(前端+后端)

一、系统简介 本项目采用eclipse工具开发&#xff0c;layuijspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为2个角色分别是&#xff1a;领养用户&#xff0c;管理员 二、模块简介 管理员 1、登录 2、个人信息管理 3、…

基于javaweb新闻网站管理系统

一、系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为3个角色分别是&#xff1a;用户&#xff0c;管理员&#xff0c;编辑者 二、模块简介 管理员 1、登录 2、个人信息…

基于javawe城市旅游网站系统

一、系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为2个角色分别是&#xff1a;管理员&#xff0c;用户 二、模块简介 管理员 1、登录 2、个人信息管理 3、用户管理 …

基于javaweb的中药材网站管理系统+在线购物

一、系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为2个角色分别是&#xff1a;管理员&#xff0c;用户 二、模块简介 管理员 1、登录 2、用户管理 3、药材管理 4、…

通信学习网站链接

1&#xff0c;http://www.techplayon.com/5gnr/ 有视频讲解&#xff0c;新发现的比较好的通信网站之一。 2&#xff0c;http://www.sharetechnote.com/ 涵盖通信的各个层面&#xff0c;概念讲解非常透彻。

pycharm下载第三方库(镜像网站+终端)

例如下载bs4包 1.打开终端&#xff08;WINR后输入cmd&#xff09; 2.输入&#xff1a; pip install --targetc:\users\lenovo\appdata\local\programs\python\python310\lib\site-packages -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com bs4 c:\users\len…