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

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

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

由于IP是32位的,最多有个2^32个IP,也就是4G,所以不能完全加载到内存中处理;可以采用映射的方法,按照IP地址的Hash(IP)%1024值,把整个大文件映射为1024个小文件,再依次分析每个小文中出现频率最大的前100个IP及相应的频率,因为涉及到排序,所以使用到了TreeSet。
画图应该好理解一点:
[img]http://dl2.iteye.com/upload/attachment/0090/6004/86afb578-b504-36e6-a2c2-5d7cf40df487.png[/img]
具体代码如下:

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~ :arrow:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值