system design之大数据

前言

为了应对微软的面试,然后看了其他老哥整理的博客,自己也整理一遍,当做是理解,侵删。

有一个无限的整数数据流,如何从中随机地抽取k个整数出来?

这个问题其实还是有点数学的意思在里面的。我们先考虑当k=1的时候,那么如果来一个,咱们就抽这个。如果来俩,那么就有50%的概率,要么换,要么不换。如果又来了一个呢?那也是一样的,先确定换还是不换,换的概率是三分之一。
到这里你有啥问题么?其实很好理解的,咱们做到了对于进来的每一个人,都是每次有n分之一的机会被选中!ohhhhhhhhh!
下面直面K吧。当我需要随机抽取K个数据的时候,那么其实就是类似的道理,先攒够了K个。然后呢,当下一个数据来的时候,依旧是有K/(K+1)的概率选择换掉前面k个数据里面的一个,那么换掉谁呢?也很简单啊,随机呗。这样是不是说,对于新来的第K+1而言,他上场被pick的概率是K/(K+1),而前K个里被pick上场的概率是1/(K+1) + K/(K+1) * ( (K-1)/K ) = K/(K+1)!
ohhhhhhh!
代码实现的话就不写了,就写个思路算了。

如何计算数据流中不同元素的个数?

是不是感觉这种题目都很刁钻?这道题目应该还是很好理解的,我反手就是一个unordered_map,直接pass?当然不可以。如果数据量很大的话,那岂不是原地爆炸?
好的,那你肯定会问面试官:数据量有多少呢?面试官可能会告诉你,有10亿个int数据,然后最多出现的重复次数是10000次,你咋整?
如果咱们搞得宽泛一点,不是那么严格的查询的话,那么可以用bitmap。
不过呢,不是用一个bit来表示一个数据,而是用16bit来表示,因为可能会重复2的16次方也就是65535次(咱们把哈希冲突的也算进去),这样算下来,一共需要的内存大小是10亿*2Byte也就是2G,还算是可以接受的,美滋滋。
不过还是有点不好的地方,那就是,哈希冲突很难受的,你统计出来的数据只会相等或者偏高。
那有啥好的方法可以缓解一下这种哈希冲突呢?这个时候你的脑子里想到了那些解决哈希冲突的方法,我只能说,还是看下面的解法吧。
Count-Min Sketch
其实意思很简单,咱准备比如16个哈希函数,然后把输入进来的数据分别和这16个哈希函数进行哈希,最后对bitmap进行取模然后映射。
如果某次别人问你某个数据出现的次数,你就直接16次哈希,然后取出bitmap中这16个地方的数据,最小值就是你要的次数了。
降低哈希冲突,漂亮(就是多浪费了空间)

寻找数据流中出现最多次数的k个元素

首先一个很容易想到的方法是哈希+内存堆,对吧。很显然,当数据量过大的时候,这就很爆炸,对吧。
咱们思考一些其他的方法。
如果人家就是要那种严谨的结果,咱们可以搞分布式计算,具体咋分布式呢?比如咱们准备8台机器,然后每台机器只处理hash(inputData)%8= 0,1,2,3等等这些,这不就分成8分了么。然后每一份都维护一个最小堆K,最后将这些最小堆合并一下就完了,多简单。
如果你想随便粗略的算一下,那么咱们刚刚讲过的count-min sketch+内存堆,就非常棒了。这个就不展开了,非常简单。

给定一个无限的整数数据流,如何查询在某个范围内的元素出现的总次数?

看清楚啊朋友,这是范围查询。范围指的是,输入数据的某个范围。
既然是范围,那么无非是类似输入数据为3,4,5,6,7…10这样,那么咱们分别查询这些数据的次数,然后相加不就完了么。
于是上面那道题的方法似乎可以继续拿来使用。可以咱们仔细思考一下,上面那skech的方法统计的结果都是偏大的,对吧,那么你要是将这么多偏大的误差累加起来,那不就爆炸了么。
咋搞呢?网上这位老哥依旧是使用sketch,只不过它搞了很多分辨率不同的sketch,这样一来,如果要查询的哈希有连续,就可以直接用分辨率低的啦(误差肯定就更小啦),直接上伪代码:

  def insert(x):
      for i in range(1, d+1):
          M1[i][h[i](x)] += 1
          M2[i][h[i](x)/2] += 1
          M3[i][h[i](x)/4] += 1
          M4[i][h[i](x)/8] += 1
          # ...

一定要注意,咱们要的是输入数据的范围,不是哈希后的范围!!!

更正

sketch结构并不是我描述的那样好吧,它并不是将多个哈希后的结果放在一个线性表中,而是每个哈希函数都对应着一个哈希表。继续。

猜你喜欢

转载自blog.csdn.net/weixin_44039270/article/details/106973710
今日推荐