MapReduce找共同好友

本文介绍了一种使用MapReduce算法来找出社交网络中具有共同好友的用户对的方法。通过两个阶段的MapReduce作业,首先识别可能的好友对,然后确认实际的共同好友。此方案适用于大数据环境下的社交网络分析。

一、在网上找的题,就拿来做了

mapreduce笔试题: 找出有共同好友的users

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 
A,C D,F 
A,D F,E 
A,F B,C,D,E,O
B,E C
C,F A,D 
D,E L
D,F A,E 
D,L E,F 
E,L D
F,M E
H,O A

二、代码部分

package com.wangs.jun;


import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


import org.apache.hadoop.conf.Configuration;
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 FindFriends {
	/**
	 * A:B,C,D
			 * B:A C:A D:A
		 */
	public static class M1 extends Mapper<LongWritable, Text, Text, Text> {
		@Override
		protected void map(LongWritable key, Text value,
				Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			String[] split = value.toString().replaceAll(":", ",").split(",");
			if (split.length > 0) {
				Text v = new Text(split[0]);
				Text k = new Text();
				for (int i = 1; i < split.length; i++) {// 不能从0开始,因为0是值
					k.set(split[i]);
					context.write(k, v);
				}
			}
		}
	}


	/**
	 * B:A , B:M, B,F
		 * A,M:B A,F:B M,F:B A,B:1
		 */
	public static class R1 extends Reducer<Text, Text, Text, Text> {


		@Override
		protected void reduce(Text key, Iterable<Text> values,
				Reducer<Text, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			List<String> f = new ArrayList<>();// A,M,F
			for (Text s : values) {
				f.add(s.toString());
			}
			String[] ss = f.toArray(new String[0]);
			for (int i = 0; i < ss.length; i++) {// M
				String s1 = ss[i];
				for (int j = 0; j < ss.length; j++) {// F
					String s2 = ss[j];
					if (!s1.equals(s2) && s1.compareTo(s2) < 0) {
						context.write(new Text(s1 + "," + s2), key);
					}
				}


				String ff = s1 + "," + key.toString();// M,B
				if (s1.compareTo(key.toString()) > 0) {// B,M:1
					ff = key.toString() + "," + s1;
				}
				context.write(new Text(ff), new Text("1"));
			}
		}
	}


	/**
	 * A,M:B A,M:C A,M:1
			 * @author liuxing
		 */
	public static class M2 extends Mapper<LongWritable, Text, Text, Text> {
		@Override
		protected void map(LongWritable key, Text value,
				Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			String[] split = value.toString().split("\t");
			context.write(new Text(split[0]), new Text(split[1]));
		}
	}


	// A,M:B,C,1,1
	public static class R2 extends Reducer<Text, Text, Text, Text> {


		@Override
		protected void reduce(Text key, Iterable<Text> values,
				Reducer<Text, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			int count = 0;
			List<String> s = new ArrayList<>();
			for (Text t : values) {
				if ("1".equals(t.toString()))
					count += 1;
				else {
					s.add(t.toString());
				}
			}
			if (count == 2 && s.size() > 0) {
				StringBuffer sb = new StringBuffer();
				for (String ss : s) {
					sb.append(",").append(ss);
				}
				context.write(key, new Text(sb.substring(1).toString()));
			}
		}
	}
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(FindFriends.class);


		job.setMapperClass(M1.class);
		job.setReducerClass(R1.class);


		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);


		FileInputFormat.setInputPaths(job, new Path(args[0]));
		Path path = new Path(args[1]);


		FileOutputFormat.setOutputPath(job, path);
		boolean b = job.waitForCompletion(true);


		if (b) {
			Job job2 = Job.getInstance(conf);
			job2.setJarByClass(FindFriends.class);
			job2.setMapperClass(M2.class);
			job2.setReducerClass(R2.class);


			job2.setOutputKeyClass(Text.class);
			job2.setOutputValueClass(Text.class);


			FileInputFormat.setInputPaths(job2, new Path(args[1]));
			Path path2 = new Path(args[2]);


			FileOutputFormat.setOutputPath(job2, path2);


			job2.waitForCompletion(true);
		}
	}
}



### 使用MapReduce实现共同好友算法 #### 算法概述 为了到社交网络中任意两个用户的共同好友,在MapReduce框架内可以设计一种高效的解决方案。该方案主要分为两步:第一步是构建用户及其朋友关系的键值对;第二步是在这些键值对的基础上共同好友。 #### 数据准备 假设有一个简单的社交图谱,其中包含若干个用户以及他们之间的友谊连接。数据集可能看起来像这样: ``` Alice Bob Bob Alice Alice Charlie Charlie Alice Bob Dave ... ``` 每一行表示一对互为好友的关系。 #### Mapper阶段 Mapper的任务是从原始的朋友关系记录中提取出所有可能的用户组合,并将其作为键值对输出。对于每一个`(User, Friend)`对,生成所有的`(Friend, User)`对,从而确保每个用户与其他所有已知联系人都能形成配对[^1]。 ```java public class CommonFriendsMapper extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] friendsPair = value.toString().split("\\s+"); if(friendsPair.length != 2){ return; } String userA = friendsPair[0]; String userB = friendsPair[1]; // 输出 (friendship pair, 1), e.g., ("Alice_Bob", 1) context.write(new Text(userA + "_" + userB), one); // 反转 friendship pairs 并再次写入以捕捉双向关系 context.write(new Text(userB + "_" + userA), one); } } ``` #### Reducer阶段 Reducer接收来自Mapper的所有`(Friend_Pair, Count)`形式的输入项。如果某个`Friend_Pair`出现了两次,则意味着这两个成员之间存在直接关联之外还有其他公共朋友。此时就可以统计出这对成员共有多少位共同好友[^3]。 ```java import java.util.HashSet; public class CommonFriendsReducer extends Reducer<Text, IntWritable, Text, IntWritable> { HashSet<String> seenPairs = new HashSet<>(); @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int count = 0; boolean isNewPair = false; for(IntWritable val : values){ ++count; // 如果这个pair只出现了一次说明这是首次遇到它或者是自反情况下的重复计数 if(!seenPairs.contains(key)){ isNewPair = true; }else{ // 已经见过一次了,现在又见到了第二次,那么这就是我们要的那种有共同朋友的情况 break; } } if(isNewPair && count >= 2){ // 记录已经处理过的pairs防止后续重复计算 seenPairs.add(key); context.write(key, new IntWritable(count)); } } } ``` 上述代码片段展示了如何使用MapReduce来识别具有至少一位共同好友的不同用户对。需要注意的是实际应用时还需要考虑更多细节比如去除自我循环等问题[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值