MapReduce实现寻找共同好友

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
输出格式:
A-B:	C,E
...

2.思路

此题旨在求两人之间的共同好友,原信息是<人,该人的所有好友>,因此首先以好友为键,人为值,交给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


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值