现在的移动刚一通话就可以在网站上看自己的通话记录,以前是本月只能看上一个月。不过流量仍然是只能看上一月的。
目的就是找到用户在一段时间内的上网流量。
本文并没有对时间分组。
可以看出实际数据集并不是每个字段都有值,但是还好,完整地以 tab 隔开了,数据格式还是不错的,我们需要的上行下行数据都有,没有缺失值。其实这个需要在程序中处理,如果不在的话 该怎么办。
- 1363157985066 13726230503 00 - FD - 07 - A4 - 72 - B8: CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 24681 200 1363157995052 13826544101 5C - 0E-8B - C7 - F1 - E0: CMCC 120.197.40.4 4 0 264 0 200 1363157991076 13926435656 20 - 10 - 7A - 28 - CC - 0A: CMCC 120.196.100.99 2 4 132 1512 200 1363154400022 13926251106 5C - 0E-8B - 8B - B1 - 50 : CMCC 120.197.40.4 4 0 240 0 200 1363157993044 18211575961 94 - 71 - AC - CD - E6 - 18 : CMCC - EASY 120.196.100.99 iface.qiyi.com视频网站15 12 1527 2106 200 1363157995074 84138413 5C - 0E-8B - 8C - E8 - 20 : 7DaysInn 120.197.40.4 122.72.52.12 20 16 4116 1432 200 1363157993055 13560439658 C4 - 17 - FE - BA - DE - D9: CMCC 120.196.100.99 18 15 1116 954 200 1363157995033 15920133257 5C - 0E-8B - C7 - BA - 20 : CMCC 120.197.40.4 sug.so.360.cn信息安全20 20 3156 2936 200 1363157983019 13719199419 68 - A1 - B7 - 03 - 07 - B1: CMCC - EASY 120.196.100.82 4 0 240 0 200 1363157984041 13660577991 5C - 0E-8B - 92 - 5C - 20 : CMCC - EASY 120.197.40.4 s19.cnzz.com站点统计24 9 6960 690 200 1363157973098 15013685858 5C - 0E-8B - C7 - F7 - 90 : CMCC 120.197.40.4 rank.ie.sogou.com搜索引擎28 27 3659 3538 200 1363157986029 15989002119 E8 - 99 - C4 - 4E-93 - E0: CMCC - EASY 120.196.100.99 www.umeng.com站点统计3 3 1938 180 200 1363157992093 13560439658 C4 - 17 - FE - BA - DE - D9: CMCC 120.196.100.99 15 9 918 4938 200 1363157986041 13480253104 5C - 0E-8B - C7 - FC - 80 : CMCC - EASY 120.197.40.4 3 3 180 180 200 1363157984040 13602846565 5C - 0E-8B - 8B - B6 - 00 : CMCC 120.197.40.4 2052.flash2 - http.qq.com综合门户15 12 1938 2910 200 1363157995093 13922314466 00 - FD - 07 - A2 - EC - BA: CMCC 120.196.100.82 img.qfc.cn 12 12 3008 3720 200 1363157982040 13502468823 5C - 0A - 5B - 6A - 0B - D4: CMCC - EASY 120.196.100.99 y0.ifengimg.com综合门户57 102 7335 110349 200 1363157986072 18320173382 84 - 25 - DB - 4F - 10 - 1A: CMCC - EASY 120.196.100.99 input.shouji.sogou.com搜索引擎21 18 9531 2412 200 1363157990043 13925057413 00 - 1F - 64 - E1 - E6 - 9A: CMCC 120.196.100.55 t3.baidu.com搜索引擎69 63 11058 48243 200 1363157988072 13760778710 00 - FD - 07 - A4 - 7B - 08 : CMCC 120.196.100.82 2 2 120 120 200 1363157985066 13726238888 00 - FD - 07 - A4 - 72 - B8: CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 24681 200 1363157993055 13560436666 C4 - 17 - FE - BA - DE - D9: CMCC 120.196.100.99 18 15 1116 954 200
首先看咱们的目的是统计每个人的上行总流量和下行总流量以及上下行总流,上下行 = 上行 + 下行,这个是有意义的,因为我们并不能实时得到自己的上网流量,这个说的有点大了,我们并没有六式计算,或者说是为了实现。
输入的 key 是行号,一般是 Object 和 LongWritable,一般输入的 key 没啥用,数据集市一行一行文本,输入 value 是 text,输入以电话号码为 key,那么是 text,输出 value 包含三类信息,上行总、下行总和总,可以封装在数组中,但是这样很不利于修改,比如说项目经历要你增加一些属性要显示,或者减少一些,一般用 bean。
- package cn.app.hadoop.mr.datacount;
- import java.io.IOException;
- import java.text.FieldPosition;
- import org.apache.hadoop.io.LongWritable;
- import org.apache.hadoop.io.Text;
- import org.apache.hadoop.mapreduce.Mapper;
- //第一个处理文本的话一般是LongWritable 或者object
- //一行一行的文本是text
- //输出的key的手机号 定位Text
- //结果是DataBean 一定要实现Writable接口
- public class DataCountMapper extends Mapper < LongWritable,
- Text,
- Text,
- DataBean > {
- //实际处理中已经进行了数据清洗 在这就不catch
- public void map(LongWritable key, Text value, Context context) throws IOException,
- InterruptedException {
- String line = value.toString();
- String[] fields = line.split("\t");
- String telNo = fields[1];
- long upPayLoad = Long.parseLong(fields[8]);
- long downPayLoad = Long.parseLong(fields[9]);
- //封装到bean,如果格式不对那么跳过 这里不考虑,假设已经清洗
- DataBean dataBean = new DataBean(telNo, upPayLoad, downPayLoad);
- //但是这种方式 每行都new了一个databena下次并没有释放 很慢
- //能不能在外边new DataBean,每次修改值,如果按以前的思维是不行的,因为指向了
- //同一块内存,没法相加
- //但是在hadoop里是可以的,因为每次写入以后就已经序列化了,下次不一样了
- context.write(new Text(telNo), dataBean);
- }
- }
bean 要能在网络间传输,需要实现 hadoop 的 writable 接口,那么首先实现接口的方法,
- //反序列化 deserializable 从字节流独处 赋值给内存
- public void readFields(DataInput in ) throws IOException {
- // TODO Auto-generated method stub
- //注意顺序 类型 里面没参数
- //this.telNo = in.readUTF(telNo);是错的
- this.telNo = in.readUTF();
- this.upPayLoad = in.readLong();
- this.downPayLoad = in.readLong();
- this.totalPayLoad = in.readLong();
- }
- //序列化serializable,从内存写入到字节流 或者通过rmi在网上传输
- public void write(DataOutput out) throws IOException {
- // TODO Auto-generated method stub
- //手机号是String,但是没有writeString,用writeUTF
- out.writeUTF(telNo);
- out.writeLong(upPayLoad);
- out.writeLong(downPayLoad);
- out.writeLong(totalPayLoad);
- }
write 就是序列化,吧对象写入到字节流,注意 String 类型并没有对性的 writeString 算法,可以用通用的 writeUTF 方法,证书类型用 long,又对影的 writeLong。
readFile 就是反序列化,从硬盘或者网络读出,然后赋值给对象,注意读的时候不需要参数,比如
- this.telNo = on.readUTF(telNo);
这样是错误的,想想看对象都成字节流,怎么能看得出是什么,所以是按顺序来判断对应属性的,但是每个属性攒了多少个字节呢,这就要靠属性的类型来确定了,这就想分配内存一样,以上纯属个人理解。
那么 bean 有什么属性呢?需要手机号码,上行、下行,以及赞自己见得总流量,然后产生 getter 和 setter;mapper 提交的时候就提交 DataBean,这就需要有参数的够着方法,不能每次都 setter,另外 mapper 写入的时候通过反射机制得到实例化的 dataBean,那么我们就需要午餐的默认垢找方法。
另外写入 databean 的时候默认输出类名 + hashcode 值,这不是我们需要的,所以重写 toString 方法,eclipse 可以自动生成。
- @Override public String toString() {
- //电话号码不要了
- return "DataBean [upPayLoad=" + upPayLoad + ", downPayLoad=" + downPayLoad + ", totalPayLoad=" + totalPayLoad + "]";
- }
reducer 的输入类型就是 mapper 的输出类型,分别是 text 和 databean,他的输出类型野是 text 和 databean。
这其实就是业务逻辑复杂一些的 wordcount,mapper 提交到 reducer 的已合并相同 key 格式是 <telNo,{{up1,dw1},{up2,dw2}}>,我们需要便利 value 结合,廉价上行流量得到上行总流量,廉价下行流量得到下行总刘玲,那么最总得流量是上下行总得和。
可以直接在 eclipse 里,new reducer driver,就是 main 函数了,为什么 main 里总是要 new conf,这是为了给本 job 个性化配置,通过 conf.set 也是 kv 对,否则就找全聚德 conf。
另外注意写路径的时候加上 hdfs://hostname:8020,因为没有上下文的 FileSystem,所以必须加,否则认为是本地的 file,提示找不到。
可以从原始数据找到一个用户的两条或者多交记录,求和,然后对比,看看业务逻辑对不。
来源: http://www.cnblogs.com/hxsyl/p/6143964.html