六、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)));
}
}
}
運行結果:
本次教程就到次結束了,有什麼不懂的歡迎大家下方評論。博主都會幫你解答的。覺的寫的不錯的點個贊價格關注,多多支持。