大數據hadoop學習【14】-----通過JAVA編程實現對MapReduce的數據進行排序


上次的博客中,林君學長通過java編程實現了對MapReduce的數據去重;本次博客,我們將深入瞭解MapReduce,並通過java編程實現對文件數據中數據的排序,一起看步驟吧!

  • 本次排序要求: 對輸入文件中數據進行排序。輸入文件中的每行內容均爲一個數字,即一個數據。要求在輸出中每行有兩個間隔的數字,其中,第一個代表原始數據在原始數據集中的位次,第二個代表原始數據。

一、數據準備

1、ubuntu文件系統中準備對應數據文件

1)、在對應位置創建file3.txt文件,並寫入相關數據:文件中的每行都是一個數據
(1)、創建file3.txt文件,並打開

cd ~/lenovo/data
touch file3.txt
gedit file3.txt

其中 ~/lenovo/data爲林君自己創建的文件夾
(2)、寫入文件內容如下所示:

2
32
654
32
15
756
65223

2)、在相同位置創建file4.txt文件,並寫入數據,兩個文件中的數據應該要有相同的和不同的,且文件中的每行都是一個數據
(1)、創建file4.txt文件,並打開

touch file4.txt
gedit file4.txt

(2)、寫入文件內容如下所示:

5956
22
650
92

3)、在相同位置創建file5.txt文件,並寫入數據,兩個文件中的數據應該要有相同的和不同的,且文件中的每行都是一個數據
(1)、創建file5.txt文件,並打開

touch file5.txt
gedit file5.txt

(2)、寫入文件內容如下所示:

26
54
6

在這裏插入圖片描述

2、運行hadoop

1)、終端輸入以下命令運行hadoop

start-dfs.sh

2)、查看hadoop是否成功運行

jps

在這裏插入圖片描述
出現以上4個節點則爲成功運行!

3、將文件上傳至hadoop文件系統

1)、在hdfs文件系統中創建file2目錄用來存放我們上傳的文件

hdfs dfs -mkdir /user/hadoop/file2

2)、將file3.txt文件上傳至hdfs文件系統中的file2目錄

hdfs dfs -put ~/lenovo/data/file3.txt /user/hadoop/file2

3)、將file4.txt文件上傳至hdfs文件系統中的file2目錄

hdfs dfs -put ~/lenovo/data/file4.txt /user/hadoop/file2

4)、將file5.txt文件上傳至hdfs文件系統中的file2目錄

hdfs dfs -put ~/lenovo/data/file5.txt /user/hadoop/file2

在這裏插入圖片描述

5)、查看文件是否上傳成功

hdfs dfs -ls /user/hadoop/file2

在這裏插入圖片描述
6)、查看文件內容是否一致

hdfs dfs -cat /user/hadoop/file2/file3.txt
hdfs dfs -cat /user/hadoop/file2/file4.txt
hdfs dfs -cat /user/hadoop/file2/file5.txt

在這裏插入圖片描述

二、編寫java程序

1、打開eclipse,編寫數據排序的java代碼

1)、新建類Sort ,其中java代碼如下所示:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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 org.apache.hadoop.util.GenericOptionsParser;
import java.io.IOException;
/**
 * 數字排序
 */
public class Sort{
    /**
     * 使用Mapper將數據文件中的數據本身作爲Mapper輸出的key直接輸出
     */
    public static class forSortedMapper extends Mapper<Object, Text, IntWritable, IntWritable> {
        private IntWritable mapperValue = new IntWritable(); //存放key的值
        public void map(Object key, Text value, Context context)
                throws IOException, InterruptedException {
            String line = value.toString(); //獲取讀取的值,轉化爲String
            mapperValue.set(Integer.parseInt(line)); //將String轉化爲Int類型
            context.write(mapperValue,new IntWritable(1)); //將每一條記錄標記爲(key,value) key--數字 value--出現的次數
                                                                //每出現一次就標記爲(number,1)
        }
    }
    /**
     * 使用Reducer將輸入的key本身作爲key直接輸出
     */
 public static class forSortedReducer extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable>{
        private IntWritable postion = new IntWritable(1); //存放名次
        @SuppressWarnings("unused")
		@Override
        protected void reduce(IntWritable key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            for (IntWritable item :values){ //同一個數字可能出多次,就要多次並列排序
                context.write(postion,key); //寫入名次和具體數字
                System.out.println(postion + "\t"+ key);
                postion = new IntWritable(postion.get()+1); //名次加1
            }
        }
    }
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration(); //設置MapReduce的配置
        String[] otherArgs = new GenericOptionsParser(conf,args).getRemainingArgs();
        if(otherArgs.length < 2){
            System.out.println("Usage: Sort <in> [<in>...] <out>");
            System.exit(2);
        }
        //設置作業
        //Job job = new Job(conf);
        Job job = Job.getInstance(conf);
        job.setJarByClass(Sort.class);
        job.setJobName("SortedData");
        //設置處理map,reduce的類
        job.setMapperClass(forSortedMapper.class);
        job.setReducerClass(forSortedReducer.class);
        //設置輸入輸出格式的處理
        job.setOutputKeyClass(IntWritable.class);
        job.setOutputValueClass(IntWritable.class);
        //設定輸入輸出路徑
        for (int i = 0; i < otherArgs.length-1;++i){
            FileInputFormat.addInputPath(job,new Path(otherArgs[i]));
        }
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length-1]));
        System.exit(job.waitForCompletion(true)?0:1);
    }
}

在MapReduce流程中,Map的輸出<Key,value>經過shuffle過程聚集成<key,value-list>後會被交給Reduce。所以從設計好的Reduce輸入可以反推出Map的輸出的Key應爲數據,而value爲任意值。繼續反推,Map輸出的Key爲數據。而在這個實例中每個數據代表輸入文件中的一行內容,所以Map階段要完成的任務就是在採用Haodoop默認的作業輸入方式之後,將value設置成Key,並直接輸出(輸出中的value任意)。Map中的結果經過shuffle過程之後被交給reduce。在Reduce階段不管每個Key有多少個value,都直接將輸入的Key複製爲輸出的Key,並輸出就可以了(輸出中的value被設置成空)

2)、運行,測試代碼沒有問題
在這裏插入圖片描述

控制檯出現如上顯示則代碼沒有問題!

2、將java文件打包成jar

1)、按照如下截圖步驟鏡像jar打包
在這裏插入圖片描述
2)、選擇JAR file
在這裏插入圖片描述
3)、選擇導出的類和導出路徑
在這裏插入圖片描述
4)、點擊ok
在這裏插入圖片描述
5)、導出成功
在這裏插入圖片描述
出現finished則爲導出成功!
6)、找到對應路徑,查詢該包是否成功導出
在這裏插入圖片描述
出現以上箭頭的jar包,則導出成功,然後關閉eclipse

三、結果測試

1、終端運行jar包

1)、終端輸入如下命令運行我們導出的jar包

hadoop jar ~/lenovo/bigData/myapp/Sort.jar /user/hadoop/file2 /user/hadoop/output3

提示: 路徑 /user/hadoop/output3中的output3不用我們創建,該命令會自動幫我們創建的,但我們輸入的output3是要保證hdfs中沒有與之相同的名稱哦,不然會報錯的,其中 /user/hadoop/file2是我們創建好的保存測試文件的目錄哦!
2)、出現如下界面則爲成功運行
在這裏插入圖片描述
在這裏插入圖片描述

2、查看運行結果

1)、終端輸入以下命令查看我們排序的結果

hdfs dfs -cat /user/hadoop/output3/*

2)、查看結果如下所示:
在這裏插入圖片描述

3、運行結果分析

1)、最開始的三個文件數據及最後運行結果的數據如下所示:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述
上面的左邊爲file3.txt,中間爲file4.txt,右邊爲爲file5.txt
在這裏插入圖片描述
上面爲最終的運行結果

2)、在上面的結果中我們可以看出,運行出來的結果將我們上面三個文件的結果相結合爲一個文件
3)、除此之外,該代碼還實現了對數據的排序從小到大依次排序成功,達到了我們要求的結果展示!
4)、需要注意的是:如果要再次運行Sort.jar,需要首先刪除HDFS中的output3目錄,否則會報錯

4、實驗結束,關閉hadoop

stop-dfs.sh

在這裏插入圖片描述

以上就是本次博客的全部內容啦,通過對本次博客的閱讀,希望小夥伴理解如何通過java對MapReduce的數據進行操作,進而理解原理,這樣以後的編程中,就可以通過原理編程,而不是面向百度編程!
遇到問題的小夥伴記得留言評論哦,林君學長看到會爲大家解答的,這個學長不太冷!

陳一月的又一天編程歲月^ _ ^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章