说明:
人物:好友1、好友2......
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
解析:
第一阶段(TextInputFormat)
第二阶段(KeyValueTextInputFormat)
数据示例:
A:B、C、D
B:A、C、D
C:A、B
第一阶段:
map端:
reduce端:
第二阶段:
map端:无变化
reduce端
代码实现:
第一阶段:
/*
* Mapper
* 输入 <人,该人的所有好友>
* 输出 <该人的一位好友,人>
*/
public class Mapper01 extends Mapper<LongWritable ,Text,Text,Text>{
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
throws IOException, InterruptedException {
// TODO Auto-generated method stub
StringTokenizer str1 = new StringTokenizer(value.toString(),":");
//取到人
Text name = new Text(str1.nextToken());
StringTokenizer str2 = new StringTokenizer(str1.nextToken(),",");
while(str2.hasMoreTokens()){
//该人对应的一位好友
Text friend = new Text(str2.nextToken());
//输出:<人,该人的一位好友>
context.write(friend, name);
}
}
}
输出结果:
A I
A K
A C
A B
A G
A F
A H
A O
A D
B A
B F
B J
B E
C A
C E
C B
C H
C F
C G
C K
D G
D C
D K
D A
D L
D F
D E
D H
E G
E M
E L
E H
E A
E F
E B
E D
F L
F M
F D
F C
F G
F A
G M
H O
I O
I C
J O
K B
L D
L E
M E
M F
O A
O H
O I
O J
O F
/*
* Reducer
* 输入 <一位好友,拥有该好友的所有人)>
* 输出 <人-人,一位好友>
*/
public class Reducer01 extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> value, Reducer<Text, Text, Text, Text>.Context context)
throws IOException, InterruptedException {
// TODO Auto-generated method stub
ArrayList<Text> a = new ArrayList<Text>();
for(Text name:value){
Text n = new Text(name.toString());
a.add(n);
}
for(int i=0;i<a.size();i++){
for(int j=i+1;j<a.size();j++){
Text t = new Text();
Text x = a.get(i);
Text y = a.get(j);
//按照字母表顺序排序(即按照ASC码)
if(x.toString().charAt(0)>y.toString().charAt(0)){
t=x;
x=y;
y=t;
}
context.write(new Text(x+"-"+y), key);
}
}
}
}
输出结果:
I-K A
C-I A
B-I A
G-I A
F-I A
H-I A
I-O A
D-I A
C-K A
B-K A
G-K A
F-K A
H-K A
K-O A
D-K A
B-C A
C-G A
C-F A
C-H A
C-O A
C-D A
B-G A
B-F A
B-H A
B-O A
B-D A
F-G A
G-H A
G-O A
D-G A
F-H A
F-O A
D-F A
H-O A
D-H A
D-O A
A-F B
A-J B
A-E B
F-J B
E-F B
E-J B
A-E C
A-B C
A-H C
A-F C
A-G C
A-K C
B-E C
E-H C
E-F C
E-G C
E-K C
B-H C
B-F C
B-G C
B-K C
F-H C
G-H C
H-K C
F-G C
F-K C
G-K C
C-G D
G-K D
A-G D
G-L D
F-G D
E-G D
G-H D
C-K D
A-C D
C-L D
C-F D
C-E D
C-H D
A-K D
K-L D
F-K D
E-K D
H-K D
A-L D
A-F D
A-E D
A-H D
F-L D
E-L D
H-L D
E-F D
F-H D
E-H D
G-M E
G-L E
G-H E
A-G E
F-G E
B-G E
D-G E
L-M E
H-M E
A-M E
F-M E
B-M E
D-M E
H-L E
A-L E
F-L E
B-L E
D-L E
A-H E
F-H E
B-H E
D-H E
A-F E
A-B E
A-D E
B-F E
D-F E
B-D E
L-M F
D-L F
C-L F
G-L F
A-L F
D-M F
C-M F
G-M F
A-M F
C-D F
D-G F
A-D F
C-G F
A-C F
A-G F
C-O I
D-E L
E-F M
A-H O
A-I O
A-J O
A-F O
H-I O
H-J O
F-H O
I-J O
F-I O
F-J O
public class Driver01 {
public static void main(String[] args) throws Exception, Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "commonfriends");
job.setJarByClass(Driver01.class);
job.setMapperClass(Mapper01.class);
job.setReducerClass(Reducer01.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path("E:/commonfriends/input/*"));
FileOutputFormat.setOutputPath(job, new Path("E:/commonfriends/output2"));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
第二阶段:
map端默认
/*
* Reducer
* 输入 <人-人,一位共同好友>
* 输出 <人-人,所有共同好友>
*/
public class Reducer02 extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> value, Reducer<Text, Text, Text, Text>.Context context)
throws IOException, InterruptedException {
// TODO Auto-generated method stub
String str = "";
for(Text people:value){
str+=people.toString();
}
context.write(key, new Text("\t"+str));
}
}
输出结果:
A-B CE
A-C DF
A-D FE
A-E BDC
A-F CBODE
A-G FDEC
A-H DOEC
A-I O
A-J OB
A-K DC
A-L EDF
A-M FE
B-C A
B-D EA
B-E C
B-F EAC
B-G CAE
B-H ECA
B-I A
B-K CA
B-L E
B-M E
B-O A
C-D FA
C-E D
C-F DA
C-G DFA
C-H AD
C-I A
C-K DA
C-L DF
C-M F
C-O IA
D-E L
D-F AE
D-G EAF
D-H EA
D-I A
D-K A
D-L EF
D-M EF
D-O A
E-F BMDC
E-G DC
E-H DC
E-J B
E-K DC
E-L D
F-G CDAE
F-H AEOCD
F-I OA
F-J OB
F-K ACD
F-L ED
F-M E
F-O A
G-H ADEC
G-I A
G-K CAD
G-L FDE
G-M FE
G-O A
H-I AO
H-J O
H-K ADC
H-L DE
H-M E
H-O A
I-J O
I-K A
I-O A
K-L D
K-O A
L-M FE
public class Driver02 {
public static void main(String[] args) throws Exception, Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "commonfriends");
//设置输入格式
job.setInputFormatClass(KeyValueTextInputFormat.class);
job.setJarByClass(Driver02.class);
job.setMapperClass(Mapper02.class);
job.setReducerClass(Reducer02.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path("E:/commonfriends/output2/part-r-00000"));
FileOutputFormat.setOutputPath(job, new Path("E:/commonfriends/output3"));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
解析:
map端
数据示例:
A:B、C、D
B:A、C、D
C:A、B
D:A
map端:
观察map端输出可以发现:key是人-该人的一位好友,value是该人的另外一位好友
接下来通过reduce端,会将key相同的value放到一起。
由此,可以想到,当key相同时,即两人是好友,此时value中,若出现重复值,则,该值为key中两人的共同好友。
即互相认识的两人的共同好友。
注意:
在输出到reduce时候,可以做一些处理,比如A-B和B-A,含义相同。
因此,可以按照ASC码值将B-A转换为A-B,即使ASC码值小的在前。
此时map端的输出为:
reduce端:
代码示例:
/*
* Mapper
* 输入 <人,该人的所有好友>
* 输出 <人-该人的一位好友,该人的另一位好友>
*/
public class Mapper01 extends Mapper<LongWritable ,Text,Text,Text>{
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
throws IOException, InterruptedException {
// TODO Auto-generated method stub
StringTokenizer str1 = new StringTokenizer(value.toString(),":");
//取到人
String name = str1.nextToken();
//将该人的所有好友放到一个数组
String[] str2 = str1.nextToken().split(",");
//将数组转换为集合
ArrayList<String> a1 = new ArrayList<String>(Arrays.asList(str2));
//定义变量pf来作为key
String pf = null;
for(String s1 : a1){
ArrayList<String> a2 = new ArrayList<String>(Arrays.asList(str2));
//将拼接了的好友移出集合
//注意:一定先进行移除,再交换
a2.remove(s1);
//定义一个变量接收之前获取到的name的值,再进行操作,否则,直接操作name,数据会出错。
String nametmp = name;
//根据ASC码值进行排序,便于之后操作
if(nametmp.toString().charAt(0)>s1.toString().charAt(0)){
String tmp;
tmp = nametmp;
nametmp = s1;
s1 = tmp;
//人-该人的一位好友
pf = nametmp+"-"+s1;
}else{
pf = nametmp+"-"+s1;
}
//遍历集合a2,找到剩下的好友
if(a2.size()!=0){
for(String s2 : a2){
//输出:<人-该人的一位好友,该人的另一位好友>
context.write(new Text(pf), new Text(s2));
}
}else{
context.write(new Text(pf), new Text(""));
}
}
}
}
输出结果:
A-B C
A-B F
A-B D
A-B C
A-B E
A-B O
A-B K
A-B E
A-C I
A-C D
A-C F
A-C F
A-C E
A-C O
A-C B
A-C D
A-D L
A-D B
A-D C
A-D F
A-D E
A-D O
A-D E
A-D F
A-E B
A-E D
A-E F
A-E O
A-E C
A-F D
A-F E
A-F M
A-F B
A-F C
A-F D
A-F C
A-F B
A-F O
A-F O
A-F E
A-G F
A-G D
A-G C
A-G E
A-H C
A-H D
A-H E
A-H O
A-I O
A-K D
A-K C
A-O I
A-O H
A-O E
A-O F
A-O D
A-O C
A-O B
A-O J
B-C K
B-C E
B-C A
B-E A
B-E C
B-E K
B-E C
B-E D
B-E M
B-E L
B-F O
B-F M
B-F E
B-F D
B-F C
B-F A
B-J O
B-K C
B-K E
B-K A
C-D F
C-D A
C-D I
C-E B
C-E D
C-E M
C-E L
C-F D
C-F M
C-F O
C-F E
C-F B
C-F A
C-F I
C-F D
C-F A
C-G F
C-G E
C-G D
C-G A
C-H O
C-H E
C-H D
C-H A
C-I D
C-I F
C-I A
C-K A
C-K D
D-E C
D-E M
D-E L
D-E A
D-E F
D-E L
D-E B
D-F C
D-F B
D-F A
D-F L
D-F E
D-F A
D-F M
D-F O
D-F E
D-G A
D-G F
D-G E
D-G C
D-H C
D-H A
D-H O
D-H E
D-K A
D-K C
D-L F
D-L F
D-L E
D-L A
D-L E
E-F O
E-F B
E-F A
E-F D
E-F C
E-F M
E-G A
E-G D
E-G C
E-G F
E-H O
E-H A
E-H D
E-H C
E-L D
E-L M
E-L D
E-L F
E-L C
E-L B
E-M F
E-M D
E-M L
E-M B
E-M C
E-M G
F-G E
F-G D
F-G C
F-G A
F-L E
F-L D
F-M A
F-M B
F-M C
F-M E
F-M G
F-M E
F-M D
F-M O
F-O E
F-O M
F-O D
F-O C
F-O B
F-O A
G-M E
G-M F
H-O C
H-O J
H-O A
H-O I
H-O E
H-O D
H-O A
I-O H
I-O A
I-O A
I-O J
J-O I
J-O B
J-O A
J-O H
/*
* Reducer
* 输入 <人-该人的一位好友,key中两人除彼此之外的所有好友>
* 输出 <人-该人的一位好友,他们的共同好友>
*/
public class Reducer01 extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> value, Reducer<Text, Text, Text, Text>.Context context)
throws IOException, InterruptedException {
// TODO Auto-generated method stub
//迭代器去对value进行遍历
Iterator<Text> it = value.iterator();
//定义一个变量来接收遍历出来的好友
String str = "" ;
while(it.hasNext()){
str += it.next().toString();
}
//将遍历出来的好友放到一个字符数组
char[] ch = str.toCharArray();
//定义一个map集合,来存放<好友,标识符>
Map<Character,Integer> map = new HashMap<Character,Integer>();
for(char c : ch){
//判断map数组中是否存在,如果存在,则根据key取得value进行累加值,从而标识出共同好友
if(map.get(c)==null){
map.put(c, 1);
}else{
//定义一个累加器,来标识出共同好友
Integer count = map.get(c);
count++;
map.put(c, count);
}
}
String comfriend="";
//定义一个set集合,存储map集合的key值,便于之后对map集合的遍历
Set<Character> s = map.keySet();
//遍历map集合,找出value=2的key,即共同好友
Iterator<Character> it1 = s.iterator();
while(it1.hasNext()){
Character friend = it1.next();
if(map.get(friend)==2){
comfriend += friend;
}
}
System.out.println("=======================");
if(comfriend!=""){
context.write(key, new Text(comfriend));
System.out.println("------");
}
}
}
输出结果:
A-B CE
A-C DF
A-D EF
A-F BCDEO
B-E C
C-F AD
D-E L
D-F AE
D-L EF
E-L D
F-M E
H-O A
I-O A
public class Driver01 {
public static void main(String[] args) throws Exception, Exception {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path path = new Path("E:/commonfriends/output5");
if(fs.exists(path)){
fs.delete(path);
}
Job job = Job.getInstance(conf, "commonfriends");
job.setJarByClass(Driver01.class);
job.setMapperClass(Mapper01.class);
job.setReducerClass(Reducer01.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path("file:///E:/commonfriends/input/*"));
FileOutputFormat.setOutputPath(job, new Path("E:/commonfriends/output5"));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
https://blog.csdn.net/qq_39192827/article/details/90393284