MapReduce面试题1--求共同好友
1、数据格式
现有一份数据如下:
A:B,C,D,F,E,O
B:A,C,E,K
C:F,A,D,I
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
M:E,F,G
O:A,H,I,J,K
数据的格式以“:”分割成两部分,前面是用户,后面是该用户的好友,以
A:B,C,D,F,E,O
为例:B,C,D,E,F,O是用户A的好友
2、题目:求所有用户之间的共同好友
最后的结果格式如下:比如用户A和用户B之间有共同好友:C,E
那么显示的结果是:
A-B C E
3、解题思路分析
根据MapReduce的编程模型的特点,MapReduce编程分为Mapper阶段(任务的拆分)和Reducer阶段(结果的汇总)两个阶段。这两个阶段的业务逻辑,分别编写在Mapper组件的map方法和Reducer组件的reduce方法中。共同点,这两个阶段的业务逻辑方法都是接受key-value对,然后输出key-value对。
所以根据以上结果的格式,可以得知,reducer阶段输出的key-value中的key是A-B,value是C E,
那么value值(C E)怎么得来呢。?根据reduce(key,values,context)方法的特点得知,reduce方法其实接收到的参数是: key相同的一组key-value
也就意味着如果想得到
A-B C E
这样的数据,必先得到如下这样的数据:
A-B C
A-B E
以上这种格式的数据的含义是: C和E 是 A和B 的共同好友
现在再来解析单条数据, 以第一条为例子:
A-B C
表示,C是A用户和B用户的共同好友, 也就是说 C是A的好友, C是B的好友, 所以C 才是A和B的共同好友。
那也就表示,如果能得到以下这样的数据:
C A
C B
那在MapReduce程序中,就能得到
C A-B
然后倒过来不就是
A-B C
么。 完美。
那么现在的问题(代号q1)就变成怎么得到如下的数据了:
C A
C B
事实上,这种格式的数据表示: C是A的好友, C是B的好友。
倒过来不就是说: A有好友C,B有好友C么?
现在请看原始数据:
A:B,C,D,F,E,O
这行数据的意思不就是表示A用户有好友B,C,D,F,E,O么?那么拆开就是:
A B
A C
A D
A F
A E
A O
这就能得到,q1问题处想要得到的数据了。
4、具体代码实现
具体的代码实现得分成两个MapReduce来实现:
先看第一个MapReduce程序的实现:
package com.ghgj.mazh.mapreduce.exercise.friend;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class CommonFriends1MR {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(CommonFriends1MR.class);
job.setMapperClass(CommonFriends1MRMapper.class);
job.setReducerClass(CommonFriends1MRReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
Path inputPath = new Path("D:\\bigdata\\commonfriends\\input");
Path outputPath = new Path("D:\\bigdata\\commonfriends\\output_111");
FileSystem fs = FileSystem.get(conf);
if (fs.exists(outputPath)) {
fs.delete(outputPath, true);
}
FileInputFormat.setInputPaths(job, inputPath);
FileOutputFormat.setOutputPath(job, outputPath);
boolean res = job.waitForCompletion(true);
System.exit(res ? 0 : 1);
}
public static class CommonFriends1MRMapper extends Mapper<LongWritable, Text, Text, Text> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] tokens = line.split(":");
String person = tokens[0];
String[] friends = tokens[1].split(",");
for (String f : friends) {
context.write(new Text(f), new Text(person));
}
}
}
public static class CommonFriends1MRReducer extends Reducer<Text, Text, Text, Text> {
@Override
protected void reduce(Text friend, Iterable<Text> persons, Context context)
throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text p : persons) {
sb.append(p).append("-");
}
context.write(friend, new Text(sb.toString()));
}
}
}
该MapReduce输出的结果的格式:
A F-I-O-K-G-D-C-H-B-
B E-J-F-A-
C B-E-K-A-H-G-F-
D H-C-G-F-E-A-K-L-
E A-B-L-G-M-F-D-H-
F C-M-L-A-D-G-
G M-
H O-
I O-C-
J O-
K O-B-
L D-E-
M E-F-
O A-H-I-J-F-
这种格式的数据表明:key是value中的任意两个用户的共同好友
比如:
A F-I-O-K-G-D-C-H-B-
表示A是F和I的共同好友,A是F和O的共同好友,A是F和K的共同好友,............
还没有得到最终的结果,所以还需要一个MapReduce程序,来解析第一个MapReduce处理得到的结果数据,以得到最终的结果:
看具体代码实现:
package com.ghgj.mazh.mapreduce.exercise.friend;
import java.io.IOException;
import java.util.Arrays;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class CommonFriends2MR {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(CommonFriends2MR.class);
job.setMapperClass(CommonFriends2MRMapper.class);
job.setReducerClass(CommonFriends2MRReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
Path inputPath = new Path("D:\\bigdata\\commonfriends\\output_111");
Path outputPath = new Path("D:\\bigdata\\commonfriends\\last_output");
FileSystem fs = FileSystem.get(conf);
if (fs.exists(outputPath)) {
fs.delete(outputPath, true);
}
FileInputFormat.setInputPaths(job, inputPath);
FileOutputFormat.setOutputPath(job, outputPath);
boolean res = job.waitForCompletion(true);
System.exit(res ? 0 : 1);
}
public static class CommonFriends2MRMapper extends Mapper<LongWritable, Text, Text, Text> {
/**
* A I-K-C-B-G-F-H-O-D-
* B A-F-J-E-
* C A-E-B-H-F-G-K-
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] tokens = line.split("\t");
String friend = tokens[0];
String[] persons = tokens[1].split("-");
Arrays.sort(persons);
for (int i = 0; i < persons.length - 1; i++) {
for (int j = i + 1; j < persons.length; j++) {
context.write(new Text(persons[i] + "-" + persons[j]), new Text(friend));
}
}
}
}
public static class CommonFriends2MRReducer extends Reducer<Text, Text, Text, Text> {
@Override
protected void reduce(Text person_pair, Iterable<Text> friends, Context context) throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text f : friends) {
sb.append(f).append(" ");
}
context.write(person_pair, new Text(sb.toString()));
}
}
}
第二个MapReduce程序执行得到的结果:
A-B E C
A-C D F
A-D E F
A-E B C D
A-F C E O D B
A-G E F C D
A-H C D E O
A-I O
A-J O B
A-K C D
A-L F D E
A-M F E
B-C A
B-D A E
B-E C
B-F C A E
B-G E C A
B-H E C A
B-I A
B-K A C
B-L E
B-M E
B-O A K
C-D A F
C-E D
C-F A D
C-G A D F
C-H D A
C-I A
C-K A D
C-L D F
C-M F
C-O I A
D-E L
D-F A E
D-G E A F
D-H A E
D-I A
D-K A
D-L E F
D-M F E
D-O A
E-F D M C B
E-G C D
E-H C D
E-J B
E-K C D
E-L D
F-G D C A E
F-H A D O E C
F-I O A
F-J B O
F-K D C A
F-L E D
F-M E
F-O A
G-H D C E A
G-I A
G-K D A C
G-L D F E
G-M E F
G-O A
H-I O A
H-J O
H-K A C D
H-L D E
H-M E
H-O A
I-J O
I-K A
I-O A
K-L D
K-O A
L-M E F
以上的数据表示右边的value值就是左边的两个用户的共同好友。
至此,大功告成。ヾ(◍°∇°◍)ノ゙