数据分析案例(三):IP需求分析

数据样例:

access.log:电信运营商的用户上网数据:

20090121000132095572000|125.213.100.123|show.51.com|/shoplist.php?phpfile.......
20090121000132406516000|117.101.222.68|gg.xiaonei.com|/view.jsp?p=389|Mo.......

ip.txt:ip地址和归属地的规则数据:

1.0.8.0|1.0.15.255|16779264|16781311|亚洲|中国|广东|广州||电信|440100|China|CN|113.280637|23.125178
1.0.32.0|1.0.63.255|16785408|亚洲|中国|广东|广州||电信|440100|China|CN|113.280637|23.125178
1.1.0.0|1.1.0.255|16842752|16843007|亚洲|中国|福建|福州||电信|350100|China|CN|119.306239|26.075302

需求:

通过计算access.log中的用户行为数据,统计出各个省份访问量(一次请求记作一次独立的访问量),并按照各个省份的访问量的从高到低进行排序。

分析:

根据.Log文件数据获取所有的ip数据,根据ip去ip的规则数据中查询区域或者运营商数据,因为在规则数据中,每个城市/省份的IP都在一个区段范围内,因此需要先通过位运算将IP转为长整型数字,在使用二分查找进行位置判断。

1 读取ip规则数据  将每行数据封装成javabean对象 。把所有的数据(不存在映射关系)封装在list中,便于后期需求更改。

2 在遍历用户上网数据的IP的同时,将IP转换成长整型,并使用二分查找算法找寻所属区段

3 创建一个新的Map集合,将省份作为key值,将上网次数作为value值,存储结果信息。

public class ProviceFlowCount {
	public static void main(String[] args) throws Exception {
		//建立List容器,存储ip地址与省份封装的对象信息
		ArrayList<IpBean> arrayList = new ArrayList<>();
		//创建缓冲字符流,读取文件
		BufferedReader br = new BufferedReader(new FileReader("F:\\多易大数据培训\\ip.txt"));
		
		String str;
		while((str=br.readLine())!=null) {
			try {
				String[] split = str.split("\\|");
				long upIp = Long.parseLong(split[2]);
				long downIp = Long.parseLong(split[3]);
				String provice = split[6];
				String city = split[7];
				
				//这里会不断的new
				arrayList.add(new IpBean(upIp,downIp,provice,city));
			}catch(NumberFormatException e) {
				continue;
			}		
		}
	
		//创建缓冲字符流,读取文件。并将IP转为长整型
		BufferedReader br1 = new BufferedReader(new FileReader("F:\\access.log"));
		//创建Map集合用于存储最后的结果
		Map<String,Integer> map = new HashMap<>();
		
		String str1;
		while((str1=br1.readLine())!=null) {
			String[] split = str1.split("\\|");
			String[] split2 = split[1].split("\\.");
			
			//将ip的点十进制表示形式转为长整型
			long ip = 0;   
			for(int i=0;i<4;i++) {
				long b = Long.parseLong(split2[i]);
				long temp = b<<((3-i)*8);   //转成10进制整型后可以直接进行位运算。
				ip += temp;
			}	
			
			//使用二分查找算法
			int start = 0;
			int end = arrayList.size()-1;
			while(start <= end) {
				int middleIndex = (start + end)/2 ;
				IpBean bean = arrayList.get(middleIndex);
				long startIp = bean.getUpIp();
				long endIp = bean.getDownIp();

				if(ip<startIp) {   //小于下限,则往前找
					end = middleIndex-1;	
				}else if(ip>endIp){  //大于上限,则往后找
					start = middleIndex+1;
				}else {  
					String provice = bean.getProvice();
					
					int count = map.getOrDefault(provice, 0);
					map.put(provice, count+1);
					//最差的情况会在start=end时满足要求,此时end与start的值并不会变化,需要我们手动的跳出循环
					break;  
				}
			}
		}
		
		//集合排序有两种方式:Collections.sort()与List集合中的sort方法,因此需要先将Map转为List。
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		ArrayList<Entry<String, Integer>> arrList2 = new ArrayList<>(entrySet);
		arrList2.sort((o1,o2)->o2.getValue()-o1.getValue());
		System.out.println(arrList2);
	}
}

注意事项:

每一个区域的IP都是一个字段,里面包含大量的IP地址。因此区分IP属于哪一个区域可以将IP转为一个长整型数据,比较是否在IP的区段范围内...

那么具体怎么在一个有序的IP地址文件中进行查询操作呢: 二分查找。二分查找算法的时间复杂度是不稳定的,但是要快于普通的暴力查询。

存储的时候不能使用Map集合了,因为Map 的键值对是唯一的,而这里IP的区段是一个范围。

编码小记:

JavaWeb中默认创建的编码格式:iso8859-1

简体中文Windows默认使用GBK编码

UTF-8:基于Unicode字符集,能表示世界上所有具有计算机的语言、符号

UTF-8 BOM:会在文本开头添加3个字节的BOM信息,这是UTF-8编码的描述信息,很多余,文本编辑器显示时会自动忽略。

ANSI:本地编码(比如简体windows的本地编码是GBK)

eg:

UTF-8的汉字编码格式:1110 xxxx 10xx xxxx 10xx xxxx        3个字节

文  0x6587  unicode编码 占三个字节

0110 0101 1000 0111 :两字节

1110 0110 1001 0110 1000 0111 :三字节

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值