MapReduce數據分析(6)共同好友

六、MapReduce第六講共同好友(Common friends)

某某社交網站,有如下用戶好友關係:

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,D,F,E,O

每行數據以冒號爲分隔符:

1、冒號左邊是網站的一個用戶A;
2、冒號右邊是用戶A的好友列表(各好友間以逗號爲分隔符);
現在,需要對網站的幾十億用戶進行分析,找出哪些用戶兩兩之間有共同好友,以及他倆的共同好友都有哪些人。比如,A、B兩個用戶擁有共同好友C和E;

最終統計的結果數據示意如下:

A-L F,E,D
A-M E,F B-C A
B-D A,E
B-E C

設計思路:
整個實驗過程需要寫兩個MapReduce程序來實現。
第一個job實現出來的結果是

B-C A
B-D A

該數據的意思是B和C用戶、B和D用戶都是A用戶的好友
第二個job實現出來的結果是

A-B E,C
A-C D,F
A-D E,F

該數據的意思是A和B的共同好友是E用戶,C用戶。

接下來我們開始寫第一個job類。
代碼如下:

package demo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;

public class demo{
	public static void main(String[] args) {
		
		Configuration conf=new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(demo.class);
		job.setMapperClass(MMapper.class);
		job.setReducerClass(MReduce.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}
	
	public static class MMapper extends Mapper<LongWritable, Text, Text, Text>{
		// 輸入數據形式如:      A:B,C,D,F,E,O
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			
			// 轉換數據類型並用:切割
			String[] line = value.toString().split(":");
			//得到數據中的用戶
			String user = line[0];
			String[] itmse = line[1].split(",");
			//得到數據中的好友
			for (String v : itmse) {
				//將每一個好友作爲key,用戶作爲value
				context.write(new Text(v), new Text(user));
			}
		}
		
	}
	public static class MReduce extends Reducer<Text, Text, Text, Text>{
		protected void reduce(Text key, Iterable<Text> value, Context context)
				throws IOException, InterruptedException {
			ArrayList<Text> arrayList = new ArrayList<Text>();
			// 將這一組擁有共同好友f的user們從迭代器中取出,放入一個arraylist暫存
			for (Text u : value) {
				arrayList.add(new Text(u));
			}
			//對users排個序,以免拼倆倆對時出現A-F 又有F-A的現象
			Collections.sort(arrayList);
			// 把這一對user進行兩兩組合,並將:
			//1.組合作爲key
			//2.共同的好友f作爲value
			//返回給reduce task作爲本job的最終結果
			for (int i = 0; i < arrayList.size()-1; i++) {
				for (int j = i+1; j <arrayList.size(); j++) {
					context.write(new Text(arrayList.get(i)+"-"+arrayList.get(j)), key);
				}
			}
		}
	}
}

運行結果:
在這裏插入圖片描述

下面我們開始寫第二個job

代碼如下;

package xxx;
import java.io.IOException;

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 demo{
	public static void main(String[] args) throws Exception {
		Configuration conf=new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(demo.class);
		job.setMapperClass(MMapper.class);
		job.setReducerClass(MReduce.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}
	
	public static class MMapper extends Mapper<LongWritable, Text, Text, Text>{
		// 輸入數據形式如:      A:B,C,D,F,E,O
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			// 將數據按製表符切分
			String[] line = value.toString().split("\t");
			// 將切出來的B-C用戶對作爲key,共同好友A作爲value
			// 返回給map task
			context.write(new Text(line[0]), new Text(line[1]));
		}
		
	}
	public static class MReduce extends Reducer<Text, Text, Text, Text>{
		protected void reduce(Text key, Iterable<Text> value, Context context)
				throws IOException, InterruptedException {
			// 構造一個StringBuilder用於拼接字符串
			StringBuffer sb = new StringBuffer();
			for (Text v : value) {
				// 將這個用戶對的所有共同好友拼接在一起
				sb.append(v).append(",");
			}
			//用戶對作爲key,拼接好的所有共同好友作爲value
			context.write(key, new Text(sb.substring(0,sb.length()-1)));
		}
	}
}

運行結果:
在這裏插入圖片描述

本次教程就到次結束了,有什麼不懂的歡迎大家下方評論。博主都會幫你解答的。覺的寫的不錯的點個贊價格關注,多多支持。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章