一:三个面试题
面试题一:有一个非常大的文件,一台机器处理不了,存储的是ip每行一个,统计一下出现次数最多的那个ip。
如果是小文件
- 1)创建io流对这个文件进行读取,将读取的内容放在map集合中(ip,次数)
- 2)循环遍历map集合,取出value最大的值
大文件情况
map集合,list集合,数组,set集合——-都是在内存进行操作的,文件过大会造成内存溢出,根本无法处理。
一台机器原始性能有限,根据摩尔定律:每18-24个月硬件性能提升一倍,但是数据的增加速度远远大于硬件的提升速度。纵向扩展性能不是最终的解决方案。
我们考虑横向扩展,使用多台机器,分而治之。将原来的大文件分成很多个小文件,这很多个小文件分别在不同的机器上计算。
最终的解决方案:
- 1)将文件切分
- 2)每个机器进行统计自己机器上的数据的ip出现的次数
- 3)聚合统计 出现次数最多的ip
面试题二:有两个超大文件,大文件中存储的都是url,每行一个,找出两个文件中相同的url。
如果是小文件:
- 1)创建两个流
- 2)创建两个集合,使用set可以单值去重
- 3)读取文件,放在set中
- 4)循环遍历一个set,在另一个set中查询是否存在set.contains()/set.add() 如果存在就是相同的,把相同的取出。
大文件:
- 首先遍历文件第一个文件,对每个url求取hash(url),再%分区数量,然后根据所取得的值将url分别存储到各个分区,变成小文件。
- 遍历第二个文件,采取和第一个文件相同的方式将url分别存储到各个分区中,变成小文件。第二个文件的分区数量应该是第一个文件分区数量的倍数或者相同。因为相似url的哈希值会是相近的,所以就变成了小分区之间一一映射查找。所以现在问题转换成了:找出小文件中每一对相同的url(不是一一映射的小文件不可能有相同的url)。
面试题三:一个大文件存储url,每行一个,用户给定一个url,怎么快速检索这个url是否存在.
如果是小文件
用流读取,放入set,再用set.contains(url)方法就能找到是否存在。
大文件:
我们知道数组是由下标的,所有查询效率很高,但是增删就很慢,我们这里需要查询,所以可以利用数组来做。
- 首先有一个一个空的m位的位数组,所有位的值都为0。我们将url进行哈希:hash(url),得到每一个url的哈希code值,哈希code值,记做:index=哈希值%(分区数n)。则如果数组的index有值,该位就变为1。即用数组下标去记录(url哈希)以后并且(%分区)以后的数值,用0,1分别记录该值是否存在。
- 但是有一个问题:哈希的冲突本来就大,(%分区)以后冲突就更大,这样得出来的结果是不准确的。此时,我们可以设计k个哈希函数,这样一个url就有k个hash值,就有k个%分区以后的位值。只有这k个位置的值都为1,我们才判定这个url是存在的。
- 又有一个问题:哈希函数个数k为多少才是合理的呢?其实以上就是布隆过滤器的思想,根据公式:当 k=0.7 (实际长度/数组长度) 时,误判率最低。例如我们有1000000条数据,要放在10000长度的数组中,需要0.7*(1000000/10000)=70个哈希函数误判率最低