同樣對於如此大的文件,單純用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
互聯網幾何級增長,未來不管是大文件處理還是可能存在的大數據都存在很大的需求空間.