数据分析案例(二):使用Java的Map集合进行上网日志流量统计

目录

数据样例:

需求: 

分析:

注意事项:


数据样例:

手机号段规则:1300000为号段,山东为所属省份,济南是所属城市,联通是所属运营商

prefix    phone    province    city    isp    post_code    city_code    area_code
130    1300000    山东    济南    联通    250000    0531    370100
130    1300001    江苏    常州    联通    213000    0519    320400
130    1300002    安徽    巢湖    联通    238000    0551    340181     ......

登陆网站流量:13026230503为手机号,提取域名baidu.com,20为上行流量,5000为下行流量

13026230503    http://v.baidu.com/tv 20 5000 
13826544101    http://www.weibo.com/?category=7 20 5000  
13926435656    http://v.baidu.com/tv 20 5000
    ......

需求: 

  1. 计算出用户上网流量总流量(上行+下行)最高的的网站Top3
  2. 根据给的的手机号段归属地规则,计算出总流量最高的省份Top3
  3. 根据给的的手机号段运营商规则,计算出总流量最高的运营商Top3

分析:

需要从两张表中提取数据,因此可以将1300000的手机号前七位作为两张表之间的外键连接,同时手机号段表中的属性很多,可以将它封装成一个javaBean(根据javabean规范封装的一个类,此处不做说明),将它的对象作为value值存入Map中,将手机号前七位作为key值。这样可以在比较时分别提取不同属性进行对比。同时在域名的提取上,我们需要做一些判断,因为有些数据是脏数据。这些我们在遇到时就可以直接try...catch配合continue清洗掉。最后做域名切分时的一些小技巧见下述代码。

另外域名切割可以使用正则表达式.......

1.计算出用户上网流量总流量(上行+下行)最高的的网站Top3

先创建一个Map容器,将域名作为key存储,将上行流量与下行流量的和作为value存储。这样查找速度比每次使用IO流从头读取的速度要快的多。

public class WebFlowCountDemo {
	public static void main(String[] args) throws Exception {
		//创建Map容器,存储:用户 + 总流量
		Map<String,Integer> map = new HashMap<>();
		//创建缓冲字符流,读取数据集。参数也可以是转换流,这样可以设定编码格式
		BufferedReader br = new BufferedReader(new FileReader("F:\\http.log"));
		
		String str;
		while((str=br.readLine())!=null) {
			String[] s = str.split("\\s");  //使用空白字符进行分割,可以代替制表符,空格
			String url = s[1];  //取出域名
			int upFlow = Integer.parseInt(s[2]);  //取出上行流量的整型数字
			int downFlow = Integer.parseInt(s[3]); //取出下行流量的整型数字
			int totalFlow = upFlow + downFlow;   //总流量
			
			String[] tempArr = url.split("\\.");  //实心点具有特殊含义,需要使用转义字符
			int index = 0;
			//不符合预期格式的数据,称为脏数据,直接使用try...catch语句清洗掉(忽略掉)。
			try {
				index = tempArr[2].indexOf("/");   //Indexof(待查元素):存在时返回索引位置,元素不存在的时候返回-1
			}catch(ArrayIndexOutOfBoundsException e) {
				continue;   //跳出本次异常,清洗掉脏数据
			}
			
			if(index != -1) {  //若符号存在,则截取字符串
				tempArr[2] = tempArr[2].substring(0, index);
			}
			
			String domainName = tempArr[1] + "." + tempArr[2];  //拼接域名
			
			//方式一:拿到域名后,检测map的key是否有该域名
			boolean bool = map.containsKey(domainName);
			//如果没有,以域名为key,流量为value,存到map中
			if(!bool) {
				map.put(domainName, totalFlow);
			}
			//如果有,以域名为key,取出value,把流量加到value上,再存到map中
			else {
				int flow = map.get(domainName) + totalFlow;
				map.put(domainName, flow);
			}
			
			//方式二:
			int flow = map.getOrDefault(domainName, 0);
			map.put(domainName, flow + totalFlow);
		}
	}
}

2.根据给的的手机号段归属地规则,计算出总流量最高的省份Top3

本次需求需要对两个表进行数据提取,连接点就是手机号前七位。由于手机号段归属地信息容量很大,需要先将其封装成javaBean对象,再作为value值存储进Map1中,这样可以便于处理后期需求的变动,以及提高查询速度。然后再创建一个Map2容器,用于存储提取后的省份总流量信息。具体是在遍历登录网站流量的手机号时,判断Map2容器中是否存在该手机号key值,如果不存在则该手机号对应的省份作为key的初始值存入,将其对应的总流量作为value的初始值存入。如果存在则以省份为key,取出value,然后把当前流量加到value中,之后在存进Map2中。

public class ProvinceFlowDemo {
	static Map<String,ProvinceBean> map;  //全局变量
	static {
		map = new HashMap<>();
	}
	
	public static void main(String[] args) throws IOException {
		getPhoneInfo();
		Map<String,Integer> temp = countProvinceFlow();
		//将Map对象转为ArrayList对象,便于使用Collections.sort()或者List.sort()方法进行排序
		Set<Entry<String, Integer>> entrySet = temp.entrySet();
		ArrayList<Entry<String, Integer>> arrayList = new ArrayList<>(entrySet);
		//使用Stream的方式可以很容易的得到Top3省份
		arrayList.stream().sorted((o1,o2)->o2.getValue()-o1.getValue());
		arrayList.stream().limit(3).forEach(System.out::println);;
	}

	//将手机号段归属地规则信息存储进Map中
	public static void getPhoneInfo() throws IOException {
		//使用缓冲字符流存储信息:转换流可以设定以那种编码格式进行转换
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("F:\\多易大数据培训\\java数据分析与web\\day01\\案例分析资料\\手机号段规则.txt")));
		
		String content;
		br.readLine(); //第一行是字段名,忽略掉
		while((content=br.readLine())!=null) {
			String[] split = content.split("\\s");
			
			String phonePrefix = split[1];
			String province = split[2];
			String city = split[3];
			ProvinceBean pro = new ProvinceBean(phonePrefix,province,city);
			//将bean对象存入map中
			map.put(phonePrefix, pro);
		}	
	}
	
	//读取用户上网流量信息,并与上一个Map集合产生关联
	public static Map<String,Integer> countProvinceFlow() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("F:\\多易大数据培训\\java数据分析与web\\day01\\案例分析资料\\http.log")));
		
		//创建新的Map对象,用于存储提取的省份+总流量信息
		Map<String,Integer> flowMap = new HashMap<>(); 
		
		String str;
		while((str=br.readLine())!=null) {
			String[] split = str.split("\\s");
			//截取号码前七位
			String phonePrefix = split[0].substring(0, 7);
			int upFlow = Integer.parseInt(split[2]);
			int downFlow = Integer.parseInt(split[3]);
			int totalFlow = upFlow + downFlow;
			
			//以手机号前7位为key,在map中获取value,然后从Bean中取得省份/城市等
			ProvinceBean bean = map.get(phonePrefix);
			String province = bean.getProvince();
			
			//以省份为key,检测map中是否包含这个省份
			//如果没有,以省份为key,流量为value,存入map
			//如果有,以省份为key,取出value,然后把流量加到value中
			Integer flow = flowMap.getOrDefault(province, 0);
			flowMap.put(province, flow + totalFlow);
		}
		return flowMap;
	}
}

注意事项:

  1. 对于切分时,使用空白字符“\\s”代表制表符与空格:正则表达式需要转义,即有特殊含义的字符需要转义
  2. 检索日志的时候可以添加计数器(编码阶段),对于脏数据可以准确的定位。同时使用try…catch语句处理异常(清洗掉脏数据),利用continue跳出本次循环。
  3. Indexof(待查元素):元素不存在的时候返回-1。
  4. 可以自定义几条数据用于验证结果集
  5. 使用IO流进行逐行读取速度很慢,可以直接将每行的信息封装成一个javaBean对象,存入Map中,这样检索速度会很快。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值