3.项目实现
用两个MR程序实现
第一个MR实现输出每个粉丝有哪些人关注了
public class SharedFriendsStepOne {
//写了一个主类,其余都用静态内部类实现,当然也可以不用内部类。
static class SharedFriendsStepOneMapper extends Mapper {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//原来数据 A:B,C,D,F,E,O
String line = value.toString();
String[] person_friends = line.split(":");
String person = person_friends[0];
String friends = person_friends[1];
for (String friend : friends.split(",")) { //多次切割
// 输出<好友,人>,以好友做k,一个人的所有好友分别做K,自己做v
context.write(new Text(friend), new Text(person));
}
}
}
//reducer端,如果不用静态内部类,要重写一个class。这里为了演示,通用内部类实现。
static class SharedFriendsStepOneReducer extends Reducer {
@Override
protected void reduce(Text friend, Iterable persons, Context context) throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text person : persons) {
sb.append(person).append(",");
}
context.write(friend, new Text(sb.toString()));
}
}
//Driver端实现。
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(SharedFriendsStepOne.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setMapperClass(SharedFriendsStepOneMapper.class);
job.setReducerClass(SharedFriendsStepOneReducer.class);
FileInputFormat.setInputPaths(job, new Path("D:/srcdata/friends"));
//当然这里可以用args[],控制台输入,更加了灵活多变
FileOutputFormat.setOutputPath(job, new Path("D:/temp/out"));
job.waitForCompletion(true);
}
}
输出的结果
部分数据展示: (默认kv的输出分隔符是\t)
A
I,K,C,B,G,F,H,O,D, //A后面的表示了哪些有A为好友粉丝的用户。这里没有排序。
B
A,F,J,E,
C
A,E,B,H,F,G,K
第二次MR,用之前的结果
public class SharedFriendsStepTwo {
static class SharedFriendsStepTwoMapper extends Mapper {
// 拿到的数据是上一个步骤的输出结果
// A I,K,C,B,G,F,H,O,D,
// 友 人,人,人
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] friend_persons = line.split("\t");
String friend = friend_persons[0];
String[] persons = friend_persons[1].split(",");
Arrays.sort(persons); //对persons进行排序,bc和 cb这样都是bc了。
//实现排列组合,即有A为好友的人任意两个都有共同好友,讲这些人排列组合。
for (int i = 0; i < persons.length - 1; i++) {
for (int j = i + 1; j < persons.length; j++) {
// 发出 <人-人,好友> ,这样,相同的“人-人”对的所有好友就会到同1个reduce中去
context.write(new Text(persons[i] + "---" + persons[j]), new Text(friend));
}
}
}
}
//第二次reducer端实现,对上面的输出进行聚合。即两个person_person的人有哪些好友,同K的v的。
static class SharedFriendsStepTwoReducer extends Reducer {
@Override
protected void reduce(Text person_person, Iterable friends, Context context) throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text friend : friends) {
sb.append(friend).append(",");
}
context.write(person_person, new Text(sb.toString()));
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(SharedFriendsStepTwo.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setMapperClass(SharedFriendsStepTwoMapper.class);
job.setReducerClass(SharedFriendsStepTwoReducer.class);
FileInputFormat.setInputPaths(job, new Path("D:/temp/out/part-r-00000"));
FileOutputFormat.setOutputPath(job, new Path("D:/temp/out2"));
job.waitForCompletion(true);
}
}
最后输出部分结果:
A---B
E,C,
A---C
D,F,
A---D
E,F,
A---E
D,B,C,
A---F
O,B,C,D,E,
A---G
F,E,C,D,
A---H
E,C,D,O,
A---I
O,
A---J
O,B,
A---K
D,C,
A---L
F,E,D,
A---M
E,F,
B---C
A,