Hadoop(六)——MapReduce(中下)

排序:

昨天说了MapReduce组件中的序列化和分区。今天接着说组件。

规则:
reduce阶段处理完数据后,输出的内容是可以按照我们自己的要求来排序的。除了基本数据类型外,如果是自定义数据类型,那么需要在类中继承一个WritableComparable接口,实现它的compareto方法来自定义比较规则。

注意:
如果两个键的compareTo结果为0,那么Reduce阶段会将这两个键看作是同一个键然后对应的值分到一组
案例:
先按照月份升序,如果月份一致则同一月中按照利润降序。

文件内容如下:
月份/名字/利润
在这里插入图片描述
1.书写封装类:

package cn.tedu.sortprofit;

import org.apache.hadoop.io.WritableComparable;

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

public class Profit implements WritableComparable<Profit> {

    private int month;
    private String name = "";
    private int profit;

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getProfit() {
        return profit;
    }

    public void setProfit(int profit) {
        this.profit = profit;
    }

    // 先按照月份升序,如果月份一致则同一月中按照利润降序
    @Override
    public int compareTo(Profit o) {
        int r1 = this.month - o.month;
        if (r1 == 0) {
            int r2 = o.profit - this.profit;
            return r2 == 0 ? -1 : r2;
        }
        return r1;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(month);
        out.writeUTF(name);
        out.writeInt(profit);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        this.month = in.readInt();
        this.name = in.readUTF();
        this.profit = in.readInt();
    }

    @Override
    public String toString() {
        return month + " " + name + " " + profit;
    }
}

2.map类
因为所有信息都在key中了,所以value就给了一个null

package cn.tedu.sortprofit;

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

import java.io.IOException;

public class SortProfitMapper
        extends Mapper<LongWritable, Text, Profit, NullWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String[] arr = value.toString().split(" ");
        Profit p = new Profit();
        p.setMonth(Integer.parseInt(arr[0]));
        p.setName(arr[1]);
        p.setProfit(Integer.parseInt(arr[2]));
        context.write(p, NullWritable.get());
    }
}

3.reduce类:

package cn.tedu.sortprofit;

import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class SortProfitReducer
        extends Reducer<Profit, NullWritable, Profit, NullWritable> {
    @Override
    protected void reduce(Profit key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {
        context.write(key, NullWritable.get());
    }
}

4.启动类:

package cn.tedu.sortprofit;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
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 SortProfitDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        job.setJarByClass(SortProfitDriver.class);

        job.setMapperClass(SortProfitMapper.class);
        job.setReducerClass(SortProfitReducer.class);

        job.setMapOutputKeyClass(Profit.class);
        job.setMapOutputValueClass(NullWritable.class);

        job.setOutputKeyClass(Profit.class);
        job.setOutputValueClass(NullWritable.class);

        FileInputFormat.addInputPath(job,
                new Path("hdfs://hadoop01:9000/txt/profit3.txt"));
        FileOutputFormat.setOutputPath(job,
                new Path("hdfs://hadoop01:9000/result/sortprofit3"));

        job.waitForCompletion(true);
    }
}

合并:

之前做的都是所有mapTask封装好数据给到RduceTask来进行计算,所谓的合并,就是在交给reduce之前,每个map自己先算好,最后把各自的数据再给reduce,这样reduce就可以减少很多的计算量。
在这里插入图片描述
如上图所示,每一个mapTask有2000个1,如果他们直接把数据给reduceTask,那么reduce要计算1w个1相加,但是如果每个map自己算好了自己的那一部分,到了reduce这里它就只需要计算5个2000相加就可以。

使用合并:
非常简单,在启动类中声明一下就可以,mapReduce自动使用

 job.setCombinerClass(SortScoreReducer.class);

注意:
Combiner能够有效的提高MapReduce的效率,但不是所有的场景都是和与使用Combiner。例如求和、求最值、去重等可传递运算的场景可以使用Combiner,例如求平均等不可传递的场景不能使用Combiner

MapReduce的基本理论:

数据本地化策略:

一个分块(block)一般是128m,而分片在一般开发中,也是规定128m,这样 分块数=分片数。

主节点(JobTracker): 用来从HDFS的NameNode中接收元数据,获取任务的block,对block进行切片,每一个切片分配给一个map。

切片: 一种逻辑上的切分,根据任务量(block的数量大小)来确定map的线程个数。

切片的规则:

  1. 如果是空文件,则整个文件作为1个切片处理

  2. 文件存在可切与不可切两种。例如绝大部分的压缩文件都市不可切的。如果文件不可切,则整个文件作为1个切片来进行处理

  3. 默认情况下,Split和Block的大小一致 如果要调小splitSize,那么需要调小maxSize -
    FileInputFormat.setMaxInputSplitSize();如果要调大splitSize,那么需要调大minSize -
    FileInputFormat.setMinInputSplitSize();

  4. 在切片过程中,存在切片与之SPLIT_SLOP=1.1,如果剩余文件大小/splitSize>1.1才会继续切,不然剩下的数据就会作为1个切片处理

从节点(TaskTracker): 接收到map来进行处理。
在这里插入图片描述
数据本地化策略:

  • 在实际生产过程中,会考虑将DataNode和TaskTracker部署在相同的节点上,因为这样做可以减少TaskTracker跨集群去拿block中的数据。
  • 在分配任务的时候,考虑尽量将任务分配到有对应数据的节点上,这样做就保证数据是从本地读取减少了集群中节点之间的网络消耗

Job执行的流程:

启动类中,我们创建了一个job对象,并且通过该对象绑定了map,reduce以及他们的输出形式和位置,下面就来细说一下Job的执行流程。

提交阶段: 在这里插入图片描述
执行阶段 :
在这里插入图片描述

uber模式:

上面说过,taskTracker会去JobTracker那里领取任务,一个分片就是一个任务,如果分片过多,任务就过多,导致map过多,那么就会耗费大量资源,通过Uber模式,可以节省一些资源。

uber默认不开启,此时每一个任务都会开启和关闭一次JVM子进程 。

开启uber模式:
配置mapred-site.xml中
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛像话

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值