把访问P站次数最多的那个人才给我找出来?
如果我掌握了P站的所有访问日志数据(海量),我想找出某一天访问次数最多的那个IP,并看看到底是那个国家的小哥精力如此旺盛???
对于这种问题,说到底,就是一个“分与合”的思想。
我们需要从访问P站日志中,把具体某一天的所有IP取出来,再逐个写入到一个大文件中。值得一提的是,IP是32位的,那么就有2^32个IP,就算扣除特殊IP,在重复量小的情况下,一般来说,不能直接把这些数据放入到内存里面。
这里的话,我们需要采用hash映射的方法,比如取模1000,把这个大文件分割成1000个小文件,再去小文件中找出出现频率最大的IP,并记录其出现频次;最后,再从这1000个IP中找到出现频次最大的IP,这样便把一个看似不能解决的问题就给解决了。
具体操作:
-
对IP地址进行hash(IP)%1000求值,再把海量IP日志分别存储到1024个小文件中;
-
分别对每一个小文件,构建一个{k:IP ,v:频次}的map,并记录下当前小文件频次最多的IP;
-
对得到的这个1000个IP,进行常规排序,便能得到最大的IP
1、构造数据
生成1亿个IP地址,写入文件:
public void genIP(String fileName) throws Exception { PrintWriter out = new PrintWriter(fileName); String s; Random r = new Random(); for (int i = 0; i < 100000000; i++) { s = "159.227."; s += r.nextInt(256) + "." + r.nextInt(256); out.println(s); } if (out != null) out.close(); }
2、分割文件
把这个大文件分割成1000个小文件,代码如下:
public void splitMiniFile(String fileName) throws Exception { BufferedReader reader = new BufferedReader(new FileReader(fileName)); PrintWriter[] out = new PrintWriter[1000]; for (int i = 0; i < 1000; i++) { out[i] = new PrintWriter(fileName + i); } String ip = null; while ((ip = reader.readLine()) != null) { ip = reader.readLine(); int fileNum = ip.hashCode() % 1000; fileNum = (fileNum >= 0 ? fileNum : fileNum + 1000); out[fileNum].println(ip); } for (int i = 0; i < 1000; i++) { out[i].close(); } reader.close(); }
3、统计IP
对每个小文件里面的ip进行统计,并获取最大频次的ip,代码如下:
public Map.Entry<String, Integer> statisIps(String fileName) throws Exception { BufferedReader reader = new BufferedReader(new FileReader(fileName)); HashMap<String, Integer> map = new HashMap<String, Integer>(); String ip = null; while ((ip = reader.readLine()) != null) { if (map.containsKey(ip)) { map.put(ip, map.get(ip) + 1); } else map.put(ip, 1); } Map.Entry<String, Integer> maxEntry = null; for (Map.Entry<String, Integer> entry : map.entrySet()) { if (maxEntry == null || entry.getValue() > maxEntry.getValue()) { maxEntry = entry; } } reader.close(); return maxEntry; }
4、IP排序
把通过后的最大IP,进行排序。代码如下:
public static void main(String[] args) throws Exception { Test t = new Test(); String FileName = "d://100000000.txt"; t.genIP(FileName); t.splitMiniFile(FileName); List<Map.Entry<String, Integer>> entryList = new ArrayList<Map.Entry<String, Integer>>(); for (int i = 0; i < 1000; i++) { entryList.add(t.statisIps(FileName + i)); } Map.Entry<String, Integer> maxEntry = entryList.get(0); for (int j = 1; j < 1000; j++) { if (entryList.get(j).getValue() > maxEntry.getValue()) { maxEntry = entryList.get(j); } } System.out.println(maxEntry.getKey()); System.out.println(maxEntry.getValue()); }