其他分享
首页 > 其他分享> > 大数据实战-callLog项目(通话记录数据分析)之数据生产

大数据实战-callLog项目(通话记录数据分析)之数据生产

作者:互联网

文章目录

前言

这个环节用到了两个工具来提高开发效率,而不是重复造轮子。一个是随机生成测试数据的 java-testdata-generator,另一个是数据处理的Joinery,我的博客中都有介绍,可以点进去了解一下。

生成基础数据

在随机生成数据之前,需要准备一些基础数据,否则直接随机的随机性太强,后面数据分析求和的意义就不大了。

Meaven依赖

其中POI是用DataFrame生成csv文件需要的依赖,如果自己手动写csv的话,joinery和poi都不需要了。

<dependency>
			<groupId>joinery</groupId>
			<artifactId>joinery-dataframe</artifactId>
			<version>1.9</version>
		</dependency>
		<dependency>
			<groupId>com.github.binarywang</groupId>
			<artifactId>java-testdata-generator</artifactId>
			<version>1.1.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.17</version>
		</dependency>

姓名-手机号列表

		private static void geneNamNum(){
		//准备生成器和df对象
		ChineseNameGenerator cng = ChineseNameGenerator.getInstance();
		ChineseMobileNumberGenerator cmng = ChineseMobileNumberGenerator.getInstance();
		DataFrame<Object> df = new DataFrame<>("name", "telephone");
		for(int i=0;i<10;i++){
			//生成中文姓名并放入df
			String generatedName = cng.generate();
			String generatedMobileNum =  cmng.generate();
			df.append(Arrays.asList(generatedName, generatedMobileNum));
		}
			try {
			//生成csv文件到运行环境的当前目录下
			df.writeCsv("./nam_num.csv");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}	

在main方法中调用即可获得结果
在这里插入图片描述

时间维度表

由于可视化的web项目中需要用到,使用在这里先一起生成了。如果用自己的可视化工具,就不用生成。

private static void genDateDimention(){
		DataFrame<Object> df = new DataFrame<>("year", "month","day");
		Calendar calendar=Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			//设置时间段的起止时间
			Date start = sdf.parse("2017-01-01");
			Date end = sdf.parse("2019-07-12");
			calendar.setTime(start);
			//先添加年月日
			while(end.compareTo(calendar.getTime()) > 0){
				//注意月份从0开始,需要+1
				df.append(Arrays.asList(calendar.get(Calendar.YEAR),
						calendar.get(Calendar.MONTH)+1 ,
						calendar.get(Calendar.DATE)));
				//日期+1
				calendar.add(Calendar.DATE, 1);
			}
			//再添加年维度和月维度的,缺失的维度设为-1
			for(int year=2017;year<2020;year++){
				df.append(Arrays.asList(year,-1,-1));
				for(int month=1;month<=12;month++){
					df.append(Arrays.asList(year,month,-1));
				}
			}
			//生成csv文件
			df.writeCsv("./dateDimentions.csv");
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

直接在main方法调用即可
在这里插入图片描述
2019 7 11表示2019年7月11日很好理解,2017 -1 -1表示2017年,2017 1 -1表示2017年1月,为什么要这样呢?因为查询通话信息的时候,选定的范围可能是一天,也可能是一个月或者一年;这种设计能将三种维度放在一张表里,便于web项目的使用。

自动随机生成

接着用之前的数据来模拟数据生产。
需要生成的数据形式为:主叫人+主叫人号码+被叫人+被叫人号码+通话时间(时间戳)+通话时长
例如秦东,15178223582,姜惑努,18481678295,1547472607462,147

生成时间戳

这个比较麻烦,需要仔细留意一下,因为整型11位数解决不了时间戳运算的问题。

生成一定范围内的long数据

java中没有提供这样的方法,需要自己封装一下;其中n表示长整型的位数

代码

//生成一定范围内的长整数
	public Long nextLong(Random rng, Long n) {  
	   // error checking and 2^x checking removed for simplicity.  
	   long bits, val;  
	   do {  
	      bits = (rng.nextLong() << 1) >>> 1;  
	      val = bits % n;  
	   } while (bits-val+(n-1) < 0L);  
	   return val;  
	}  

调用演示

在这里插入图片描述

获得随机的时间戳

代码

//生成一段时间内的时间戳
	private Long getTimeStamp(SimpleDateFormat formatter, String startStr, String endStr){
		Random random = new Random();
		Long startTime = null, endTime = null, offset = null;
		try {
			startTime = formatter.parse(startStr).getTime();
			endTime = formatter.parse(endStr).getTime();
			//这里就用到了之前的nextLong,偏移的范围在起止时间相差的时间段内
			offset = this.nextLong(random, endTime-startTime);			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return startTime+offset;
	}

调用示例

这样就能获得指定时间段类的任意时间了
在这里插入图片描述

生成一行记录

首先需要读取之前的nam_num.csv文件并放入Map,用于随机抽取通话人。

	private Map<String,String> getNamNumMap(String pathname){
		Map<String, String> map = new HashMap<String,String>();
        //Java7的try-with-resources可以优雅关闭文件,异常时自动关闭文件
        try (FileReader reader = new FileReader(pathname);
             BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言
        ) {
            String line = br.readLine();
            String[] strs;
            while ((line = br.readLine()) != null) {
                // 一次读入一行数据
                strs = line.split(",");
                map.put(strs[0], strs[1]);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
        return map;
	}

再准备一个写csv文件的方法

private void writeRecord(String outputFilePath, String line){
		//构造好记录后就往文件中写,输出的文件通过主函数的参数传递进来
		try(FileWriter writer = new FileWriter(outputFilePath, true);
			BufferedWriter br = new BufferedWriter(writer)){
			br.write(line+"\n");
			br.flush();
			//设置休眠时间来调整,数据生产的速度
			Thread.sleep(10*1000);
		}catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
			e.printStackTrace();
		} 
	}

然后就可以再Main方法中构造记录了,注意主函数需要两个参数,一个是nam_num.csv文件路径另一个是

public static void main(String[] args) {
		 AutoDataGen adg = new AutoDataGen();	
		 //获得基础的姓名手机号映射
		 Map<String, String> map = adg.getNamNumMap(args[0]);
		 String[] keys = new String[map.size()];
		 //获得Key的数组用于随机取出通话人
		 map.keySet().toArray(keys);
		 
		 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		 Random random = new Random();
		 String key1,key2,value1,value2;
		 while(true){
			 //获得主叫人被叫人姓名
			 key1 = keys[random.nextInt(keys.length)];
			 key2 = keys[random.nextInt(keys.length)];
			 //自己不能够自己打电话
			 if(key1==key2)
				 continue;
			//获得主叫人被叫人手机号
			value1 = map.get(key1);
			value2 = map.get(key2);
			//获得通话时间
			Long timeStamp = adg.getTimeStamp(formatter, "2017-01-01 00:00:00", "2019-07-11 23:59:59");
			//获得通话时间
			int callTime = random.nextInt(9999);
			String line = key1+","+value1+","+key2+","+value2+","+String.valueOf(timeStamp)+","+String.valueOf(callTime);
			System.out.println(line);
			adg.writeRecord(args[1], line);		
		 }
	}

可以现在Eclipse中测试一下,首先打开运行参数的设置菜单
在这里插入图片描述
设置两个路径,第二个是保存结果的
在这里插入图片描述
可以看到控制台间隔10S打印一行记录
在这里插入图片描述

打包上传

在Eclipse中打包很方便
在这里插入图片描述
然后可以在target下找到jar包将其上传到linux中,并且把nam_num.csv一同带过去
在这里插入图片描述
我在家目录下新建了callLogs文件夹,并将它们放在里面(上传的步骤省去,直接用Xterm或者WinSCP都能实现)
在这里插入图片描述

执行程序

java -cp calllogs-0.0.1-SNAPSHOT.jar product.AutoDataGen ./nam_num.csv ./calllog.csv注意自己的包名和类名
只要这样一直开着就能一直不断产生数据
在这里插入图片描述
在这里插入图片描述

后记

终于实现了数据生成这个环节了,我也通过这次锻炼收获了不少,而且其中封装的一些代码在别的项目也能拿过去用。

标签:数据分析,map,String,通话记录,生成,callLog,new,line,csv
来源: https://blog.csdn.net/weixin_44112790/article/details/95721280