配色: 字号:
MapReduce实现手机上网流量分析
2016-12-09 | 阅:  转:  |  分享 
  
MapReduce实现手机上网流量分析

一、问题背景



现在的移动刚一通话就可以在网站上看自己的通话记录,以前是本月只能看上一个月。不过流量仍然是只能看上一月的。



目的就是找到用户在一段时间内的上网流量。



本文并没有对时间分组。



二、数据集分析



可以看出实际数据集并不是每个字段都有值,但是还好,完整地以tab隔开了,数据格式还是不错的,我们需要的上行下行数据都有,没有缺失值。其实这个需要在程序中处理,如果不在的话该怎么办。



13631579850661372623050300-FD-07-A4-72-B8:CMCC120.196.100.82i02.c.aliimg.com2427248124681200

1363157995052138265441015C-0E-8B-C7-F1-E0:CMCC120.197.40.4402640200

13631579910761392643565620-10-7A-28-CC-0A:CMCC120.196.100.99241321512200

1363154400022139262511065C-0E-8B-8B-B1-50:CMCC120.197.40.4402400200

13631579930441821157596194-71-AC-CD-E6-18:CMCC-EASY120.196.100.99iface.qiyi.com视频网站151215272106200

1363157995074841384135C-0E-8B-8C-E8-20:7DaysInn120.197.40.4122.72.52.12201641161432200

136315799305513560439658C4-17-FE-BA-DE-D9:CMCC120.196.100.9918151116954200

1363157995033159201332575C-0E-8B-C7-BA-20:CMCC120.197.40.4sug.so.360.cn信息安全202031562936200

13631579830191371919941968-A1-B7-03-07-B1:CMCC-EASY120.196.100.82402400200

1363157984041136605779915C-0E-8B-92-5C-20:CMCC-EASY120.197.40.4s19.cnzz.com站点统计2496960690200

1363157973098150136858585C-0E-8B-C7-F7-90:CMCC120.197.40.4rank.ie.sogou.com搜索引擎282736593538200

136315798602915989002119E8-99-C4-4E-93-E0:CMCC-EASY120.196.100.99www.umeng.com站点统计331938180200

136315799209313560439658C4-17-FE-BA-DE-D9:CMCC120.196.100.991599184938200

1363157986041134802531045C-0E-8B-C7-FC-80:CMCC-EASY120.197.40.433180180200

1363157984040136028465655C-0E-8B-8B-B6-00:CMCC120.197.40.42052.flash2-http.qq.com综合门户151219382910200

13631579950931392231446600-FD-07-A2-EC-BA:CMCC120.196.100.82img.qfc.cn121230083720200

1363157982040135024688235C-0A-5B-6A-0B-D4:CMCC-EASY120.196.100.99y0.ifengimg.com综合门户571027335110349200

13631579860721832017338284-25-DB-4F-10-1A:CMCC-EASY120.196.100.99input.shouji.sogou.com搜索引擎211895312412200

13631579900431392505741300-1F-64-E1-E6-9A:CMCC120.196.100.55t3.baidu.com搜索引擎69631105848243200

13631579880721376077871000-FD-07-A4-7B-08:CMCC120.196.100.8222120120200

13631579850661372623888800-FD-07-A4-72-B8:CMCC120.196.100.82i02.c.aliimg.com2427248124681200

136315799305513560436666C4-17-FE-BA-DE-D9:CMCC120.196.100.9918151116954200

三、实验分析



3.1Mapper



首先看咱们的目的是统计每个人的上行总流量和下行总流量以及上下行总流,上下行=上行+下行,这个是有意义的,因为我们并不能实时得到自己的上网流量,这个说的有点大了,我们并没有六式计算,或者说是为了实现。



输入的key是行号,一般是Object和LongWritable,一般输入的key没啥用,数据集市一行一行文本,输入value是text,输入以电话号码为key,那么是text,输出value包含三类信息,上行总、下行总和总,可以封装在数组中,但是这样很不利于修改,比如说项目经历要你增加一些属性要显示,或者减少一些,一般用bean。



packagecn.app.hadoop.mr.datacount;



importjava.io.IOException;

importjava.text.FieldPosition;



importorg.apache.hadoop.io.LongWritable;

importorg.apache.hadoop.io.Text;

importorg.apache.hadoop.mapreduce.Mapper;



//第一个处理文本的话一般是LongWritable或者object

//一行一行的文本是text

//输出的key的手机号定位Text

//结果是DataBean一定要实现Writable接口

publicclassDataCountMapperextendsMapper{



//实际处理中已经进行了数据清洗在这就不catch

publicvoidmap(LongWritablekey,Textvalue,Contextcontext)

throwsIOException,InterruptedException{

Stringline=value.toString();

String[]fields=line.split("\t");

StringtelNo=fields[1];

longupPayLoad=Long.parseLong(fields[8]);

longdownPayLoad=Long.parseLong(fields[9]);



//封装到bean,如果格式不对那么跳过这里不考虑,假设已经清洗

DataBeandataBean=newDataBean(telNo,upPayLoad,downPayLoad);



//但是这种方式每行都new了一个databena下次并没有释放很慢

//能不能在外边newDataBean,每次修改值,如果按以前的思维是不行的,因为指向了

//同一块内存,没法相加

//但是在hadoop里是可以的,因为每次写入以后就已经序列化了,下次不一样了

context.write(newText(telNo),dataBean);

}



}







3.2DataBean



bean要能在网络间传输,需要实现hadoop的writable接口,那么首先实现接口的方法,



//反序列化deserializable从字节流独处赋值给内存

publicvoidreadFields(DataInputin)throwsIOException{

//TODOAuto-generatedmethodstub



//注意顺序类型里面没参数

//this.telNo=in.readUTF(telNo);是错的



this.telNo=in.readUTF();

this.upPayLoad=in.readLong();

this.downPayLoad=in.readLong();

this.totalPayLoad=in.readLong();



}



//序列化serializable,从内存写入到字节流或者通过rmi在网上传输

publicvoidwrite(DataOutputout)throwsIOException{

//TODOAuto-generatedmethodstub

//手机号是String,但是没有writeString,用writeUTF

out.writeUTF(telNo);

out.writeLong(upPayLoad);

out.writeLwww.baiyuewang.netong(downPayLoad);

out.writeLong(totalPayLoad);

}

write就是序列化,吧对象写入到字节流,注意String类型并没有对性的writeString算法,可以用通用的writeUTF方法,证书类型用long,又对影的writeLong。



readFile就是反序列化,从硬盘或者网络读出,然后赋值给对象,注意读的时候不需要参数,比如



1

this.telNo=on.readUTF(telNo);

这样是错误的,想想看对象都成字节流,怎么能看得出是什么,所以是按顺序来判断对应属性的,但是每个属性攒了多少个字节呢,这就要靠属性的类型来确定了,这就想分配内存一样,以上纯属个人理解。



那么bean有什么属性呢?需要手机号码,上行、下行,以及赞自己见得总流量,然后产生getter和setter;mapper提交的时候就提交DataBean,这就需要有参数的够着方法,不能每次都setter,另外mapper写入的时候通过反射机制得到实例化的dataBean,那么我们就需要午餐的默认垢找方法。



另外写入databean的时候默认输出类名+hashcode值,这不是我们需要的,所以重写toString方法,eclipse可以自动生成。



@Override

publicStringtoString(){

//电话号码不要了

return"DataBean[upPayLoad="+upPayLoad

+",downPayLoad="+downPayLoad+",totalPayLoad="

+totalPayLoad+"]";

}





3.3Reducer



reducer的输入类型就是mapper的输出类型,分别是text和databean,他的输出类型野是text和databean。



这其实就是业务逻辑复杂一些的wordcount,mapper提交到reducer的已合并相同key格式是,我们需要便利value结合,廉价上行流量得到上行总流量,廉价下行流量得到下行总刘玲,那么最总得流量是上下行总得和。



3.4Main



可以直接在eclipse里,newreducerdriver,就是main函数了,为什么main里总是要newconf,这是为了给本job个性化配置,通过conf.set也是kv对,否则就找全聚德conf。



另外注意写路径的时候加上hdfs://hostname:8020,因为没有上下文的FileSystem,所以必须加,否则认为是本地的file,提示找不到。

献花(0)
+1
(本文系thedust79首藏)