大文字檔案(接近7GB): 統計頻數,Top K問題求解
阿新 • • 發佈:2019-01-30
自己實踐如下
1 產生了一個1G行,每行一個[0,100000]區間的整數
2 top n 求解:
2.1 大檔案分成小檔案
把這個7G左右的大檔案,按照讀入數字的hashcode值分成1024個小檔案(每個檔案平均最大就7M左右)
2.2 小檔案統計
對每個小檔案,可以用堆,hash,內部排序等等方法進行處理;
本例使用Java的HashMap
2.3 小檔案的統計結果 再做一次統計 求出出現頻數最高的那個數
結果:
java原始碼
import java.io.*;
import java.util.*;
class IP implements Serializable {
private static final long serialVersionUID = -8903000680469719698L;
private String ip = "";
private int count;
public IP(String ip2, Integer integer) {
this.ip = ip2;
this.count = integer;
}
public int getCount() {
return count;
}
public String getIp() {
return ip;
}
public void setCount(int count) {
this.count = count;
}
public void setIp(String ip) {
this.ip = ip;
}
}
public class Data {
static String fileLoc = "D:\\hadoop\\numsout\\nums.txt";
/**
* 將打檔案hash成1024個小檔案
*
* @throws FileNotFoundException
* @throws IOException
*/
private static void hashToSmallFiles() throws FileNotFoundException, IOException {
BufferedReader br = new BufferedReader(new FileReader(fileLoc));
String ip = "";
HashMap<String, FileWriter> fileWriters = new HashMap<String, FileWriter>();
while ((ip = br.readLine()) != null) {
int tmp = Math.abs(ip.hashCode() % 1024);
String fileName = fileLoc + tmp + ".txt";
FileWriter fw = null;
if (fileWriters.containsKey(fileName)) {
fw = fileWriters.get(fileName);
} else {
fw = new FileWriter(fileName, true);
fileWriters.put(fileName, fw);
}
fw.write(ip + "\n");
}
br.close();
for (FileWriter ff : fileWriters.values()) {
ff.close();
}
}
/**
* 利用HashMap<> 統計每個小檔案頻數最高的ip;
* @return 所有小檔案的結果 組成List 返回
* @throws FileNotFoundException
* @throws IOException
*/
private static List<IP> countEverySmallFile() throws FileNotFoundException, IOException {
List<IP> list = new ArrayList<IP>();
for (int i = 0; i < 1024; i++) {
File file = new File(fileLoc + i + ".txt");
if (file.exists()) {
long startTime = System.currentTimeMillis();
BufferedReader br1 = new BufferedReader(new FileReader(file));
String ip1 = "";
HashMap<String, Integer> hm = new HashMap<String, Integer>();
while ((ip1 = br1.readLine()) != null) {
if (!hm.containsKey(ip1)) {
hm.put(ip1, 1);
} else {
hm.put(ip1, hm.get(ip1) + 1);
}
}
IP[] ips = new IP[hm.size()];
int index = 0;
for (String temp : hm.keySet()) {
ips[index] = new IP(temp, hm.get(temp));
index++;
}
int max = 0;
for (int j = 1; j < ips.length; j++) {
if (ips[j].getCount() > ips[max].getCount()) {
max = j;
}
}
list.add(ips[max]);
long endTime = System.currentTimeMillis();
System.out.println("已經統計檔案:" + fileLoc + i + ".txt,用時:" + (endTime - startTime) + " 毫秒");
}
}
return list;
}
/**
* 從每個檔案出現頻率最高ip中,計算出所有檔案中出現頻率最高ip。
*
* @param list
*/
private static IP calculateResult(List<IP> list) {
IP[] ips = new IP[list.size()];
ips = list.toArray(ips);
int max = 0;
for (int j = 1; j < ips.length; j++) {
if (ips[j].getCount() > ips[max].getCount()) {
max = j;
}
}
return ips[max];
}
public static void findIp() throws IOException, ClassNotFoundException {
long start = System.currentTimeMillis();
//hashToSmallFiles();
long end1 = System.currentTimeMillis();
System.out.println("將大檔案對映成小檔案,用時:" + (end1 - start) + "毫秒");
System.out.println("將大檔案對映成小檔案,約:" + (end1 - start) / 60000 + "分鐘");
// 測試時大約28分鐘
System.out.println("對映到小檔案完成,開始統計每個小檔案中出現頻率最高的ip");
long start1 = System.currentTimeMillis();
List<IP> list = countEverySmallFile();
long end2 = System.currentTimeMillis();
System.out.println("統計所有檔案共用時:" + (end2 - start1) + " 毫秒");
System.out.println("統計所有檔案共用時,約:" + (end2 - start1) / 60000 + "分鐘");
// 測試時大約13分鐘
System.out.println("統計完成,開始計算所有ip中出現頻率最高的ip");
IP ip = calculateResult(list);
System.out.println("訪問次數最多的ip是:" + ip.getIp() + ":" + ip.getCount());
long end = System.currentTimeMillis();
System.out.println("公用時:" + (end - start) + "毫秒");
}
// 產生大檔案
public static void getBigFile() {
try
{
File file = new File(fileLoc);
if(!file.exists())
{ //如果不存在則建立
file.createNewFile();
System.out.println("檔案建立完成,開始寫入");
}
FileWriter fw = new FileWriter(file); //建立檔案寫入
BufferedWriter bw = new BufferedWriter(fw);
//產生隨機資料,寫入檔案
Random random = new Random();
for(int i=0;i<1024*1024*1024;i++)
{
int randint = (int)Math.floor((random.nextDouble()*100000.0));//產生【0,10000】之間隨機數
bw.write(String.valueOf(randint)); //寫入一個隨機數
bw.newLine(); //新的一行
}
bw.close();
fw.close();
System.out.println("檔案寫入完成");
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//getBigFile();
// 產生檔案:有1024*1024*1024行(1G行),每一行一個數字
findIp();
System.out.println("Finished");
}
}