1.需求
給出A-O個人中每個人的好友列表,求出哪些人兩兩之間有共同好友,以及他們的共同好友都有誰
原始文件:
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
輸出格式:
此題旨在求兩人之間的共同好友,原信息是<人,該人的所有好友>,因此首先以好友爲鍵,人爲值,交給reduce找出擁有此好友的所有人;再將這些人中兩兩配對作爲鍵,之前的鍵(好友)作爲值交給reduce去合併
簡而言之我打算分成兩個步驟,兩次迭代
1)求出每一個人都是哪些人的共同好友
2)把這些人(用共同好友的人)作爲key,其好友作爲value輸出
3.代碼
public class SharedFriend {
/*
第一階段的map函數主要完成以下任務
1.遍歷原始文件中每行<所有朋友>信息
2.遍歷“朋友”集合,以每個“朋友”爲鍵,原來的“人”爲值 即輸出<朋友,人>
*/
static class SharedFriendMapper01 extends Mapper<LongWritable, Text, Text, Text>{
@Override
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException {
String line = value.toString();
String[] person_friends = line.split(":");
String person = person_friends[0];
String[] friends = person_friends[1].split(",");
for(String friend : friends){
context.write(new Text(friend), new Text(person));
}
}
}
/*
第一階段的reduce函數主要完成以下任務
1.對所有傳過來的<朋友,list(人)>進行拼接,輸出<朋友,擁有這名朋友的所有人>
*/
static class SharedFriendReducer01 extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> values,Context context)
throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for(Text friend : values){
sb.append(friend.toString()).append(",");
}
sb.deleteCharAt(sb.length()-1);
context.write(key, new Text(sb.toString()));
}
}
/*
第二階段的map函數主要完成以下任務
1.將上一階段reduce輸出的<朋友,擁有這名朋友的所有人>信息中的 “擁有這名朋友的所有人”進行排序 ,以防出現B-C C-B這樣的重複
2.將 “擁有這名朋友的所有人”進行兩兩配對,並將配對後的字符串當做鍵,“朋友”當做值輸出,即輸出<人-人,共同朋友>
*/
static class SharedFriendMapper02 extends Mapper<LongWritable, Text, Text, Text>{
@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); //排序
//兩兩配對
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));
}
}
}
}
/*
第二階段的reduce函數主要完成以下任務
1.<人-人,list(共同朋友)> 中的“共同好友”進行拼接 最後輸出<人-人,兩人的所有共同好友>
*/
static class SharedFriendReducer02 extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> values,Context context)
throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
Set<String> set = new HashSet<String>();
for(Text friend : values){
if(!set.contains(friend.toString()))
set.add(friend.toString());
}
for(String friend : set){
sb.append(friend.toString()).append(",");
}
sb.deleteCharAt(sb.length()-1);
context.write(key, new Text(sb.toString()));
}
}
public static void main(String[] args)throws Exception {
Configuration conf = new Configuration();
//第一階段
Job job1 = Job.getInstance(conf);
job1.setJarByClass(SharedFriend.class);
job1.setMapperClass(SharedFriendMapper01.class);
job1.setReducerClass(SharedFriendReducer01.class);
job1.setOutputKeyClass(Text.class);
job1.setOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job1, new Path("H:/大數據/mapreduce/sharedfriend/input"));
FileOutputFormat.setOutputPath(job1, new Path("H:/大數據/mapreduce/sharedfriend/output"));
boolean res1 = job1.waitForCompletion(true);
//第二階段
Job job2 = Job.getInstance(conf);
job2.setJarByClass(SharedFriend.class);
job2.setMapperClass(SharedFriendMapper02.class);
job2.setReducerClass(SharedFriendReducer02.class);
job2.setOutputKeyClass(Text.class);
job2.setOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job2, new Path("H:/大數據/mapreduce/sharedfriend/output"));
FileOutputFormat.setOutputPath(job2, new Path("H:/大數據/mapreduce/sharedfriend/output01"));
boolean res2 = job2.waitForCompletion(true);
System.exit(res1?0:1);
}
}
4.輸出
1)第一階段輸出文件的內容
A I,K,C,B,G,F,H,O,D
B A,F,J,E
C A,E,B,H,F,G,K
D G,C,K,A,L,F,E,H
E G,M,L,H,A,F,B,D
F L,M,D,C,G,A
G M
H O
I O,C
J O
K B
L D,E
M E,F
O A,H,I,J,F
2)第二階段輸出文件的內容
A-B: C,E
A-C: D,F
A-D: E,F
A-E: B,C,D
A-F: B,C,D,E,O
A-G: C,D,E,F
A-H: C,D,E,O
A-I: O
A-J: B,O
A-K: C,D
A-L: D,E,F
A-M: E,F
B-C: A
B-D: A,E
B-E: C
B-F: A,C,E
B-G: A,C,E
B-H: A,C,E
B-I: A
B-K: A,C
B-L: E
B-M: E
B-O: A
C-D: A,F
C-E: D
C-F: A,D
C-G: A,D,F
C-H: A,D
C-I: A
C-K: A,D
C-L: D,F
C-M: F
C-O: A,I
D-E: L
D-F: A,E
D-G: A,E,F
D-H: A,E
D-I: A
D-K: A
D-L: E,F
D-M: E,F
D-O: A
E-F: B,C,D,M
E-G: C,D
E-H: C,D
E-J: B
E-K: C,D
E-L: D
F-G: A,C,D,E
F-H: A,C,D,E,O
F-I: A,O
F-J: B,O
F-K: A,C,D
F-L: D,E
F-M: E
F-O: A
G-H: A,C,D,E
G-I: A
G-K: A,C,D
G-L: D,E,F
G-M: E,F
G-O: A
H-I: A,O
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