MapReduce运用之粉丝互粉

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40678969/article/details/79244523

项目名称:粉丝互粉

项目说明:如下所示,分别给出微博用户信息和其粉丝信息,如第一行:“:”左边的代表用户A,右边是关注A的粉丝。

用户和粉丝之间是单向关系,也即E是A的粉丝,但是A不一定是E的粉丝。

项目需求:用mapreduce找出两两之间有共同粉丝的用户对,及他俩的共同好友。如:A-B    C,E

           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

        需求解读:以为第一行为例进行说明:

      根据MapReduce的设置,给出的信息以文本的形式存放在一个InputPath处,在Map阶段通过RecoderReader中的read()方法每次读取文本信息的一行数据,并组装成K-V对传递给map方法,因此传入map的Key-in与Key-value分别是起始偏移量(LongWritable)和第一行的文本数据(Text):

       LongWritable   Key-in:key,Text value-in:value,

        第一次调用Map方法时的key-value="A:B,C,D,F,E,O";

       我们要找两两用户间的共同粉丝,不如先找出每个用户分别是谁的粉丝,如C是用户A,B,F,G,H,K的共同粉丝,然后再将A,B,F,G,H,K两两组合作为key-out,C作为value-out传送出去,那么reduce阶段框架自然会帮助我们将有着同一个key-out的value值组装为一个Iteratable形式的value-out,也就实现了我们的需求:找出了两两用户间的共同粉丝。

示例图:

 

示例代码:

Step1:

     

package com.itcast.bigdata.mr.fense2;

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 Step1 {
	
	//实现功能:将给出的原始文本整理成A(粉丝)	I,K,C,B,G,F,H,O,D(用户)的形式
	
	static class MyMapper extends Mapper<LongWritable, Text, Text, Text>{
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
		 //1.将TextValue转换成String类型并根据“:”split成数组,arr[0]代表用户,arr[1]代表粉丝字符串
			String[] arr = value.toString().split(":");
			String user = arr[0];
			String fenses = arr[1];
			
		//2.将粉丝字符串根据“,”split,并作为key-out传送出去,value-out就是user
			String[] fenses_arr = fenses.split(",");
			
			for(String fense:fenses_arr) {
				
				context.write(new Text(fense), new Text(user));
			}
		}
	}
	
	static class MyReduce 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 {
			
			//1.建立一个StringBuffer用来拼接value中的每个user
			StringBuffer sb = new StringBuffer();
			
			//2.遍历values,将遍历出来的值用sb拼装起来
			for(Text user:values) {
				sb.append(user.toString()).append(",");
			}
			
			//3.将粉丝作为key-out,拼装好的sb作为value-out传出
			context.write(key, new Text(sb.substring(0,sb.length()-1)));
		}
	}

	//驱动模板代码
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		//hadoop配置信息
		Configuration conf = new Configuration();
		
		//1.获得job对象并设置jar
		Job job = Job.getInstance(conf);
		job.setJarByClass(Step1.class);
		
		//2.设置MapClass和ReduceClass
		job.setMapperClass(MyMapper.class);
		job.setReducerClass(MyReduce.class);
		
		//3.设置Map的输出类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		//4.设置Reduce的输出类型
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		
		//5.声明FileInputPath和FileOutputPath
		FileInputFormat.setInputPaths(job, new Path("F:/Java教学视频/大数据学习资料/教学视频/day09 离线计算系统实战/day09/作业题/data.log"));
		FileOutputFormat.setOutputPath(job, new Path("F:/Java教学视频/大数据学习资料/教学视频/day09 离线计算系统实战/day09/作业题/res1.log"));
		
		//6.提交job
		job.waitForCompletion(true);
		
		
		
		
	}
}
step2:

    

package com.itcast.bigdata.mr.fense2;

import java.io.IOException;
import java.util.Arrays;

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;

import com.itcast.bigdata.mr.fense2.Step1.MyReduce;


public class Step2 {
	
	
	
	//根据Step1得出来的数据进一步整理成userCombiner,共同fense的形式
	static class MyMapper extends Mapper<LongWritable,Text, Text, Text>{
		
		
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			
			//1.将输入进来的value按照“\t”切分成数组,arr[0]是fense,arr[1]是users字符串
			String[]arr = value.toString().split("\t");
			String fense = arr[0];
			String[] users = arr[1].split(",");
			Arrays.sort(users);
			//2.遍历users,将其两两组合,作为key-out,将fense作为value-out
			      //以为I,K,C,B,G,F,H,O,D为例
			for(int i=0;i<users.length-1;i++) {
				 //I
				for(int j=i+1;j<users.length;j++) {
				 //K,C,B,G,F,H,O,D  组合为I-K I-C I-B I-G...
				
			//3.将拼接结果写出
				context.write(new Text(users[i]+"-"+users[j]),new Text(fense) );
				}
			}
			
		}
		
		static class MyReduce extends Reducer<Text, Text, Text, Text>{
			
			
			@Override
			protected void reduce(Text userCombine, Iterable<Text> fenses, Reducer<Text, Text, Text, Text>.Context context)
					throws IOException, InterruptedException {
				
				//提供一个字符串拼接工具
				StringBuffer sb = new StringBuffer();
			
				for(Text fense:fenses) {
					sb.append(fense.toString()).append(",");
				}
				context.write(userCombine, new Text(sb.substring(0,sb.length()-1)));
				
			}
		}
	}
	
	public static void main(String[] args) throws Exception {
		
		Configuration conf = new Configuration();
		
		Job job = Job.getInstance(conf);
		job.setJarByClass(Step2.class);
		
		job.setMapperClass(MyMapper.class);
		job.setReducerClass(MyReduce.class);
		
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		
		FileInputFormat.setInputPaths(job,new Path("F:/Java教学视频/大数据学习资料/教学视频/day09 离线计算系统实战/day09/作业题/res1.log/part-r-00000"));
		FileOutputFormat.setOutputPath(job, new Path("F:/Java教学视频/大数据学习资料/教学视频/day09 离线计算系统实战/day09/作业题/res2.log"));
		
		job.waitForCompletion(true);
		
	}
	
	

}




 最后结果:

    

A-B	E,C
A-C	D,F
A-D	E,F
A-E	D,B,C
A-F	O,B,C,D,E
A-G	F,E,C,D
A-H	E,C,D,O
A-I	O
A-J	O,B
A-K	D,C
A-L	F,E,D
A-M	E,F
B-C	A
B-D	A,E
B-E	C
B-F	E,A,C
B-G	C,E,A
B-H	A,E,C
B-I	A
B-K	C,A
B-L	E
B-M	E
B-O	A
C-D	A,F
C-E	D
C-F	D,A
C-G	D,F,A
C-H	D,A
C-I	A
C-K	A,D
C-L	D,F
C-M	F
C-O	I,A
D-E	L
D-F	A,E
D-G	E,A,F
D-H	A,E
D-I	A
D-K	A
D-L	E,F
D-M	F,E
D-O	A
E-F	D,M,C,B
E-G	C,D
E-H	C,D
E-J	B
E-K	C,D
E-L	D
F-G	D,C,A,E
F-H	A,D,O,E,C
F-I	O,A
F-J	B,O
F-K	D,C,A
F-L	E,D
F-M	E
F-O	A
G-H	D,C,E,A
G-I	A
G-K	D,A,C
G-L	D,F,E
G-M	E,F
G-O	A
H-I	O,A
H-J	O
H-K	A,C,D
H-L	D,E
H-M	E
H-O	A
I-J	O
I-K	A
I-O	A
K-L	D
K-O	A
L-M	E,F
   最后补充两点需要注意的地方:

    1.step1完成后会产生结果1:res1.log文件夹,里面的文件包括两个*.crc文件,请将这两个文件删除,否则在运行step2的时候

会报一个错:

         org.apache.hadoop.fs.ChecksumException: Checksum error: file:/F:/Java教学视频/大数据学习资料/教学视频/day09 离线计算系统实                 战/day09/作业题/res1.log/part-r-00000 at 0 exp:993346089 got: 1409847564

       那是因为Mapreduce自动在扫描InputPath的时候会检查文件里是不是含有crc文件,如果有它会进行一个验证,验证失败就提示                             Checksum error,如果你删除掉crc文件,就可以不用进行验证,也就不会有这个错了

 2.如果说在运行中出现越界异常,那么有可能是你的FileInputPath所指定的文件含有空格行,也被RecoderReader组件读到了,后面再用null调用方法,就爆出错误了。


  

  

   


   













展开阅读全文

没有更多推荐了,返回首页