通過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裏面加入日誌文件之後就不會出現紅色報錯問題。
**最後感謝我的大數據老師張玲給與我的幫助**
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章