通过Hadoop框架下MapReduce来实现查找共同好友和共同课程的问题

1 设计要求
上图为部分学生的公共选修课选课表,每一行代表一个学生和他的选课列表。需要求出哪些人两两之间有共同选修课,以及他俩的共同选修课有哪些课。需求就是求出哪些人两两之间有共同选修课,以及他俩的共同选修课有哪些课,在Hadoop和eclipse上进行文档的输出。
1.1 功能要求
Hadoop框架的广泛性,大多数的电脑都可以使用,HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
1.2 架构要求
使用cmd命令进行相关的键入和输出,使用的主要框架是Hadoop框架和eclipse软件进行代码的编写。
1.3 性能要求
Hadoop处理数据的速度非常快而且Hadoop按位存储和处理数据的能力非常可靠。
(对应的共同好友问题也是如此)

2 hadoop下载、安装与配置
1)hadoop2.7.2下载与安装

  1. http://hadoop.apache.org/ 网站上找到 2.7.2版本的下载地址:
    https://archive.apache.org/dist/hadoop/common/hadoop-2.7.2/
    下载压缩文件:
    1.执行文件 hadoop-2.7.2.tar.gz
  1. 源代码文件:hadoop-2.7.2-src.tar.gz (可选)
    2) 解压hadoop-2.7.2.tar.gz文件到指定目录下 比如在C盘创建一个目录都可以
    3 hadoop-common(用于Windows环境上运行)下载解压与复制
  1. 下载: https://github.com/srccodes/hadoop-common-2.2.0-bin/archive/master.zip
    注意:该网站的下载的版本中,最关键的两个文件hadoop.dll和winutils.exe 和hadoop-2.7.2 不匹配,需要从CSDN上下载匹配的版本,下面的压缩包已经验证过:
    2)解压该包,形成文件如下:
    在这里插入图片描述

3)复制上述7个文件到: C:\zl\hadoop-2.7.2\bin下。
4)复制hadoop.dll和winutils.exe到: C:\Windows\System32下。(这里注意一定要导入到相关的目录下面否则在后期程序运行的时候会出现Hadoop的错误)
JDK的下载安装和配置的多余步骤这里就不作多余的解释,需要的可以私聊我。
3)hadoop环境变量设置

  1. HADOOP_HOME 设置
    配置你安装的路径即可

  2. CLASSPATH 设置
    新建classpath变量
    内容:%HADOOP_HOME%\bin;%HADOOP_HOME%\lib;(注意这个引号的形式应该是英文形式的,否则输入之后会报错)
    4)hadoop参数配置
    进入C:\wh\hadoop-2.7.2\etc\hadoop目录,找到
    1)Hadoop-env.cmd 配置,该文件主要用于设置Hadoop和Yarn的的环境变量。
    打开该文件,在文件末位增加:

set JAVA_HOME=C:\Java\jdk1.8.0_92
set HADOOP_HOME=C:\wh\hadoop-2.7.2
set HADOOP_PREFIX=C:\wh\hadoop-2.7.2
set HADOOP_CONF_DIR=%HADOOP_PREFIX%\etc\hadoop
set YARN_CONF_DIR=%HADOOP_CONF_DIR%
set PATH=%PATH%;%HADOOP_PREFIX%\bin

2)core-site.xml 配置: 该文件主要用于namenode的IP地址和端口

<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://0.0.0.0:19000/</value>   (0.0.0.0表示本机地址)
</property>
</configuration>

3)hdfs-site.xml 配置

<configuration>
	<property>
		<name>dfs.replication</name>  (数据的副本数)
		<value>1</value> 
	</property>
	<property>
	    <name>dfs.namenode.name.dir</name>
		<value>file:/C:/wh/txtfile/namenodedata</value> 
	</property>
	<property>
	    <name>dfs.datanode.data.dir</name>
		<value>file:/C:/wh/txtfile/datanodedata</value> 
	</property>
</configuration>

4)mapred-site.xml的配置,配置mapreduce框架相关的位置

<configuration>
<property>
	<name>mapreduce.job.user.name</name>
	<value>%USERNAME%</value>
</property>
<property>
	<name>mapreduce.framework.name</name>
	<value>yarn</value>
</property>
<property>
	<name>yarn.apps.stagingDir</name>
	<value>/user/%USERNAME%/staging</value>
</property>
<property>
	<name>mapreduce.jobtracker.address</name>
	<value>local</value>
</property>

</configuration>
  1. yarn-site.xml的配置
<configuration>
<property>
	<name>yarn.server.resourcemanager.address</name>
	<value>0.0.0.0:8020</value>
</property>
<property>
	<name>yarn.server.resourcemanager.application.expiry.interval</name>
	<value>60000</value>
</property>
<property>
	<name>yarn.server.nodemanager.address</name>
	<value>0.0.0.0:45454</value>
</property>
<property>
	<name>yarn.nodemanager.aux-services</name>
	<value>mapreduce_shuffle</value>
</property>
<property>
	<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
	<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<property>
	<name>yarn.server.nodemanager.remote-app-log-dir</name>
	<value>/app-logs</value>
</property>
<property>
	<name>yarn.nodemanager.log-dirs</name>
	<value>/dep/logs/userlogs</value>
</property>

<property>
	<name>yarn.server.mapreduce-appmanager.attempt-listener.bindAddress</name>
	<value>0.0.0.0</value>
</property>
<property>
	<name>yarn.server.mapreduce-appmanager.client-service.bindAddress</name>
	<value>0.0.0.0</value>
</property>
<property>
	<name>yarn.log-aggregation-enable</name>
	<value>true</value>
</property>
<property>
	<name>yarn.log-aggregation.retain-seconds</name>
	<value>1</value>
</property>
<property>  
       <name>yarn.application.classpath</name>       <value>%HADOOP_CONF_DIR%,%HADOOP_COMMON_HOME%/share/hadoop/common/*,%HADOOP_COMMON_HOME%/share/hadoop/common/lib/*,%HADOOP_HDFS_HOME%/share/hadoop/hdfs/*,%HADOOP_HDFS_HOME%/share/hadoop/hdfs/lib/*,%HADOOP_MAPRED_HOME%/share/hadoop/mapreduce/*,%HADOOP_MAPRED_HOME%/share/hadoop/mapreduce/lib/*,%HADOOP_YARN_HOME%/share/hadoop/yarn/*,%HADOOP_YARN_HOME%/share/hadoop/yarn/lib/*</value>  
</property>  
</configuration>

3、hadoop 格式化与启动
1) 切换到hadoop目录下
etc/hadoop
2) 运行hadoop-env.cmd脚本

3) 格式化HDFS文件系统
运行 %HADOOP_PREFIX%\bin\hdfs namenode -format 命令,格式化hadoop文件系统
(注意:如果已经格式化,系统会提示是否重新格式化。 这步操作不是每次必须执行的,执行过一次就行了,以后再启动hadoop时候,不需要执行这一步操作。)
4)启动HDFS
运行%HADOOP_PREFIX%\sbin\start-dfs.cmd ,启动hadoop文件系统
在这里插入图片描述
(弹出两个窗口,中间没有shut down代表着Hadoop运行起来了)
5) 启动yarn

  1. 运行 yarn-env.cmd
    执行 %HADOOP_PREFIX%\sbin\start-yarn.cmd
  2. 执行成功后,两个窗口:resourcemanager和 nodemanager
    在这里插入图片描述
    6) 关闭hadoop系统
    运行 %HADOOP_PREFIX%\sbin\stop-all.cmd
    在这里插入图片描述
    4、hadoop 的命令的使用
    1) 在HDFS创建zlhadoop目录,操作命令如下:
    hdfs dfs -mkdir /zlhadoop(这个随意创建不一定要用这个目录,最终都是会在eclipse下显示出来的)
    在这里插入图片描述
    2)在hdfs 查看当前目录,操作命令如下:
    hdfs dfs –ls [文件目录]
    hdfs dfs -ls -R / //显式目录结构
    在这里插入图片描述
  3. 将本地文件存储至hadoop
    hdfs dfs –put [本地地址] [hadoop目录]
    在这里插入图片描述
    在这里不需要输入.txt文件的扩展名点开就可以看到这是一个txt文件
    (在这里不需要输入.txt文件的扩展名点开就可以看到这是一个txt文件)
  4. 下载和安装Eclipse及插件
    1)从http://www.eclipse.org/downloads/ 网站上下载eclipse-inst-win64.exe (32位下载eclipse-inst-win32.exe)文件,并安装java 或者java ee 开发环境
  5. 从CSDN下查找和下载下载hadoop的eclipse插件hadoop-eclipse-plugin-2.7.2.jar,,并解压/复制到eclipse的dropins(注意:不是plugins)目录下。
  6. 重启eclipse,并设置hadoop安装路径**(如果找不安装目录的话可以选中程序右键查看属性可以直接就可以查看目录了)**
    eclipse的Window->Preferences进入进行设置,如下图
    在这里插入图片描述
  7. 把map\reduce设置窗口调出显示,方便设置Window->Show View->Other找到Map/Reduce Locations,单击‘Open’打开。
    经过上面步骤后,在eclipse下面会显示如下(默认是没有下面那行hadoop1 localhost的,我这里因为已经设置了):
    在这里插入图片描述
    单击带+号的大象图标,就可以进入设置界面了
    在这里插入图片描述
    这一步的设置是最容易出错的地方,我在前面配置文件中提到,只有hdfs文件系统的端口设置为19000了,其他的都是默认的,那么怎么知道我上面应该配置的是50010呢?很多时候,hadoop配置时可能显示可能是50020、50030等,这时候我们可以去看一下启动的hadoop窗口了,有一个namenode窗口,上面显示了我们要配置的这两个端口号。
    在namenode会看到19000端口:作为DFS Master的端口设置
    在这里插入图片描述
    在namenode会看到5100端口:作为Map/Reduce(V2) Master的端口设置
    在这里插入图片描述
    4、在hdfs上根据需要创建文件夹,可以创建、删除、上传文件和文件夹,这里的操作实际上是对hdfs文件系统的操作(你也可以到命令窗口操作,在HADOOP_HOME\bin目录下运行hdfs dfs -mkdir命令可以创建目录)
    在这里插入图片描述
    6、Hadoop/mapReduce编程操作
    1、创建map/reduce工程duo_MapReduce

在这里插入图片描述

2、新建类StepFirst和StepSecond


5 实验步骤代码解释
5.1 将数据加载到hadoop的平台,在导入到eclipse的Hadoop1当中  
hdfs dfs -mkdir /invert  先创建在hadoop创建一个invert文件  
hdfs dfs -put D:/cloudtest/fr3.txt /invert  成功的导入到Hadoop的平台和eclipse的Hadoop1当中

5.2 将选课的原始数据进行相关的切割,并且进行相关的拼接
<1>map1
protected void map(LongWritable key, Text value,Mapper<LongWritable, Text, Text, Text>.Context context)throws IOException, InterruptedException 
String line = value.toString();//传入的value 12018001:。。。。,吧value转换为字符串,line表示行数据,就为学号
String[] arr = line.split(":");//分割字符串
最后进行循环便遍历,以<科目,学号>的形式进行输出 这是第一个map所作的事情
<2>reduce1
protected void reduce(Text friend, Iterable<Text> users,Context context)throws IOException, InterruptedException {
			StringBuffer buf = new StringBuffer();//上面是传入数据,下面是建立一个buffer来存放有该科目的学号们
			for (Text user : users) {
				buf.append(user).append(",");//遍历学号,将学号放在buffer中,“,”分割
			}
			context.write(new Text(friend), new Text(buf.toString()));
		}
最后进行循环遍历,科目为key,学号为value进行输出,样式为   科目  学号1,学号2,学号3
<3>main主函数
public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);//实例化job
		job.setJarByClass(StepFirst.class);//设置主类名
		job.setOutputKeyClass(Text.class);//设置job的key
		job.setOutputValueClass(Text.class);
		job.setMapperClass(FirstMapper.class);
		job.setReducerClass(FirstReducer.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));//输入wh中的class
		FileOutputFormat.setOutputPath(job, new Path(args[1]));//输出cut1中
		
		job.waitForCompletion(true);
	}
到此为止,第一步的输入和输出都已经结束了,但是输入和输出需要在run configs中手动进行配置
hdfs://0.0.0.0:19000/invert/wh.txt/
hdfs://0.0.0.0:19000/invert/cut1/
输入和输出的端口号在eclipse的配置中都有进行相关的说明,注意输入的格式是txt格式

5.3 将第一步的数据进行切割进行最后的拼接输出
<1>map2
protected void map(LongWritable key, Text value,Mapper<LongWritable, Text, Text, Text>.Context context)throws IOException, InterruptedException {
String line = value.toString();//将Accounting12018001,12018003,12018007传入“\t分割”
String[] friend_users = line.split("\t");//得到科目和学号
String friend = friend_users[0];//0的位置就是Accounting
String[] users = friend_users[1].split(",");//分割字符串得到每一个学号
Arrays.sort(users);//把学号进行排序,防止重复
for (int i = 0; i < users.length-1; i++) {
for (int j = i+1; j < users.length; j++) {//学号——学号为key,科目为value传到reducer2
context.write(new Text(users[i]+"-"+users[j]), new Text(friend));//进行循环遍历

<2>reduce2
protected void reduce(Text user_user, Iterable<Text> friends,Context context)throws IOException, InterruptedException {
StringBuffer buf = new StringBuffer();//传入的学号-学号 科目 新建buffer用来存储学号们的共同科目
or (Text friend : friends) {
				buf.append(friend).append(" ");
			}//遍历所有的科目,把其放在buf中
			context.write(user_user, new Text(buf.toString()));
		}//科目为key 用户为value 传入下一个mapper
<3>main主函数
public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(StepSecond.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		job.setMapperClass(SecondMapper.class);
		job.setReducerClass(SecondReducer.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));//输入路径cut1的值
		FileOutputFormat.setOutputPath(job, new Path(args[1]));//shuchu路径cut2中的值
		job.waitForCompletion(true);
到此为止,第二步的输入和输出都已经结束了,但是输入和输出需要在run configs中手动进行配置
hdfs://0.0.0.0:19000/invert/cut1/
hdfs://0.0.0.0:19000/invert/cut2/
输入和输出的端口号在eclipse的配置中都有进行相关的说明
5.4 在cmd命令行中键入查看命令和端口号进行查询
注意在键入命令的时候要到具体的Hadoop的目录下面,否则会产生报错,无法进行查看
键入hdfs dfs –cat /invert/cut1/part-r-00000/ 和cut2

对运行参数进行配置:
第一次切割
1.被统计的文件路径:hdfs://0.0.0.0:19000/invert/wh.txt/
2.统计结果保存文件路径:hdfs://0.0.0.0:19000/invert/cut1/
第二次切割
1.被统计的文件路径:hdfs://0.0.0.0:19000/invert/cut1/
2.统计结果保存文件路径:hdfs://0.0.0.0:19000/invert/cut2/
(需要在运行之后才能对参数进行配置)
在这里插入图片描述

在这里插入图片描述
第一次mapreduce的切割输出
在这里插入图片描述

第二次切割输出
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在cmd命令行里的键入命令和相关的显示
在这里插入图片描述
在这里插入图片描述
6 实验代码

package duo_MapReduce;
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 StepFirst {
	static class FirstMapper extends Mapper<LongWritable,Text,Text,Text>{
		@Override
		protected void map(LongWritable key, Text value,Mapper<LongWritable, Text, Text, Text>.Context context)throws IOException, InterruptedException {
			String line = value.toString();
			String[] arr = line.split(":");
			String user = arr[0];
			String friends = arr[1];
			for (String friend : friends.split(",")) {
				context.write(new Text(friend), new Text(user));
		}
	}
	static class FirstReducer extends Reducer<Text, Text, Text, Text>{
		@Override
		protected void reduce(Text friend, Iterable<Text> users,Context context)throws IOException, InterruptedException {
			StringBuffer buf = new StringBuffer();
			for (Text user : users) {
				buf.append(user).append(",");
			}
			context.write(new Text(friend), new Text(buf.toString()));
		}
	}
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(StepFirst.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		job.setMapperClass(FirstMapper.class);
		job.setReducerClass(FirstReducer.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		job.waitForCompletion(true);
	}
}

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;
public class StepSecond {
	static class SecondMapper extends Mapper<LongWritable,Text,Text,Text>{
		@Override
		protected void map(LongWritable key, Text value,Mapper<LongWritable, Text, Text, Text>.Context context)throws IOException, InterruptedException {
			String line = value.toString();
			String[] friend_users = line.split("\t");		
			String friend = friend_users[0];
			String[] users = friend_users[1].split(",");
			Arrays.sort(users);
			for (int i = 0; i < users.length-1; i++) {
				for (int j = i+1; j < users.length; j++) {
					context.write(new Text(users[i]+"-"+users[j]), new Text(friend));
				}
			}
		}
	}
	static class SecondReducer extends Reducer<Text, Text, Text, Text>{
		@Override
		protected void reduce(Text user_user, Iterable<Text> friends,Context context)throws IOException, InterruptedException {
			StringBuffer buf = new StringBuffer();
			for (Text friend : friends) {
				buf.append(friend).append(" ");
			}
			context.write(user_user, new Text(buf.toString()));
		}
	}
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(StepSecond.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		job.setMapperClass(SecondMapper.class);
		job.setReducerClass(SecondReducer.class);
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}	
**7 可能遇见的问题描述**
(1)在Hadoop的配置过程中出现了很多问题比如在配置相关的配置环境变量的时候Java home的时候应该把具体的路径打进去。
(2)还有在格式化了Hadoop之后,Hadoop挂掉了,应该把上一次运行的name文件删除掉在进行运行。
(3)在运行eclipse的代码的时候,出现了jdk找不到main的错误,是应该把电脑中的原来的jdk卸载掉在进行配置,因为以前的eclipse当中默认运行的以前的jdk。
 (4)加之在配置两个mapreduce文件的run configs的时候应该注意的第一个文件的输入路径是第二个文件的输入路径问题。
(5)如果出现了log4三排日志文件的问题具体原因可以百度,就是在file里面加入日志文件之后就不会出现红色报错问题。
**最后感谢我的大数据老师张玲给与我的帮助**
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值