N道大数据海量信息处理 算法面试集锦

Top K问题想必面试过的盆友都遇到过,比如亿万级数据如何查找前十的请求/IP地址等的Top K问题,还有类似亿万级数据如何在数据库中分页

今天在这里总结下,直接上干货不多BB,希望大家理解后可以在面试中有更好的表现

1 Top K

题目:大数据量请求,找出请求次数最多的IP地址

思路:分治+Hash

详解:

1)按照每天为单位处理,IP地址有2^32=4G钟取值,所以肯定不能把一天的数据量全部读在内存中,我们假设这里的数据文件为4G的情况(根据实际业务场景变更数据大小即可,算法是不变的)

2)使用分治思想,把数据分为1024个小文件,IP地址经过Hash函数处理取模%1024,把大文件分成1024个小文件,这样每个文件只有4MB大小。

3)哈希法(扫描两遍,时间复杂度为O(N)),先对每个小文件建立HashTable(我用的是Python,所以建立字典,如果想字典有序可以使用collctions中的Orderdict数据结构),Key为IP地址,Value为出现的次数(初始为0),扫描一遍先建出来HashTable,然后再扫一遍记录每个IP地址出现的次数。

4)再根据每个文件的HashTable中的Ip地址进行排序,排序指标为出现的次数也就是Value。快排和堆排都可以,个人比较喜欢回答堆排序的思想。如果结果是Top10的情况建立一个大小为10的小根堆,堆顶就是最小的IP地址对应的出现次数,建堆的时间复杂度为O(logN),然后遍历文件中的IP地址的Value。如果大于堆顶(堆顶为最小的出现次数),那么堆顶与当前数值互换,进行堆调整,调整的时间复杂度为O(logN)。最后的小根堆,所得及所求。

2 海量字符串最高的频率查找(Top K变种)

题目:一个G的文件,每一行是一个词,词大小不超过16k,内存限制为1M,返回频率最高的100个词

详解: 1)顺序读取文件中的每行,Python中可以使用with open方法,with open方法是按照上下文读取文件,并自动关闭文件,由于Python中的读取的流对象是一个可迭代对象所以可以使用For循环按照行读取,放心再大的文件都不会溢出。

2)把1G文件分成5000份这样每份大概200K,然后进行Hash取模,把对应行的内容存在对应的文件中,如果其中文件超过1M(哈希冲突导致的),可以把该文件继续按照之前的方法分解为10份或者几份直到满足要求为止。

3)使用Tire树做词频统计(使用HashMap也可以但是前缀树更适合做词频统计),在建立Tire树时多加一个数据项,表示查询的次数,那么就可以表示以某个单词的查询次数。

4)对每个文件建立最小堆,堆大小为100,词对应的频率存入文件,这样又得到至少五千个文件,然后对文件中的词频进行归并排序

3 10个文件每个文件1G,放着用户的QUERY,按照QUERY频率排序

详解: 典型的Top K问题

Plan A:

1)顺序读取10个文件,存入10个文件(哈希取模%10),理论上哈希函数会均分在10个文件中,每个文件大概为1G大小。

2)电脑内存为2G,建立HashTable,K-V键值对为QUERY-QUERY_TIMES,扫描一遍文件count所有QUERY的出现次数。

3)最后根据Value:QUERY_TIMES进行排序,单个文件使用随机快排 ,堆排序常数项时间复杂度大于快排,并且在工程中寻址时间也长,所以导致理论上大数据量堆排序快于快排,但是实际效果还是不如快排,排序好的数据存入文件,这样得到了10个独立有序的文件

4)对10个独立有序的文件进行归并排序

Plan B:

1)一般来说QUERY只是重复的次数多,所以如果考虑一次性读入内存中。

2)扫描一遍内存中的QUERY,然后建立Tire树或者HashMap。Tire树扫描一遍就可以获得词频数据,而HashMap要扫两边,虽然都是O(N),但是HashMap是2N,Tire是N,然后存为文件。

3)直接使用随即快排

4 两个文件各存50亿个url,每个url64个字节,内存限制4G,找出A,B共同的url

1)单个文件读取肯定超出内存大小,所以还是采取之前的分治思想,大化小,对A/B分别取模分成1000个文件存储。50亿url算下来每个文件300M。

2)对小文件求公共url的时候可以使用set去重。或者使用并查集的IsSameSet判断,缺点是建立十个集合。A文件Set建立后另外一个文件的内容遍历跟Set中内容比对,如果相等则记录

另:可以考虑使用BloomFilter,后面的黑名单问题中会详解BloomFilter的

5 N亿个数找出一个只出现一次的数

**详解:**思路跟之前一样,首先分成小文件,然后建立HashTable/tire树进行统计,差别还是Tire树只需要扫一遍,HashTable需要扫两遍

**另外:**可以使用BitMap,每个数分配两Bit,00不存在,01出现一次,10出现多次,11没意义。需要内存2^32*8bit=1G,建立完毕扫描数据把对应位置的比特位描成00/01/10/11,最后查找01

6 有一百多万个黑名单,如何判断某个用户是否被拉黑

BloomFilter最佳应用场景

BloomFilter介绍: 布隆过滤器属于BitMap的变种。HashMap如果长度有限,数据量很大的情况下,采用拉链法解决哈希冲突会导致链过长而查询性能受到影响,采用地址开方法(Python中字典使用的解决Hash冲突的方法),那么还是会导致空间不足。所以想节省空间Bitmap就诞生了。也就是说BloomFilter优点就是省空间,但是布隆过滤器的缺点就是会有失误率。这个失误率是指本来A不属于黑名单,但是被误判进了黑名单,宁可杀错,绝不放过的一种失误。

原理: 1.某个Key需要加入集合中,需要K个哈希函数计算出K个hash值,并查询对应的比特位,如果所有的比特位对应的值都是1,那么就认为这个Key是在这个集合中的,相比HashMap不需要存储Key节省空间

结构: 集合中每一个位置为比特,非0即1,一个Int型整数,4个字节,32个比特,即一个1000的集合,可以表示32000个比特位,数组的InteIndex表示数组中的位置,BitIndex为数组中某一位的比特。根据计算出来的hash值来描黑,最后由该位置的32Bit数或上左移的BitIndex位的1实现

JavaCode

应用到案例: 黑名单问题,url经过k个hash函数进行处理后模个m,对应0~m-1上的一个,算出位置描黑,有可能不同url打在同一位置,重复描黑。如果k个位置都是黑的那么,这个url就在黑名单里

失误率控制

通过控制m长度和k来控制失误率

确定数组长度M M=-(n*lnp)/(ln)^2,n是样本量,p预期失误率,算出来是bit,对应的实际字节数应该除以8

附加题

题目:千万级数据分页如何实现?

思考:海量数据分页已经无法使用数据库内的分页方法LIMIT,因为这样会严重影响性能。常见的解决方法有两种:1.将查询数据读入内存中,然后在内存中分页,限制每次的查询量 2.采用存储过程分页,不同数据库实现方式不同,并且性能达不到预期

优解:

1)在待查询的表中添加一个自增长字段,Query_ID,主键自增长。按照大小顺序逆序排列数据。

语句: SELECT QUERY_ID FORM TABLE WHERE XXX ORDER BY DESC

因为只是查找QUERY_ID字段所以,即使数据量很大查询速度也是很快的,然后将查询到的QUERY_ID保存应用服务器的一个数组中

2)用户在客户端进行翻页的时候,客户端将查询的页号作为参数传递给应用服务器。服务器通过页号和QUERY_ID数组计算出待查询的最大值和最小值,然后查询。

计算QUERY_ID最大最小值: 定义page:待查询的页号;pagesize为每页的大小;query_ids为之前生成的数组

优点:

1)所有数据库都适用

2)CPU和内存占用较低

3)查询速度较快

物理优化:

1)数据分区

2)增加内存

3)数据分表

还可以分成两个库,一个做查询,一个做事务

....三天终于写完了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值