Hadoop----MapReduce求共同好友

原文件

说明:
人物:好友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)

  • map端
  • 输入:
  • 输出:
  • reduce端
  • 输入:<一位好友,拥有该好友的所有人>
  • 输出:<人-人,一位共同好友>

第二阶段(KeyValueTextInputFormat)

  • map端:无处理
  • reduce端
  • 输入:<人-人,一位共同好友>
  • 输出:<人-人,所有共同好友>

数据示例:
A:B、C、D
B:A、C、D
C:A、B
第一阶段:
map端:

reduce端:

  • 输入: , , ,
  • 输出: , , ,

第二阶段:
map端:无变化
reduce端

  • 输入=第一阶段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端

  • 输入:<人,该人的所有好友>
  • 输出:<人-该人的一位好友,该人的另一位好友>
    reduce端
  • 输入:<人-该人的一位好友,该人的另一位好友>
  • 输出:<人-该人的一位好友,他们的共同好友>

数据示例:
A:B、C、D
B:A、C、D
C:A、B
D:A

map端:

  • 输入:< A , (B,C,D) >, < B , (A,C,D) >, < C , (A,B) >
  • 输出:<人-该人的一位好友 , 该人的另外一位好友>
  • < A-B , C >, < A-B , D > , < A-C , B > , < A-C , D > , < A-D , B > , < A-D , C >
  • < B-A , C >, < B-A , D > , < B-C , A > , < B-C , D > , < B-D , A > , < B-D , C >
  • < C-A , B >
  • < D-A , >

观察map端输出可以发现:key是人-该人的一位好友,value是该人的另外一位好友
接下来通过reduce端,会将key相同的value放到一起。
由此,可以想到,当key相同时,即两人是好友,此时value中,若出现重复值,则,该值为key中两人的共同好友。
即互相认识的两人的共同好友。
注意:
在输出到reduce时候,可以做一些处理,比如A-B和B-A,含义相同。
因此,可以按照ASC码值将B-A转换为A-B,即使ASC码值小的在前。

此时map端的输出为:

  • < A-B , C >, < A-B , D > , < A-C , B > , < A-C , D > , < A-D , B > , < A-D , C >
  • < A-B , C >, < A-B , D > , < B-C , A > , < B-C , D > , < B-D , A > , < B-D , C >
  • < A-C , B >
  • < A-D , >

reduce端:

  • 输入:
  • < A-B , C >, < A-B , D > , < A-C , B > , < A-C , D > , < A-D , B > , < A-D , C >
  • < A-B , C >, < A-B , D > , < B-C , A > , < B-C , D > , < B-D , A > , < B-D , C >
  • < A-C , B >
  • < A-D , >
  • 输出:
  • < A-B , ( C , D , C , D ) >
  • < A-C , ( B , D , B ) >
  • < A-D , ( B , C ) >

  • 根据以上输出可以看出:
    key相同时,在value中重复出现的值,为key中两两认识的两人的共同好友

代码示例:

/*
 * 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

你可能感兴趣的:(Hadoop)