大數據學習(八)MR wordcount進階 partition+序列化排序

簡介

上一章介紹了MR的wordcount的demo,這一節我們來進行擴充,逐步將wordcount豐富,擁有更多的業務基礎邏輯。

我們目標

  1. 是實現自主切分partition,生成自定義的數量和數據特徵的partition文件。
  2. 並且實現序列化數據bean,利用writableComparable接口實現升序降序排列。

首先我們看一眼數據,這是我隨便敲的。
在這裏插入圖片描述
我們用partition分成兩個文件,分別是奇數和偶數。
並且每個文件降序排序。

得到如下
文件一:
在這裏插入圖片描述
文件二:
在這裏插入圖片描述

目錄結構

在這裏插入圖片描述
和上一章相比我們增加了兩個文件
dataBean 和partitioner

dataBean

package MRcode;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.hadoop.io.WritableComparable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

/**
 * @Author: Braylon
 * @Date: 2020/1/19 10:18
 * @Version: 1.0
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class dataBean implements WritableComparable<dataBean> {
    private Long data0;

    public void set(Long data0) {
        this.data0 = data0;
    }

    @Override
    public int compareTo(dataBean o) {
        return this.data0 > o.getData0() ? -1 : 1;
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.data0 = dataInput.readLong();
    }

    @Override
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeLong(data0);
    }

    @Override
    public String toString() {
        return '\001' + data0.toString() + '\001';
    }
}

這裏我增加了一個dataBean來標記數據,因爲每個數據只有一個數字,所以我就只寫了一個data0,在真正的應用中肯定不止一個屬性。然後需要注意的是,這個bean實現了WritableComparable的接口。

至於爲什麼要使用這個實現自定義數據的序列化,我看了一個博主寫的很好,我借用一下:

  1. 在進行mapreduce編程時key鍵往往用於分組或排序,當我們在進行這些操作時Hadoop內置的key鍵數據類型不能滿足需求時,
    或針對用例優化自定義數據類型可能執行的更好。因此可以通過實現org.apache.hadoop.io.WritableComparable接口定義一個自定義的WritableComparable類型,並使其作爲mapreduce計算的key類型。
    2.自定義Hadoop key類型。
    1.Hadoop mapreduce的key類型往往用於進行相互比較, 可以達到進行相互比較來滿足排序的目的。
    2.Hadoop Writable數據類型實現了WritableComparable接口,並增加了CompareTo()方法。
    CompaeTo()方法的返回值有三種類型。負整數、0、正整數分別對應小於、等於、大於被比較對象
    ————————————————
    原文鏈接:https://blog.csdn.net/xj626852095/article/details/52675874

然後要注意的就是compareTo方法,這個的返回值很關鍵,決定了排序方式。

partitioner

package MRcode;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Partitioner;

/**
 * @Author: Braylon
 * @Date: 2020/1/18 12:03
 * @Version: 1.0
 */
public class partitioner extends Partitioner<dataBean, IntWritable> {

    @Override
    public int getPartition(dataBean dataBean, IntWritable intWritable, int i) {

        String str = dataBean.getData0().toString();
        String firWord = str.substring(str.length() - 1, str.length());
        char[] charArray = firWord.toCharArray();
        int result = charArray[0];

        if (result % 2 == 0) {
            return 0;
        }else {
            return 1;
        }
    }
}

這裏就是根據數據的最後以爲的奇偶來返回到不同的parttion文件中,定義了兩種不同的返回數據我們需要在driver中設定reducenum,如下所示:

driver

package MRcode;

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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


import java.io.IOException;

public class WorkCountDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        args = new String[] {"inputPath","outputPath"};

        //獲取配置信息
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        job.setJarByClass(WorkCountDriver.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);


        job.setMapOutputKeyClass(dataBean.class);
        job.setMapOutputValueClass(IntWritable.class);
        //reduce 輸出的K,V類型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        job.setPartitionerClass(partitioner.class);
        job.setNumReduceTasks(2);

        FileInputFormat.setInputPaths(job,new Path(args[0]));
        FileOutputFormat.setOutputPath(job,new Path(args[1]));

        //提交job
        job.waitForCompletion(true);
    }
}

        job.setPartitionerClass(partitioner.class);
        job.setNumReduceTasks(2);

上面的兩行是很重要的,尤其是設置reducetask的個數,由於在partitioner中設置了兩種不同的返回類型,所以這裏的個數必須要大於等於2,否則會報錯。

下面我放上mapper和reducer類的代碼,其中比較重要的是他們的輸入輸出類型,具體的map和reduce的過程與原理大家可以看上一章我寫的,這裏不再贅述。

mapper

package MRcode;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class WordCountMapper extends Mapper<LongWritable, Text, dataBean, IntWritable> {

    dataBean k = new dataBean();
    IntWritable v = new IntWritable();


    @Override
    protected void map(LongWritable key,
                       Text value,
                       Context context) throws IOException, InterruptedException {
        //第一步 轉化格式
        String line0 = value.toString();

        //第二部 切分數據  按空格切分數據
        String[] words = line0.split(" ");

        //第三步 輸出<單詞 , 1>
        for (String word : words) {
            //寫法1:context.write(new Text(word),new IntWritable(1));
            k.set(Long.parseLong(word));
            v.set(1);
            context.write(k,v);
        }
    }
}

reducer

package MRcode;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;


import java.io.IOException;

public class WordCountReducer extends Reducer<dataBean, IntWritable,Text,IntWritable> {
    @Override
    protected void reduce(dataBean key,
                          Iterable<IntWritable> values,
                          Context context) throws IOException, InterruptedException {
        //初始化次數
        int count=0;

        //彙總次數
        for(IntWritable value : values){
            count += value.get();
        }
        //輸出總次數
        context.write(new Text(key.getData0().toString()), new IntWritable(count));
    }
}

最終得到上述的結果。

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