今天就写写之前的一道笔试题:每个用户访问,系统都会记录用户的IP到日志中,一个小时产生1G的日志文件,请分析日志文件获取当天访问次数前100的IP(大概是这样)。
由于IP是32位的,最多有个2^32个IP,也就是4G,所以不能完全加载到内存中处理;可以采用映射的方法,按照IP地址的Hash(IP)%1024值,把整个大文件映射为1024个小文件,再依次分析每个小文中出现频率最大的前100个IP及相应的频率,因为涉及到排序,所以使用到了TreeSet。
画图应该好理解一点:
具体代码如下:
package test.bigdata; import java.io.*; import java.security.SecureRandom; import java.util.*; public class LogAnalysis { //保存每个文件的流对象 public final MapbwMap = new HashMap (); //分隔文件用-存储相当数量之后再存入某个文件 public final Map > dataMap = new HashMap >(); //存储访问次数前100的IP public Set set = new TreeSet (); // 生成日志文件 public void creatLog(File log,long logNums) throws Exception{ FileWriter fw = new FileWriter(log,true); BufferedWriter bw = new BufferedWriter(fw); SecureRandom random = new SecureRandom(); for (int i = 0; i < logNums; i++) { bw.write("192."+random.nextInt(255)+"."+random.nextInt(255)+"."+random.nextInt(255)+"\n"); if((i+1) % 1000 == 0){ bw.flush(); } } bw.flush(); fw.close(); bw.close(); } // 分割日志文件 public void splitLog(File logflie,int fileNums) throws Exception{ FileReader fr = new FileReader(logflie); BufferedReader br =new BufferedReader(fr); String ip = br.readLine(); //先创建文件及流对象方便使用 for(int i=0;i ()); } while(ip != null){ int hashCode = ip.hashCode(); hashCode = hashCode < 0 ? -hashCode : hashCode; int fileNum = hashCode % fileNums; List list = dataMap.get(fileNum); list.add(ip + "\n"); if(list.size() % 1000 == 0){ BufferedWriter writer = bwMap.get(fileNum); for(String line : list){ writer.write(line); } writer.flush(); list.clear(); } ip = br.readLine(); } for(int fn : bwMap.keySet()){ List list = dataMap.get(fn); BufferedWriter writer = bwMap.get(fn); for(String line : list){ writer.write(line); } list.clear(); writer.flush(); writer.close(); } bwMap.clear(); fr.close(); br.close(); } //分析统计,找出次数前100的IP public void analysis(File logSplit) throws Exception{ FileReader fr = new FileReader(logSplit); BufferedReader br =new BufferedReader(fr); String ip = br.readLine(); //临时temp1存储当前文件所有IP Set temp1 = new TreeSet (); while(ip != null){ ip = ip.trim(); temp1.add(new IP(ip,1)); ip = br.readLine(); } br.close(); fr.close(); //提取temp1存储当前文件访问次数前100的IP并将其与set合并 int i=0; for (IP o : temp1) { set.add(o); if (i>100) { break; } i++; } //临时temp2截取已经合并的set中前100的IP Set temp2 = new TreeSet (); for (IP o : set) { temp2.add(o); if (i>100) { break; } i++; } //使得set一直存储目前已经分析访问次数前100的IP set = temp2; temp2=null; temp1=null; } }
IP对象类:
class IP implements Comparable{ public String ip; public int nums; public IP(){} public IP(String ip,int nums){ this.ip = ip; this.nums = nums; } @Override public int compareTo(IP o) { if (this.ip.equals(o.ip)) { o.nums=this.nums+o.nums; }else { if (this.nums > o.nums) { return -1; }else{ return 1; } } return 0; } }
测试代码:
package test.bigdata; import java.io.*; public class TestIP { public static void main(String[] args) throws Exception{ //生成模拟日志文件 LogAnalysis logAnalysis = new LogAnalysis(); File log = new File("D:\\javasoft\\TempTest\\BigData\\ip.txt"); log.createNewFile(); logAnalysis.creatLog(log, 10000);//节省时间 //分割日志文件 logAnalysis.splitLog(log, 1024); //分析文件 File logSplits = new File("D:\\javasoft\\TempTest\\BigData\\logSplit"); for (File logSplit : logSplits.listFiles()) { logAnalysis.analysis(logSplit); } for (IP o : logAnalysis.set) { System.out.println(o.ip+"---"+o.nums); } } }
有一篇博文说得好,扎实的基础跟开阔的视野才是企业所看重的。
关注时代的发展,学习能力强,愿意接受新事物才是企业所喜欢的,当然双向选择,一个创新,有挑战,能快,高,长大的企业也是雇员所喜欢的。加油~
Have a nice day~