论坛首页 Java企业应用论坛

迅雷的一个面试题

浏览 54838 次
精华帖 (8) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2012-03-01  
yinjh 写道
在具体的应用中,每个用户的分数是不是在随时变化着呢?比如游戏得分。
其实准确的名次没什么意义,可以利用概率啊。
随机取万分之一的数据排序
得到的名次乘以2万
就可以了。



这种方案也不错,只要保证最前面的排名实时即可(有些系统会列出top100的排名)。

其他人老想着实时,精确,老想着数据是有序的,难道这些真的有用???

积分排名,又不是金额,干嘛那么精确? 考虑具体需求的实用性吧
0 请登录后投票
   发表时间:2012-03-01  
3005218046 写道
hardPass 写道
tsxm 写道
hardPass 写道
就一定要用数据表来完成么?
CPU,内存,外存
同学们啊!

桶排序呗,
直接在程序中搞个数组,数组的下标就是分数,元素是每个分数对应的人数。

具体的,如果不需要精确计算,为了减少同步及遍历计算的性能损失,可以为每个数组元素设定一个预留值。







都说内存不够了,用外存估计速度太慢



1G内存还不够?如果现在排名第一的是1亿分,也就是一个长度为1亿的数组而已
300MB左右就够了,剩下的内存还可以再维护个计数缓存的数组(每个元素是上面数组希格玛,0到i),数组长度是上面数组一样


你只允许255个人得同样的分数啊...



数组的下标就是分数,元素是每个分数对应的人数


你没看清楚吧????
0 请登录后投票
   发表时间:2012-03-01  
一道简单的题目,考察了一个完整的数据库存储原理,2亿条记录,也算海量数据了,
基本处理思想是:
0、如果数据量真的非常大的很多,要考虑数据库分布式处理,数据库也可以负载均衡处理,但2亿条应该可以不用考虑这个。
1、一个统一的数据库内,切分成几个DBF文件,一个文件的最大存储量不要上G,一般来说500M-800M差不多了,保证数据库缓存加载搜索目标文件比较快速;
2、文件内进行分区处理,分区策略采用RANGE的吧,分数肯定都是根据范围切割的;
3、建立分区索引字典,分区内位记录建立关键字索引,比如ID建立索引;
4、查询的时候记录要根据ROWID或ROWNUM进行数据库存储区内分页查询,不要采用上面说的内存内去二分查找,一个内存中的数据不可能一下在全部加载完的,一次性5000条,单点服务器应该就有卡机和延迟现象了,所以要数据库存储区内分页查询搜索。
================================================================
给出一个分的话,就可以很轻松的定位到当前分数位于第几个分区了,这个分区的总的记录数,以及RANGE的范围是知道的,所以,计算一下分区的偏移量,计算一下分区内记录的偏移量,然后根据RANGE的范围就可以计算出排名了
0 请登录后投票
   发表时间:2012-03-01  
每天排一次,以uid -> rank的对应存起来,呵呵,别的没想到办法
0 请登录后投票
   发表时间:2012-03-01  
CshBBrain 写道
kidding87 写道
终于有人说了我说的东西。。。
你们难道就没发现别人说的是数据源,不是数据库
那么多数据select * from table where id=?没有索引这个的效率都低死,数据库还不是一个个找


的确,题目强调了是【数据源】,并且是有序的数据源,没有说具体的存储形式,用数据库,用文件系统,还是用缓存服务器集群......;其实大多数人一看到2亿条数据都想到自己采用怎样形式去存这个数据了,而忽略题目的本意是怎样快速有效的找出用户的排名;依我个人的愚见,用户登录系统时找到用户的分数排名,要到数据库去找,或是到文件系统去找花费不菲而且效率也不见得好,一般会放到缓存服务器集群中。当然其实数据源的存储形式我们不用去操心。用户登录肯定已经获取到id和自己的分数,我们就假设已经知道用户id和用户分数(这是比较合理的假设)。

数据源既然【有序】那么我们肯定就有办法(是什么办法根据数据源具体的存储形式可以写个方法<当然有可能数据源本身可以提供>)取到指定位置的元素。

1.获取数据源的最后一个元素和数据源的第一个元素的 score, 将这2个score 相减 得到的 最大分数与最小分数的差值 S1。
2.用得到的分数差值 除以 数据源的元素数量 得到 平均每个用户之间的 分数差 V1;
3.将用户的分数US 减去 数据源中最小分数 得到用户与最小 分数之间的差值 S2,
4.W = S2 / V1 ,W 为我们估算的用户在所有用户中的排名数量
5.取出W处的元素的score WS
6.如果 用户的分数US 小于 WS,则从 W处开始向前查找用户的排名,如果US大于 WS 则从W处开始向后查找用户的排名,用户的排名就在附近,不用加载太多数据。如果US的只等于WS,那么恭喜你了。
7.这个算法没有考虑分数相同并列排名的处理,我想迅雷也许也没有处理并列排名的情况,只是获取数据源中的具体位置。
8.如果分数分布特别不均匀的话,可以递归使用上面的方法多算几次,直到US 和 WS 相差非常小(小到一个阀值)再从W处开始向前或向后查找定位。

你好牛啊,就算面试官觉得你说的跟迅雷的做法不符,你分析了那么有条理,肯定对你有兴趣。
0 请登录后投票
   发表时间:2012-03-01  
id--4Bytes(假如迅雷野心不是那么大的话,2^32≈40多亿用户够用了^_^)
score--4Bytes
2亿数据≈2*10^8*8≈2^31Bytes=2GB。

1.直接二分查找log2^31=31(I/O)
2.若不考虑建立索引的时间,则把分数全部加在到内存中(2GB/2=1GB),二分查找即可,不需要I/O时间。
3.若考虑建立索引的时间,索引次数应当<31次才能更快,不过这个需要实验加载多大MB外存到内存时间后才能测量。
0 请登录后投票
   发表时间:2012-03-01  
freish 写道
select count(1) from tableName where scores>(select scores from tableName where id=MyID)

这方法我看行
0 请登录后投票
   发表时间:2012-03-01  
哪有这么多二分查找啊??
如果是按分数排序..
只给出了用户ID。不给用户的分数
怎么二分查?(先找到用户ID,再二分找分数?那为什么不找到用户ID的同时获取他的排名?)

如果给出了用户ID 又出了分数..
那用户ID有什么用???
直接根据分数找出排名就行了..

个人感觉.他应该是在考多线程处理能力访问的
迅雷是下载软件啊
0 请登录后投票
   发表时间:2012-03-01  
数据库按名次和分数分区建一个表
客户端缓存用户上次登录时查到的积分,在下次登陆时根据本地缓存的分数在分区表中查询名次区间,然后在分数表中从rownum=名次区间较小值开始查询id=用户id的记录,获取到用户新的rownum和积分。rownum就是排名,积分缓存至客户端用以下次登录访问。

如果客户端没有缓存积分,只能从计分表中直接查询id=用户id记录的rowNum
0 请登录后投票
   发表时间:2012-03-01  
panshunchang 写道
freish 写道
select count(1) from tableName where scores>(select scores from tableName where id=MyID)

这方法我看行

非常慢,你也可试试
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics