Hadoop——MapReduce解决实际问题

目的:

1通过理论联系实际,引导学生依据所掌握的Java语言程序设计和分布式编程框架知识,在理解MapReduce运行机制的基础上,研究分析和解决实际问题方案

2掌握自主学习的方法,加深相关知识点的理解,提高分析问题的能力以及编码、调试的能力,促进课程目标的达成。

内容:

1.单词统计:利用倒排索引实现每个单词在不同文件中出现的次数

2.手机上网流量统计:按照手机号码分别统计上网的上下行流量,并按照总流量从大到小排序

3.社交粉丝数据分析:根据已存在的qq好友列表数据,求出哪些人两两之间有共同好友,及他俩的共同好友都有谁

1单词统计

设计思路:

①因为需要计算每个单词在不同文件中出现的次数,因此首先将常规mapper的输出格式  <单词,1> 变为 <单词:文件名,1>,即单词和文件名作为key,1作为value;

②然后使用combine先将数据<单词:文件名,1,1,1…>中的values进行合并(累加),然后再将数据形式变为以单词作key,文件名和出现次数作value,即<单词, 文件名-出现的总次数(2/3/4….)>;

③然后使用Reducer再进行汇总,得出每个单词在每个文件中出现的次数。

Map端程序:(给出map方法即可)

String line = ivalue.toString();       //取出一行

String[] words = line.split(" ");        //切分line.split(" ")

FileSplit fileSplit = (FileSplit) context.getInputSplit();         //取出当前处理切片所在的文件名

String filename = fileSplit.getPath().getName();

for (String word : words) {                        //输出<单词:文件名,1>

       context.write(new Text(word+":"+filename),new IntWritable(1));       //将单词和文件名作为key,1作为value

}

Combiner端程序:

int sum = 0;          // 首先求和,将value的值累加

for (IntWritable val : values) {

       sum+=val.get();

}

//处理之后数据变为<单词:文件名,出现的总次数(例如3)>

//将key中的单词和文件名使用“:”进行拆分

String[] key = _key.toString().split(":");     

context.write(new Text(key[0]), new Text(key[1]+"-"+sum));         //然后将单词作为key,文件名和出现的次数作为value

Reduce程序:(给出reduce方法即可)

String value = "";

for (Text val : values) {

       value += val.toString()+";";             //将values的值通过“;”连接

}

context.write(_key, new Text(value));                //最后将<单词,文件名1-2;文件名2-3;文件名3...>输出

Driver程序:(给出map输出和reduce输出设置即可)

job.setMapOutputKeyClass(Text.class);            //mapper的输出

job.setMapOutputValueClass(Text.class);

job.setOutputKeyClass(Text.class);                //Reducer的输出

job.setOutputValueClass(Text.class);

 

2手机上网流量统计

设计思路:

①先按手机号统计上网的上下行流量,即按手机号的升序统计出结果;

②在①的基础上,将手机上网流量(FlowBean)作为key,然后自定义两个FlowBean对象的比较方法,让其按照从大到小的顺序排列

Map端程序:(给出map方法即可)

①的Map端程序:

String line = ivalue.toString();           //取出手机号和上行、下行流量

String[] strings = line.split("\t");          //切分字段

String phoneNu = strings[1];             //手机号

long upFlow = Long.parseLong(strings[strings.length-3]);         //上行流量

long downFlow = Long.parseLong(strings[strings.length-2]);      //下行流量

context.write(new Text(phoneNu), new FlowBean(upFlow,downFlow));

②的Map端程序:

String line = ivalue.toString();         // 取出手机号和上行、下行流量

String[] strings = line.split("\t");       // 切分字段

String phoneNu = strings[0];          // 手机号

long upFlow = Long.parseLong(strings[1]);        // 上行流量

long downFlow = Long.parseLong(strings[2]);     // 下行流量

//将总的流量作为key,手机号作为value,让其按总流量进行排序

context.write(new FlowBean(upFlow, downFlow),new Text(phoneNu));

 

Reduce端程序:(给出reduce方法即可)

①的Reduce端程序:

long sum_upFlow = 0;

long sum_downFlow = 0;

//将一个手机号中的所有上行、下行流量累加,即对values中的数据求和

for (FlowBean val : values) {

       sum_upFlow += val.getUpFlow();

       sum_downFlow += val.getDownFlow();

}

context.write(_key, new FlowBean(sum_upFlow, sum_downFlow));

②的Reduce端程序:

for (Text val : values) {            //遍历相同上网流量的手机号列表

                                                //将输出结果仍然变成手机号为key,流量为value

       for (Text phone : values) {

              context.write(new Text(phone), _key);

       }    

}

 

Driver程序:(给出map输出和reduce输出设置即可)

①的Driver端程序:

job.setMapOutputKeyClass(Text.class);           //mapper的输出

job.setMapOutputValueClass(FlowBean.class);

job.setOutputKeyClass(Text.class);              //reduce的输出

job.setOutputValueClass(FlowBean.class);

②的Driver端程序:

job.setMapOutputKeyClass(FlowBean.class);           //mapper的输出结果

job.setMapOutputValueClass(Text.class);

job.setOutputKeyClass(Text.class);                // reduce的输出结果

job.setOutputValueClass(FlowBean.class);

FlowBean程序:(两个对象进行比较大小)

@Override                     //定义两个对象进行比较大小

public int compareTo(FlowBean o) {         

       return this.sumFlow > o.getSumFlow()?-1:1;

}

 

3社交粉丝数据分析

设计思路:

阶段一:将数据整理成<好友1,用户1,用户2,用户3…..>

①使用mapper先将文件使用” : ”进行分割,得到的好友再用分割,接着将好友作为key,该用户作为value,有点类似于第1题,注意好友有多个,因此使用for循环将<好友1,用户1>作为输出写入context中;

Reducer接收到数据后将同一好友的value值使用进行合并,利用字符串处理,最后输出数据为<好友1,用户1,用户2,用户3…..>…..

阶段二:在阶段一的基础上将数据整理成<用户1-用户2,好友1,好友2,…..>

①使用mapper将数据中的keyvalue倒过来,并且注意将所有的用户利用for循环进行两两组合排列(用户1-用户2)作为输出的key,而原数据的key作为输出的value,即<用户1-用户2,好友1>

Reducer接收到数据后将同一组用户的value值使用进行合并,同样利用字符串处理,最后输出数据为<用户1-用户2,好友1,好友2,…..>…..

Map端程序:(给出map方法即可)

阶段一的Map端程序:

//取出一行数据,并将其分割

String[] strings = ivalue.toString().split(":");

String[] frineds = strings[1].split(",");//该用户的所有好友

for (String string : frineds) {

       //将好友作为key,该用户作为value输出

       context.write(new Text(string), new Text(strings[0]));

}

阶段二的Map端程序:

// 将数据以空格分割

String[] strings = ivalue.toString().split(" ");

String[] users = strings[1].split(";");           // 拥有该好友的所有用户

for (int i = 0; i < users.length; i++) {

         //将所有用户进行两两组合排列

       for (int j = i+1; j < users.length; j++) {

              // 将两个用户组合作为key,该好友作为value输出

             context.write(new Text(users[i].toString()+"-"+users[j].toString()), new Text(strings[0]));

       }                  

}

 

Reduce端程序:(给出reduce方法即可)

阶段一的Reduce端程序:

String value = "";

// 将同一好友的value值进行合并

for (Text val : values) {

       value += val.toString()+";";

}

context.write(_key, new Text(value));

阶段二的Reduce端程序:

// 将接收的数据中同一组用户的value值进行合并

String value = "";

for (Text val : values) {

       value += val.toString()+";";

}

context.write(_key, new Text(value));

 

Driver程序:(给出map输出和reduce输出设置即可)

阶段一的Driver程序:

//mapper的输出

job.setMapOutputKeyClass(Text.class);

job.setMapOutputValueClass(Text.class);

// reducer的输出

job.setOutputKeyClass(Text.class);

job.setOutputValueClass(Text.class);

阶段二的Driver程序:

//mapper的输出

job.setMapOutputKeyClass(Text.class);

job.setMapOutputValueClass(Text.class);

//reducer的输出

job.setOutputKeyClass(Text.class);

job.setOutputValueClass(Text.class);

 

 

猜你喜欢

转载自blog.csdn.net/qq_39672140/article/details/106878737
今日推荐