『數據結構』海量數據處理

本篇博客我們通過幾個經典的問題來看一下計算機中處理海量數據的常用方法。

哈希切分


問題:給定一個超過100G大小的日誌文件,文件中保存着IP地址,設計算法找出出現次數最多的IP地址?如何找到出現次數topK的IP?如何直接用Linux命令實現

  • 找到出現次數最多或者前K多的IP地址並不困難,直接使用優先級隊列就可以解決該問題。這道題真正困難的是100G大小的日誌文件,因爲我們常用的計算機並沒有這麼大的內存。可能你會說我們找一個有這麼大內存的機器來處理不就好了,這樣也不是不可以。但是如果我們的日誌文件大小爲1000G或者10000G呢,或者更大,因爲磁盤的空間肯定是遠大於內存空間大小的。所以我們需要別的辦法來處理這個問題。
  • 我們使用切分的思想,將一個大文件切分成很多個小文件,這樣這些小文件就可以分別加載到內存中進行統計。但是這裏有一個問題,就是我們必須保證相同的IP地址能夠被分到同一個小文件中,這樣正確的統計出每個IP的出現次數,所以我們使用哈希切分,哈希切分,通過哈希函數來計算該IP地址應該被切分到哪個小文件中,這樣就能保證相同的IP地址被切分到同一個文件中。
  • 通過前面的哈希切分,我們就可以得到很多個小文件,我們將每一個小文件加載到內存中,找出這個小文件中出現次數最多的IP地址,重複這個過程,我們就可以得到每一個小文件中出現次數最多的IP地址
  • 上一步我們可以得到每個小文件中出現次數最多的IP地址,我們就可以將這些IP地址通過一個優先級隊列來找到出現次數最多或者前K多的IP地址

上述過程的示意圖如下
在這裏插入圖片描述

  • 另外,如果我們使用Linux來操作的話,可以使用grep命令來實現上述功能
grep -i -o -E "([0-9]{1,3}\.){3}[0-9]{1,3}" logfile.txt | sort -n | uniq -c | sort -n -r | head -K

位圖應用


問題一:給40億個不重複的無符號整數沒排過序。給一個無符號整數,如何快速判斷一個數是否在這40億個數中

  • 這種問題就是判斷一個數是否在一個集合中,我們通常的做法就是將這些數據存到一個Set中,然後就可以快速判斷一個數是否在這個集合中。但是當前的場景明顯不行,因爲數據量太大了,大到內存中存不下。我們有40億個無符號整數一個無符號整數是4個字節,所以40億個無符號整數就是160億個字節大約就是16G的內存才能存的下,很明顯,使用Set明顯是不行的。
  • 因此我們可以使用位圖的方式來表示。數據是否在給定的整型數據中,結果是在或者不在,剛好是兩種狀態,那麼可以使用一個二進制比特位來代表數據是否存在的信息,如果二進制比特位爲1,代表存在,爲0代表不存在
  • 因此保存40億個不重複的無符號整數的狀態只需要40億個bit位的空間,即5億個字節大約500M的內存空間即可保存。因此我們將這40億個不重複的整數的狀態保存到數組中
  • 我們判斷一個數是否在這40億個整數中,只需要查看數組中該下標位置中的內容是0還是1,如果爲0表示不存在,如果爲1表示存在

位圖的大致結構如下
在這裏插入圖片描述

問題二:給定100億個整數,設計算法找到只出現一次的整數

  • 該問題和上個問題差不多,也是用位圖的思路來解決,上個問題每個數只有兩個狀態,即存在和不存在,所以使用一個bit位來表示。而本問題每個數存在三個狀態,即:不存在出現一次出現多次。所以我們需要使用兩個bit位來表示一個數的狀態,即:00表示不存在01表示出現一次10表示出現多次。按照這種方法,每個整數需要2個bit位,所以一共需要200億個bit位,即25億個字節大約2.5G的內存,這個內存對我們來說還是佔用太大。
  • 因爲直接使用位圖的方式需要2.5G的內存,還是佔用太大,所以我們可以藉助哈希切分的思想來解決這個問題。我們通過一個哈希函數將一個大文件切分成多個小文件,然後分別對每個小文件使用位圖的思想來解決該問題。找到每個小文件中出現次數爲1的數字,彙總起來就是最終的結果。

上述過程的示意圖如下
在這裏插入圖片描述

問題三:給兩個文件分別有100億個整數,我們只有1G內存,如何找到兩個文件交集

  • 如果我們直接使用位圖的方式,每個數據有兩個狀態,即存在和不存在,因此可以使用一個bit位來表示,0表示不存在,1表示存在。因此我們需要100億個bit位,大約1.25G的內存,顯然不符合題意。
  • 因此我們使用哈希切分的思想對兩個文件使用相同的哈希函數進行切分。然後分別對對應的小文件使用位圖的方式求交集,最後將所有的結果進行彙總就是最終的結果
  • 對兩個小文件使用位圖求交集,首先根據一個文件來構建位圖,然後從另一個文件中讀數據,如果這個數據在位圖中存在,說明是這個數在交集中,重複這個過程即可的到兩個小文件的交集。

上述過程的示意圖如下
在這裏插入圖片描述

問題四:一個文件有100億個int1G內存,設計算法找到出現次數不超過2次的所有整數

  • 該問題如果直接使用位圖的話,一個數有四種狀態:不存在,出現一次,出現兩次,出現多次。所以需要使用兩個bit位來表示,即需要200億個bit,大約2.5G內存,顯然是不行的。
  • 所以這個問題我們還是需要藉助哈希切分的思想來解決,我們使用哈希函數將一個文件切成多個小文件,然後對每個小文件使用位圖的方式來找到出現次數不超過兩次的整數
  • 對於每個小文件,每個數據使用兩個bit位來表示。即:00表示不存在,01表示出現1次,10表示出現兩次,11表示出現次數超過兩次。

上述過程的示意圖大致如下
在這裏插入圖片描述

布隆過濾器


什麼是布隆過濾器?


本質上布隆過濾器是一種數據結構,比較巧妙的概率型數據結構,特點是高效的插入和查詢,可以用來告訴你“某樣東西一定不存在或者可能存在”
布隆過濾器使用位圖的方式實現,相比於傳統的List、Set、Map等數據結構,它更高效、佔用空間更少,但是缺點是其返回的結果是概率性的,而不是確切的

布隆過濾器數據結構


  • 布隆過濾器大概長這樣
    在這裏插入圖片描述
  • 如果我們要映射一個值到布隆過濾器中,我們需要使用多個不同的哈希函數生成多個哈希值,並對每個生成的哈希值指向的bit位置爲1,例如針對值“Alibaba”和三個不同的哈希函數分別生成了三個哈希值1,4,7,則上圖轉變爲:
    在這裏插入圖片描述
  • 此時我們再插入一個值“Tencent”,如何哈希函數返回3,4,8的話,圖轉變成如下:
    在這裏插入圖片描述
  • 值得注意的是,下標爲4的bit位由於兩個值的哈希函數都返回了這個bit位,因此它被覆蓋了。現在如果我們想要查詢“ByteDance”這個值是否存在,哈希函數反悔了1,5,8三個值,結果我們發現5這個bit位上爲0,說明沒有任何一個值映射到這個bit位上,因此我們可以很確定的說“ByteDance”這個值不存在
    但是當我們查詢“Alibaba”這個值是否存在的話,那麼哈希函數必然會返回1,4,7,然後我們檢查發現這三個bit位上的值均爲1,那麼我們可以說“Alibaba”存在了嗎?答案是不可以,只能說“Alibaba”這個值可能存在。答案很簡單,因爲隨着增加的值越來越多,被置爲1的bit位也會越來越多,這樣某個值“ByteDance”即使沒有被存儲過,但是萬一哈希函數返回的三個bit位都被其他值置爲了1,那麼程序還是會判斷“ByteDance”這個值存在

布隆過濾器支持刪除嗎?


傳統的布隆過濾器不支持刪除,因爲可能有多個值對某一個bit位置1,因此不支持刪除操作,如果想要支持刪除操作,就不能使用位圖的結構,將一個bit位調整成一個整數,用於統計被置1的次數,類似於一個計數器,刪除時,對對應的位進行減減操作。但是這樣空間就會消耗很大。

如何選擇哈希函數個數和布隆過濾器長度


  • 很顯然,過小的布隆過濾器很快所有的bit位均爲1,那麼查詢任何值都會“可能存在”,起不到過濾的目的了。布隆過濾器的長度會直接影響誤報率,布隆過濾器越長其誤報率越小
  • 另外,哈希函數的個數也需要權衡,個數越多則布隆過濾器bit位置1的速度越快,且布隆過濾器的效率越低;但是如果太少的話,誤報率會變高
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章