笔试题:海量日志中提取访问次数前100的IP

大数据时代是一个信息量爆炸的时代,利用数据分析将会产生不可估量的价值,基金,证券,电商以及现在越来越火的O2O。当然作为一个热点,企业的笔试与面试中当然少不了关于大数据的问题。

今天就写写之前的一道笔试题:每个用户访问,系统都会记录用户的IP到日志中,一个小时产生1G的日志文件,请分析日志文件获取当天访问次数前100的IP(大概是这样)。

由于IP是32位的,最多有个2^32个IP,也就是4G,所以不能完全加载到内存中处理;可以采用映射的方法,按照IP地址的Hash(IP)%1024值,把整个大文件映射为1024个小文件,再依次分析每个小文中出现频率最大的前100个IP及相应的频率,因为涉及到排序,所以使用到了TreeSet。
画图应该好理解一点:
笔试题:海量日志中提取访问次数前100的IP_第1张图片
具体代码如下:
package test.bigdata;
import java.io.*;
import java.security.SecureRandom;
import java.util.*;
public class LogAnalysis {
	//保存每个文件的流对象
	public final Map<Integer,BufferedWriter> bwMap = new HashMap<Integer,BufferedWriter>();
	//分隔文件用-存储相当数量之后再存入某个文件
	public final Map<Integer,List<String>> dataMap = new HashMap<Integer,List<String>>();
	//存储访问次数前100的IP
	public Set<IP> set = new TreeSet<IP>();
	
	// 生成日志文件
	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<fileNums;i++){
			File file = new File("D:\\javasoft\\TempTest\\BigData\\logSplit\\"+ i + ".txt");
			bwMap.put(i, new BufferedWriter(new FileWriter(file,true)));
			dataMap.put(i, new LinkedList<String>());
		}
		while(ip != null){
			int hashCode = ip.hashCode();
			hashCode = hashCode < 0 ? -hashCode : hashCode;
			int fileNum = hashCode % fileNums;
			List<String> 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<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();
		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<IP> temp1 = new TreeSet<IP>();
		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<IP> temp2 = new TreeSet<IP>();
		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<IP>{
	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~


你可能感兴趣的:(java,面试,大数据,日志分析,笔试)