【Hadoop學習之MapReduce】_18MR之InputFormat數據輸入

一、切片與MapTask並行度決定機制

MapTask的並行度決定Map階段的任務處理併發度,進而影響到整個Job的處理速度

數據塊:Block是HDFS物理上把數據分成一塊一塊

數據切片:數據切片知識在邏輯上對輸入進行分片,並不會在磁盤上將其切分成片進行存儲

在這裏插入圖片描述

  1. 一個JobMap階段並行度由客戶端在提交Job時的切片數決定
  2. 每一個Split切片分配一個MapTask並行實例處理
  3. 默認情況下,切片大小=BlockSize
  4. 切片時不考慮數據集整體,而是逐個針對每一個文件單獨切片

二、Job提交流程源碼

在這裏插入圖片描述
核心源碼

waitForCompletion()

submit();

	// 1建立連接
	connect();	
		// 1)創建提交Job的代理
		new Cluster(getConfiguration());
			// (1)判斷是本地yarn還是遠程
			initialize(jobTrackAddr, conf); 

    // 2 提交job
    submitter.submitJobInternal(Job.this, cluster)
        // 1)創建給集羣提交數據的Stag路徑
        Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);

        // 2)獲取jobid ,並創建Job路徑
        JobID jobId = submitClient.getNewJobID();

        // 3)拷貝jar包到集羣
        copyAndConfigureFiles(job, submitJobDir);	
        rUploader.uploadFiles(job, jobSubmitDir);

        // 4)計算切片,生成切片規劃文件
        writeSplits(job, submitJobDir);
        maps = writeNewSplits(job, jobSubmitDir);
        input.getSplits(job);

        // 5)向Stag路徑寫XML配置文件
        writeConf(conf, submitJobFile);
        conf.writeXml(out);

        // 6)提交Job,返回提交狀態
        status = submitClient.submitJob(jobId, submitJobDir.toString(), job.getCredentials());

三、FileInputFormat切片機制

(一)FileInputFormat切片機制

  1. 簡單的按照文件的內容長度進行切片
  2. 切片大小,默認等於Block大小
  3. 切片時不考慮數據集整體,而是逐個針對每一個文件單獨切片

(二)FileInputFormat切片源碼解析(input.getSplits(job))

  1. 程序先找到你數據存儲的目錄

  2. 開始遍歷處理(規劃切片)目錄下的每一個文件

  3. 遍歷第一個文件ss.txt(300M)

    (1)獲取文件大小fs.sizeOf(ss.txt)

    (2)計算切片大小

    computeSplitSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
    

    (3)默認情況下,切片大小=blocksize

    (4)開始切片:形成第1個切片ss.txt—0:128M,第2個切片ss.txt—128:256M,第3個切片ss.txt—256M:300M每次切片時,都要判斷切完剩下的部分是否大於塊的1.1倍,不大於1.1倍就劃分一塊切片

    (5)將切片信息寫到一個切片規劃文件中

    (6)整個切片的核心過程在getSplit()方法中完成

    (7)InputSplit只記錄切片的元數據信息,比如起始位置、長度以及所在的節點列表等

  4. 提交切片規劃文件到YARN上,YARN上的MrAppMaster就可以根據切片規劃文件計算開啓MapTask個數

(三)案例分析

  1. 輸入數據有兩個文件

    file1.txt	320M
    file2.txt	10M
    
  2. 經過FileInputFormat的切片機制運算後,形成的切片信息如下:

    file1.txt.split1	0M~128M
    file1.txt.split2	128M~256M
    file1.txt.split3	256M~320M
    file2.txt.split1	0M~10M
    

(四)FileInputFormat切片大小的參數配置

  1. 源碼中計算切片大小的公式

    Math.max(minSize,Math.min(maxSize,blockSize));
    mapreduce.input.fileinputformat.split.minSize=1 默認值爲1
    mapreduce.input.fileinputformat.split.maxSize=LongMAXValue 默認值爲LongMAXValue
    

    默認情況下:切片大小=blocksize

  2. 切片大小設置

    maxsize(切片最大值):參數如果調得比blockSize小,則會讓切片變小,而且就等於配置的這個參數的值

    minsize(切片最小值):參數如果調的比blockSize大,則可以讓切片變得比blockSize還大

  3. 獲取切片信息API

    // 獲取切片的文件名稱
    String name = inputSplit.getPath().getName();
    // 根據文件類型獲取切片信息
    FileSplit inputSplit = (FileSplit) context.getInputSplit();
    

四、CombineTextInputFormat切片機制

框架默認的TextInputFormat切片機制是對任務按文件規劃切片,不管文件多小,都會是一個單獨的切片,都會交給一個MapTask,這樣如果有大量小文件,就會產生大量的MapTask,處理效率極其低下。

  1. 應用場景

    CombineTextInputFormat用於小文件過多的場景,它可以將多個小文件從邏輯上規劃到一個切片中,這樣,多個小文件就可以交給一個MapTask處理。

  2. 虛擬存儲切片最大值設置

    CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);	// 4m
    // 注意:虛擬存儲切片最大值設置最好根據實際的小文件大小情況來設置具體的值。
    
  3. 切片機制

    生成切片過程包括:虛擬存儲過程和切片過程兩部分

    (1)虛擬存儲過程

    ​ 將輸入目錄下所有文件大小,依次和設置的setMaxInputSplitSize值比較,如果不大於設置的最大值,邏輯上劃分一個塊。如果輸入文件大於設置的最大值且大於兩倍,那麼以最大值切割一塊;當剩餘數據大小超過設置的最大值且不大於最大值2倍,此時將文件均分成2個虛擬存儲塊(防止出現太小切片)。

    ​ 例如setMaxInputSplitSize值爲4M,輸入文件大小爲8.02M,則先邏輯上分成一個4M。剩餘的大小爲4.02M,如果按照4M邏輯劃分,就會出現0.02M的小的虛擬存儲文件,所以將剩餘的4.02M文件切分成(2.01M和2.01M)兩個文件。

    (2)切片過程

    ​ (a)判斷虛擬存儲的文件大小是否大於setMaxInputSplitSize值,大於等於則單獨形成一個切片。

    ​ (b)如果不大於則跟下一個虛擬存儲文件進行合併,共同形成一個切片。

    ​ (c)測試舉例:有4個小文件大小分別爲1.7M、5.1M、3.4M以及6.8M這四個小文件,則虛擬 存儲之後形成6個文件塊,大小分別爲:1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)

    最終會形成3個切片,大小分別爲:(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M

五、CombineTextInputFormat案例實操

(一)需求分析

  1. 需求

    將輸入的大量小文件合併成一個切片統一處理。

  2. 輸入數據

    準備4個小文件。

  3. 期望

    期望一個切片處理這4個小文件。

(二)代碼實現

以下代碼均在WordCount案例基礎上實現:

  1. 不做任何處理,運行程序,查看切片數量爲4
    在這裏插入圖片描述

  2. WordcountDriver中添加如下代碼,修改虛擬存儲切片最大值,使運行結果中切片數量爲1

    // 如果不設置InputFormat,它默認用的是TextInputFormat.class
    job.setInputFormatClass(CombineTextInputFormat.class);
    
    //虛擬存儲切片最大值設置8m
    CombineTextInputFormat.setMaxInputSplitSize(job, 8388608);
    

    在這裏插入圖片描述

六、FileInputFormat實現類

FileInputFormat常見的接口實現類包括:TextInputFormatKeyValueTextInputFormatNLineInputFormatCombineTextInputFormat和自定義InputFormat等。

  1. TextInputFormat

    TextInputFormat是默認的FileInputFormat實現類,按行讀取每條記錄。鍵是存儲該行在整個文件中的起始字節偏移量,爲LongWritable類型。值是這行內容,不包括任何終止符(換行符和回車符),爲Text類型。

    示例文本:

    Rich learning form
    Intelligent learning engine
    Learning more convenient
    From the real demand for more close to the enterprise
    

    對應示例鍵值對:

    (0,Rich learning form)
    (19,Intelligent learning engine)
    (47,Learning more convenient)
    (72,From the real demand for more close to the enterprise)
    
  2. KeyValueTextInputFormat

    每一行均爲一條記錄,被分隔符分割爲key,value。可以通過在驅動類中設置conf.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR, "\t");來設定分隔符。默認分隔符是tab(\t)

    示例文本(其中——>表示一個(水平方向的)製表符):

    line1 ——>Rich learning form
    line2 ——>Intelligent learning engine
    line3 ——>Learning more convenient
    line4 ——>From the real demand for more close to the enterprise
    

    對應示例鍵值對:

    (line1,Rich learning form)
    (line2,Intelligent learning engine)
    (line3,Learning more convenient)
    (line4,From the real demand for more close to the enterprise)
    
  3. NLineInputFormat

    如果使用NlineInputFormat,代表每個map進程處理的InputSplit不再按Block塊去劃分,而是按NlineInputFormat指定的行數N來劃分。即輸入文件的總行數/N=切片數,如果不整除,切片數=商+1

    示例文本:

    Rich learning form
    Intelligent learning engine
    Learning more convenient
    From the real demand for more close to the enterprise
    

    對應示例鍵值對(如果N是2,則每個輸入分片包含兩行,開啓兩個MapTask):

    // 第一個MapTask
    (0,Rich learning form)
    (19,Intelligent learning engine)
    // 第二個MapTask
    (47,Learning more convenient)
    (72,From the real demand for more close to the enterprise)
    // 注意:此時生成的鍵和值與TextInputFormat生成的一樣
    

七、KeyValueTextInputFormat使用案例

(一)需求分析

  1. 需求

    統計輸入文件中每一行第一個單詞相同的行數。

  2. 輸入數據

    banzhang ni hao
    xihuan hadoop banzhang
    banzhang ni hao
    xihuan hadoop banzhang
    
  3. 期望輸出數據

    banzhang	2
    xihuan		2
    

(二)代碼實現

  1. 創建包名:com.easysir.kv

  2. 創建KVTextMapper類:

    package com.easysir.kv;
    
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    import java.io.IOException;
    
    public class KVTextMapper extends Mapper<Text, Text, Text, LongWritable>{
    
        // 1 設置value
        LongWritable v = new LongWritable(1);
    
        @Override
        protected void map(Text key, Text value, Context context)
                throws IOException, InterruptedException {
    
            // banzhang ni hao
    
            // 2 寫出
            context.write(key, v);
        }
    }
    
  3. 創建KVTextReducer

    package com.easysir.kv;
    
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    
    public class KVTextReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
    
        LongWritable v = new LongWritable();
    
        @Override
        protected void reduce(Text key, Iterable<LongWritable> values,	Context context) throws IOException, InterruptedException {
    
            long sum = 0L;
    
            // 1 彙總統計
            for (LongWritable value : values) {
                sum += value.get();
            }
    
            v.set(sum);
    
            // 2 輸出
            context.write(key, v);
        }
    }
    
  4. 創建KVTextDriver

    package com.easysir.kv;
    
    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.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.input.KeyValueLineRecordReader;
    import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    import java.io.IOException;
    
    public class KVTextDriver {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    
            // 輸入輸出路徑需要根據自己電腦上實際的輸入輸出路徑設置
            args = new String[] { "E:\\idea-workspace\\mrWordCount\\input\\kv_data.txt", "E:\\idea-workspace\\mrWordCount\\output" };
    
            Configuration conf = new Configuration();
            // 設置切割符
            conf.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR, " ");
            // 1 獲取job對象
            Job job = Job.getInstance(conf);
    
            // 2 設置jar包位置,關聯mapper和reducer
            job.setJarByClass(KVTextDriver.class);
            job.setMapperClass(KVTextMapper.class);
            job.setReducerClass(KVTextReducer.class);
    
            // 3 設置map輸出kv類型
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(LongWritable.class);
    
            // 4 設置最終輸出kv類型
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(LongWritable.class);
    
            // 5 設置輸入輸出數據路徑
            FileInputFormat.setInputPaths(job, new Path(args[0]));
    
            // 設置輸入格式
            job.setInputFormatClass(KeyValueTextInputFormat.class);
    
            // 6 設置輸出數據路徑
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
            // 7 提交job
            job.waitForCompletion(true);
        }
    }
    

八、NLineInputFormat使用案例

(一)需求分析

  1. 需求

    對每個單詞進行個數統計,要求根據每個輸入文件的行數來規定輸出多少個切片。

  2. 輸入數據(本案例要求每三行放入一個切片)

    banzhang ni hao
    xihuan hadoop banzhang
    banzhang ni hao
    xihuan hadoop banzhang
    banzhang ni hao
    xihuan hadoop banzhang
    banzhang ni hao
    xihuan hadoop banzhang
    banzhang ni hao
    xihuan hadoop banzhang banzhang ni hao
    xihuan hadoop banzhang
    
  3. 期望輸出數據

    number of splits:4
    

(二)代碼實現

  1. 創建包名:com.easysir.nline

  2. 創建NLineMapper類:

    package com.easysir.nline;
    
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    import java.io.IOException;
    
    public class NLineMapper extends Mapper<LongWritable, Text, Text, LongWritable>{
    
        private Text k = new Text();
        private LongWritable v = new LongWritable(1);
    
        @Override
        protected void map(LongWritable key, Text value, Context context)	throws IOException, InterruptedException {
    
            // 1 獲取一行
            String line = value.toString();
    
            // 2 切割
            String[] splited = line.split(" ");
    
            // 3 循環寫出
            for (int i = 0; i < splited.length; i++) {
    
                k.set(splited[i]);
    
                context.write(k, v);
            }
        }
    }
    
  3. 創建NLineReducer

    package com.easysir.nline;
    
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    
    public class NLineReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
    
        LongWritable v = new LongWritable();
    
        @Override
        protected void reduce(Text key, Iterable<LongWritable> values,	Context context) throws IOException, InterruptedException {
    
            long sum = 0l;
    
            // 1 彙總
            for (LongWritable value : values) {
                sum += value.get();
            }
    
            v.set(sum);
    
            // 2 輸出
            context.write(key, v);
        }
    }
    
  4. 創建NLineDriver

    package com.easysir.nline;
    
    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.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.input.NLineInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    import java.io.IOException;
    
    /**
     * description
     *
     * @author Hu.Wang 2020/02/09 13:38
     */
    public class NLineDriver {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
            // 輸入輸出路徑需要根據自己電腦上實際的輸入輸出路徑設置
            args = new String[] { "E:\\idea-workspace\\mrWordCount\\input\\nline_data.txt", "E:\\idea-workspace\\mrWordCount\\output" };
    
            // 1 獲取job對象
            Configuration conf = new Configuration();
            Job job = Job.getInstance(conf);
    
            // 2 設置jar包位置
            job.setJarByClass(NLineDriver.class);
    
            // 3 關聯map和reduce
            job.setMapperClass(NLineMapper.class);
            job.setReducerClass(NLineReducer.class);
    
            // 4 設置map輸出kv類型
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(LongWritable.class);
    
            // 5 設置最終輸出kv類型
            job.setOutputKeyClass(Text.class);
            job.setOutputKeyClass(LongWritable.class);
    
            // 設置每個切片行數
            NLineInputFormat.setNumLinesPerSplit(job, 3);
            // 設置使用NLineInputFormat進行切片
            job.setInputFormatClass(NLineInputFormat.class);
    
            // 6 設置輸入輸出路徑
            FileInputFormat.setInputPaths(job, new Path(args[0]));
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
            // 7 提交job
            job.waitForCompletion(true);
    
        }
    }
    

九、自定義InputFormat

在企業開發中,Hadoop框架自帶的InputFormat類型不能滿足所有應用場景,需要自定義InputFormat來解決實際問題。

自定義InputFormat的步驟如下:

  1. 自定義一個類繼承FileInputFormat
  2. 改寫RecordReader,實現一次讀取一個完整文件封裝爲KV
  3. 在輸出時使用SequenceFileOutPutFormat輸出合併文件

十、自定義InputFormat案例實操

(一)需求分析

  1. 需求

    將多個小文件合併成一個SequenceFile文件(SequenceFile文件是Hadoop用來存儲二進制形式的key-value對的文件格式),SequenceFile裏面存儲着多個文件,存儲的形式爲文件路徑+名稱爲key,文件內容爲value

  2. 輸入數據

    三個txt文件。

  3. 期望輸出

    一個二進制文件。

  4. 需求分析

    (1)自定義一個類繼承FileInputFormat

    ​ a. 重寫isSplitable()方法,返回false不可切割

    ​ b. 重寫createRecordReader(),創建自定義的RecordReader對象,並初始化

    (2)改寫RecordReader,實現一次讀取一個完整文件封裝爲KV

    ​ a. 採用IO流一次讀取一個文件輸出到value中,因爲設置了不可切片,最終把所有文件都封裝到value中

    ​ b. 獲取文件路徑信息+名稱,並設置key

    (3)設置Driver

    // 設置輸入的inputFormat
    job.setInputFormatClass(WholeFileInputformat.class);
    // 設置輸出的outputFormat
    job.setOutputFormatClass(SequenceFileOutputFormat.class);
    

(二)代碼實現

  1. 創建包名:com.easysir.inputformat

  2. 創建WholeFileInputformat類:

    package com.easysir.inputformat;
    
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.BytesWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.InputSplit;
    import org.apache.hadoop.mapreduce.JobContext;
    import org.apache.hadoop.mapreduce.RecordReader;
    import org.apache.hadoop.mapreduce.TaskAttemptContext;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    
    import java.io.IOException;
    
    // 定義類繼承FileInputFormat,其中Text爲文件的路徑和名稱信息
    public class WholeFileInputformat extends FileInputFormat<Text, BytesWritable>{
    
        @Override
        protected boolean isSplitable(JobContext context, Path filename) {
            return false;
        }
    
        @Override
        public RecordReader<Text, BytesWritable> createRecordReader(InputSplit split, TaskAttemptContext context)	throws IOException, InterruptedException {
    
            WholeRecordReader recordReader = new WholeRecordReader();
            recordReader.initialize(split, context);
    
            return recordReader;
        }
    }
    
  3. 創建WholeRecordReader類:

    package com.easysir.inputformat;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FSDataInputStream;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.BytesWritable;
    import org.apache.hadoop.io.IOUtils;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.InputSplit;
    import org.apache.hadoop.mapreduce.RecordReader;
    import org.apache.hadoop.mapreduce.TaskAttemptContext;
    import org.apache.hadoop.mapreduce.lib.input.FileSplit;
    
    import java.io.IOException;
    
    public class WholeRecordReader extends RecordReader<Text, BytesWritable>{
    
        private Configuration configuration;
        private FileSplit split;
    
        private boolean isProgress= true;
        private BytesWritable value = new BytesWritable();
        private Text k = new Text();
    
        @Override
        public void initialize(InputSplit split, TaskAttemptContext context){
    
            this.split = (FileSplit)split;
            configuration = context.getConfiguration();
        }
    
        @Override
        public boolean nextKeyValue() throws IOException {
    
            if (isProgress) {
    
                // 1 定義緩存區
                byte[] contents = new byte[(int)split.getLength()];
    
                FileSystem fs = null;
                FSDataInputStream fis = null;
    
                try {
                    // 2 獲取文件系統
                    Path path = split.getPath();
                    fs = path.getFileSystem(configuration);
    
                    // 3 讀取數據
                    fis = fs.open(path);
    
                    // 4 讀取文件內容
                    IOUtils.readFully(fis, contents, 0, contents.length);
    
                    // 5 輸出文件內容
                    value.set(contents, 0, contents.length);
    
                    // 6 獲取文件路徑及名稱
                    String name = split.getPath().toString();
    
                    // 7 設置輸出的key值
                    k.set(name);
    
                } finally {
                    IOUtils.closeStream(fis);
                }
    
                isProgress = false;
    
                return true;
            }
    
            return false;
        }
    
        @Override
        public Text getCurrentKey(){
            return k;
        }
    
        @Override
        public BytesWritable getCurrentValue(){
            return value;
        }
    
        @Override
        public float getProgress(){
            return 0;
        }
    
        @Override
        public void close(){
        }
    }
    
  4. 創建SequenceFileMapper類:

    package com.easysir.inputformat;
    
    import org.apache.hadoop.io.BytesWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    import java.io.IOException;
    
    public class SequenceFileMapper extends Mapper<Text, BytesWritable, Text, BytesWritable>{
    
        @Override
        protected void map(Text key, BytesWritable value, Context context)
                throws IOException, InterruptedException {
    
            context.write(key, value);
        }
    }
    
  5. 創建SequenceFileReducer類:

    package com.easysir.inputformat;
    
    import org.apache.hadoop.io.BytesWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    import java.io.IOException;
    
    public class SequenceFileReducer extends Reducer<Text, BytesWritable, Text, BytesWritable> {
    
        @Override
        protected void reduce(Text key, Iterable<BytesWritable> values, Context context)
                throws IOException, InterruptedException {
    
            context.write(key, values.iterator().next());
        }
    }
    
  6. 創建SequenceFileDriver類:

    package com.easysir.inputformat;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.BytesWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
    
    import java.io.IOException;
    
    public class SequenceFileDriver {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    
            // 輸入輸出路徑需要根據自己電腦上實際的輸入輸出路徑設置
            args = new String[] { "E:\\idea-workspace\\mrWordCount\\input1", "E:\\idea-workspace\\mrWordCount\\output" };
    
            // 1 獲取job對象
            Configuration conf = new Configuration();
            Job job = Job.getInstance(conf);
    
            // 2 設置jar包存儲位置、關聯自定義的mapper和reducer
            job.setJarByClass(SequenceFileDriver.class);
            job.setMapperClass(SequenceFileMapper.class);
            job.setReducerClass(SequenceFileReducer.class);
    
            // 7設置輸入的inputFormat
            job.setInputFormatClass(WholeFileInputformat.class);
    
            // 8設置輸出的outputFormat
            job.setOutputFormatClass(SequenceFileOutputFormat.class);
    
            // 3 設置map輸出端的kv類型
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(BytesWritable.class);
    
            // 4 設置最終輸出端的kv類型
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(BytesWritable.class);
    
            // 5 設置輸入輸出路徑
            FileInputFormat.setInputPaths(job, new Path(args[0]));
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
            // 6 提交job
            boolean result = job.waitForCompletion(true);
            System.exit(result ? 0 : 1);
        }
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章