php Shell大文件數據統計並且排序

版權聲明: https://blog.csdn.net/u012322399/article/details/80143316
諸多大互聯網公司的面試都會有這麼個問題,有個4G的文件,如何用只有1G內存的機器去計算文件中出現次數最多的數字(假設1行是1個數組,例如QQ號碼),如果這個文件只有4B或者幾十兆,那麼最簡單的辦法就是直接讀取這個文件後進行分析統計,但是這個是4G的文件,當然也可能是幾十G甚至幾百G的文件,這就不是直接讀取能解決了的.

同樣對於如此大的文件,單純用PHP做是肯定行不通的,我的思路是不管多大文件,首先要切割爲多個應用可以承受的小文件,然後批量或者依次分析統計小文件後再把總的結果彙總後統計出符合要求的最終結果,類似於比較流行的MapReduce模型,其核心思想就是“Map(映射)”和“Reduce(化簡)”,加上分佈式的文件處理,當然我能理解和使用到的只有Reduce後去處理.

假設有1個10億行的文件,每行一個6位-10位不等的QQ號碼,那麼我需要解決的就是計算在這10億個QQ號碼中,重複最多的前10個號碼,使用下面的PHP腳本生成這個文件,很可能這個隨機數中不會出現重複,但是我們假設這裏面會有重複的數字出現,代碼如下:

$fp = fopen('qq.txt','w+'); 
for( $i=0; $i<1000000000; $i++ ){ 
    $str = mt_rand(10000,9999999999)."n"; 
    fwrite($fp,$str); 

fclose($fp); 

生成文件的世界比較長,Linux下直接使用php-client運行PHP文件會比較節省時間,當然也可以使用其他方式生成文件,生成的文件大約11G,然後使用Linux Split切割文件,切割標準爲每100萬行數據1個文件,代碼如下:

split -l 1000000 -a 3 qq.txt qqfile  

qq.txt被分割爲名字是qqfileaaa到qqfilebml的1000個文件,每個文件11mb大小,這時再使用任何處理方法都會比較簡單了,我還是使用PHP進行分析統計,代碼如下:

$results = array(); 
foreach( glob('/tmp/qq/*') as $file ){ 
    $fp = fopen($file,'r'); 
    $arr = array(); 
    while( $qq = fgets($fp) ){ 
        $qq = trim($qq); 
        isset($arr[$qq]) ? $arr[$qq]++ : $arr[$qq]=1; 
    } 
    arsort($arr); 
    //以下處理方式存在問題 
    do{ 
        $i=0; 
        foreach( $arr as $qq=>$times ){ 
            if( $i > 10 ){ 
                isset($results[$qq]) ? $results[$qq]+=$times : $results[$qq]=$times; 
                $i++; 
            } else { 
                break; 
            } 
        } 
    } while(false); 
    fclose($fp);  

if( $results ){ 
    arsort($results); 
    do{ 
        $i=0; 
        foreach( $results as $qq=>$times ){ 
            if( $i > 10 ){ 
                echo $qq . "t" . $times . "n"; 
                $i++; 
            } else { 
                break; 
            } 
        } 
    } while(false); 

這樣每個樣本取前10個,最後放到一起分析統計,不排除有個數在每個樣本中都排名第11位但是總數絕對在前10的可能性,所以後面統計計算算法還需要改進.

也許有人說使用Linux中的awk和sort命令可以完成排序,但是我試了下如果是小文件還可以實現,但是11G的文件,不管是內存還是時間都無法承受,下面是我改的1個awk+sort的腳本,或許是寫法有問題,求牛人指導,代碼如下:

awk -F '\@' '{name[$1]++ } END {for (count in name) print name[count],count}' qq.txt |sort -n > 123.txt 

互聯網幾何級增長,未來不管是大文件處理還是可能存在的大數據都存在很大的需求空間.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章