從海量日志數(shù)據(jù),提取出某日訪問百度次數(shù)最多的那個IP & java實現(xiàn)

問題分析:

  • Step 1. 首先將這天訪問百度的IP從log中讀取出來,并寫入到一個大文件中,這個過程可以通過程序生成大量隨機的IP來模擬;
  • Step 2. 以IPV4為例,IP是32位的(因為IP格式為a.b.c.d,其中a/b/c/d都是0-255的整數(shù)),因此可能有2^32個不同的IP,占據(jù)的空間為4 * 4G = 16GB,對于32位的操作系統(tǒng)而言無法完全加載到內(nèi)存中處理;

解決方案:

分而治之 + hash

  • 分而治之:既然所有的IP數(shù)量太大,那么可以將這些IP分在多個不同的小文件中,這樣每次處理的小文件所需要的內(nèi)存空間就小多了;
  • hash:對IP取hash值并取余數(shù)(比如1000,就有1000個小文件),這樣的話相同的IP可以分配在同一個小文件中;當(dāng)然,不同的IP也可能會有同樣的hash值;
  • 然后依次讀取每個小文件,對于單個小文件遍歷其中的IP,統(tǒng)計出每個小文件中出現(xiàn)次數(shù)最多的IP(放在Hashmap中,IP為key,次數(shù)為value);
  • 從Hashmap中找出value最大的key-value對;

java代碼:


public class IpUtil {

    private List<String> keyList = new LinkedList<String>();   //保存每個小文件中次數(shù)出現(xiàn)最多的IP
    private int ipMaxNum = 0;   //次數(shù)出現(xiàn)最多的值
    private int callNum = 0;

    /**
     * 模擬生成大量的IP(1億個)并批量寫入到同一個大文件中 
     */
    public void genIP2BigFile(File ipFile, long numberOfLine){
        BufferedWriter bw = null;
        FileWriter fw = null;
        long startTime = System.currentTimeMillis();
        try{
            fw = new FileWriter(ipFile,true);
            bw = new BufferedWriter(fw);

            SecureRandom random = new SecureRandom();
            for (int i = 0; i < numberOfLine; i++) {
                bw.write("10."+random.nextInt(255)+"."+random.nextInt(255)+"."+random.nextInt(255)+"\n");
                if((i+1) % 1000 == 0) {
                  // 每1000條批量寫入文件中,提高效率
                    bw.flush();
                }
            }
            bw.flush();
            long endTime = System.currentTimeMillis();
            System.err.println((endTime - startTime) / 1000);
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            try{
                if(fw != null){
                    fw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try{
                if(bw != null){
                    bw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * check這個大文件是否已經(jīng)存在
     */
    public void checkFileExists(File ipFile) {
        if (!ipFile.exists()) {
            try {
                ipFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            gernBigFile(ipFile, 100000000);
            System.out.println(">>>>>> Ip file generated.");
        } else {
            System.out.println(">>>>>> Ip file already existed.");
        }
    }



    /**
     * 對IP求取hash值并取余數(shù)(比如1000),將hash值相同的IP放入到同一個小文件中,得到1000個小文件
     */
    public void splitFile(File ipFile,int numberOfFile){
        Map<Integer,BufferedWriter> bwMap = new HashMap<Integer,BufferedWriter>();//保存每個文件的流對象
        Map<Integer,List<String>> dataMap = new HashMap<Integer,List<String>>();//分隔文件用
        BufferedReader br = null;
        FileReader fr = null;
        BufferedWriter bw = null;
        FileWriter fw = null;
        long startTime = System.currentTimeMillis();
        try{
            fr = new FileReader(ipFile);
            br = new BufferedReader(fr);
            String ipLine = br.readLine();
            //先創(chuàng)建文件及流對象方便使用
            for(int i=0;i<numberOfFile;i++){
                File file = new File("/Users/ycaha/Desktop/tmpIps/"+ i + ".log");
                bwMap.put(i, new BufferedWriter(new FileWriter(file,true)));
                dataMap.put(i, new LinkedList<String>());
            }
            while(ipLine != null){
                // 對每個ip求取hash
                int hashCode = ipLine.hashCode();
                hashCode = hashCode < 0 ? -hashCode : hashCode;
                // 對hash值取余數(shù),根據(jù)余數(shù)分配文件地址
                int fileNum = hashCode % numberOfFile;
                List<String> list = dataMap.get(fileNum);
                list.add(ipLine + "\n");
                if(list.size() % 1000 == 0){
                    BufferedWriter writer = bwMap.get(fileNum);
                    for(String line : list){
                        writer.write(line);
                    }
                    writer.flush();
                    list.clear();
                }
                ipLine = br.readLine();
            }
            for(int fn : bwMap.keySet()){
                List<String> list = dataMap.get(fn);
                BufferedWriter writer = bwMap.get(fn);
                for(String line : list){
                    writer.write(line);
                }
                list.clear();
                writer.flush();
                writer.close();
            }
            bwMap.clear();
            long endTime = System.currentTimeMillis();
            System.err.println((endTime - startTime) / 1000);
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            try{
                if(fr != null){
                    fr.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try{
                if(br != null){
                    br.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try{
                if(fw != null){
                    fw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try{
                if(bw != null){
                    bw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * 讀取單個小文件split,并獲取小文件中的出現(xiàn)次數(shù)最大的IP
     */
    public void read(File split) {
        Map<String,Integer> ipNumMap = new HashMap<String, Integer>();   //保存每個文件中的每個IP出現(xiàn)的次數(shù)
        //使用局部變量,不要使用全局變量,以免OOM 
        callNum ++;
        BufferedReader br = null;
        FileReader fr = null;
        long startTime = System.currentTimeMillis();
        try{
            fr = new FileReader(split);
            br = new BufferedReader(fr);
            String ipLine = br.readLine();
            while(ipLine != null) {
                ipLine = ipLine.trim();
                if (ipNumMap.containsKey(ipLine)) {
                    Integer count = ipNumMap.get(ipLine);
                    count ++;
                    ipNumMap.replace(ipLine, count);
                } else {
                    ipNumMap.put(ipLine, 1);
                }
                ipLine = br.readLine();
            }
            Set<String> keys = ipNumMap.keySet();
            for (String key: keys) {
                int value = ipNumMap.get(key);
                if (value > ipMaxNum) {
                    ipMaxNum = value;
                    keyList.add(key);
                }
            }

            long endTime = System.currentTimeMillis();
            totalTime += (endTime - startTime);
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            try{
                if(fr != null){
                    fr.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try{
                if(br != null){
                    br.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println(">>>>>> FileOrder: " + callNum + ", ipMaxNum: " + ipMaxNum + ", key: " + keyList.get(keyList.size()-1) );
    }

}


// 主類
public class TestMain {

    public static void main(String[] args) throws UnsupportedEncodingException {
        File ipFile = new File("/Users/ycaha/Desktop/ipAddr.log");
        IpUtil genIp = new IpUtil();
        genIp.checkFileExists(ipFile);
        long start = System.currentTimeMillis();
        genIp.splitFile(ipFile, 1000);
        File files = new File("/Users/ycaha/Desktop/tmpIps/");
        for (File split : files.listFiles()) {
            genIp.read(split);
        }
        long end = System.currentTimeMillis();
        System.out.println(">>>>>> The whole consumed time in seconds: " + (end - start) / 1000);
    }
}





結(jié)論:

    1. 生成的大文件ipAddr.log的大小為1.38G;
    1. 單個小文件的大小為2.1M,共有1000個;
    1. 出現(xiàn)次數(shù)最多的IP鍵值對為(10.52.99.80,52);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容