MapperReducer

用java代码实现wordcount

新建Java类MRMapper

package MR_wc;

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 MRMapper extends Mapper<LongWritable,Text,Text,IntWritable> {

    IntWritable ONE =new IntWritable(1);

    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        /*super.setup(context);*/
        System.out.println("-----------Mapper.setup--------------");
    }

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        /*super.map(key, value, context);*/
        System.out.println("-----------Mapper.map--------------");

        // 获取内容,转为小写
        final String line =value.toString().toLowerCase();

        // 按照分隔符进行拆分
        final String[] splits = line.split(" ");

        //输出
        for (String word : splits){
            context.write(new Text(word),ONE);
        }

    }

    @Override
    protected void cleanup(Context context) throws IOException, InterruptedException {
        /*super.cleanup(context);*/
        System.out.println("-----------Mapper.cleanup--------------");
    }
}

新建Java类MRReducer

package MR_wc;

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

import java.io.IOException;

public class MRReducer extends Reducer<Text,IntWritable,Text,IntWritable>{

    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        System.out.println("-----------Reducer.setup--------------");
    }


    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        System.out.println("-----------Reducer.reduce--------------");

        //初始值 count
        int count=0;

        for (IntWritable value : values){
            count += value.get();
        }

        context.write(key,new IntWritable(count));

    }

    @Override
    protected void cleanup(Context context) throws IOException, InterruptedException {
        System.out.println("-----------Reducer.cleanup--------------");
    }
}

新建Java类MRDriver(连接MRMapper和MRReducer)

package MR_wc;

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;

public class MRDrive {
    public static void main(String[] args) throws Exception {

        String input = "data/wc";
        String output = "out_mr_wc";

        final Configuration configuration=new Configuration();

        //1.获取job对象
        final Job job =Job.getInstance(configuration);

        //1.5 删除输出文件夹
        FileUtils.deleteTarget(configuration,output);

        //2.设置class
        job.setJarByClass(MRDrive.class);

        //3.设置 Mapper 和 Reducer
        job.setMapperClass(MRMapper.class);
        job.setReducerClass(MRReducer.class);

        // 4.设置 Mapper 阶段输出数据的 kv 类型,对应就是MRMapper 的第三 四个参数的类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //5.设置 Reducer 阶段输出数据的 kv 类型,对应就是MRReducer 的第三 四个参数的类型
        job.setOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //设置combiner
        job.setCombinerClass(MRReducer.class);

        //6. 设置输入输出的路径
        FileInputFormat.setInputPaths(job,new Path(input));
        FileOutputFormat.setOutputPath(job,new Path(output));

        //7.提交job
        final boolean result = job.waitForCompletion(true);

        System.exit(result ? 0:1);



    }

}

新建Java类FileUtils(删除输出文件夹)

package MR_wc;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class FileUtils {

    public static  void deleteTarget(Configuration configuration, String output) throws Exception{

        final FileSystem fileSystem = FileSystem.get(configuration);

        final Path path =new Path(output);

        if(fileSystem.exists(path)){
            fileSystem.delete(path,true);
        }
    }

}

运行结果

hadoop解决数据倾斜的方法。

什么是数据倾斜?

比如一个文件, a b c

a 1亿个  b 1个   c 1个

1.combiner

        a  1亿个  (a,1亿)

        b  1个        (b,1)

        c  1个        (c,1)

        减少数据的网络传输

        但是avg不适合,如果导致数据倾斜的key分布在很多不同的文件,不同mapper,这种方法就不适合了。

100mapper每 个mapper里1万个a

2.导致数据倾斜的key分布在很多不同的文件的时候

        2.1   局部聚合+全局聚合

                第一次map:对于导致数据倾斜的key,加上一个随机数前缀

                1_a,2_a,3_a...

                这样的话,本来相同的key是不是也会被分到多个reducer中进行局部聚合

                第二次map:去掉key的随机前缀,进行全局聚合

                思想:两次MR,第一.次将key|随机散列到不同的reducer进行处理,达到负载均衡的目的

                第二次再根据去掉key的随机前缀,按照原本的key进行reduce处理

        2.2   增加reducr数,提高并行度

        job.setNumReduceTasks(int);

        比如本来a,b,c只有三个reduce,现在我将reduce数改为30个,是不是也相当于处理a的reducer就多了

        job.setNumReduceTasks(0);

        设置成0,reducer就不输出了,直接将map的结果写在输出文件中

        2.3   实现自定义分区

        partitioner:按照某种规则(可以自定义)对map输出的数据进行分区操作

        默认的是HashPartitioner  job.setPartitionerClass (HashPartitioner.class) ;

        顺序:map => partitioner => reduce

        根据数据分布情况,自定义散列函数,将key均匀分配到不同的reducer

shuffle 优化

1.  map端

        1.1  减少输入的文件个数,对小文件进行合并

        1.2  combiner

2.  I/O

        数据传输时进行压缩

3.  reduce端

        3.1        设置map  reduce共存,mapred-site.xml

        mapreduce.job.reduce.slowstart.completedmaps  默认0.05

        也就是说map在执行到5%的时候开始为reduce进行申请资源,开始执行reduce操作

        3.2        尽量少用reduce

        reduce会产生大量的网络消耗,但是该用还是要用

        3.3        增加reducer,提高并行度

4.整体

        4.1        合理的设置map数和reduce数

        4.2        mr on yarn        进行参数调优  container

        4.3        加配置(机器,内存等)

一些其他面试题

1.是否可以只要map没有reduce?

        可以

2.是否可以只有reduce没有map?

        可以

        

作业

1.combiner不适合做avg,为什么?

用combiner做avg计算可能会得到错误的结果。

例如,计算1950年一段时期的平均温度:

map(1950,0,20,10) map(1950,25,15)

正常: reduce(O, 20, 10,25, 15) =14 

 利用组合函数combiner (avg) : reduce (avg ( map(0,20,10)),avg ( map(25,15)) ) =》avg (10,20)=15, 结果就不对了!所以平均值就不适用combiner了.

2.有哪几种压缩方式?分别的优缺点和适用场景。

(1)Gzip
优点
压缩解压速度快 , 压缩率高 , hadoop本身支持
处理压缩文件时方便 , 和处理文本一样
大部分linux 系统自带 Gzip 命令 , 使用方便
缺点
不支持切片
使用场景
文件压缩后在130M以内 (一个块大小) , 都可以使用 GZip 压缩(因为Gzip唯一的缺点是不能切片)
总结 : 不需要切片的情况下 可以使用


(2)BZip2
优点
压缩率高(高于Gzip)
可以切片
hadoop自带 使用方便
缺点
压缩解压速度超级慢
使用场景
不要求压缩速率 ,但是对压缩率有要求的情况下 比如备份历史记录 , 备份文件
或者 输出的文件较大 , 处理后的数据需要减少磁盘存储并且以后使用数据的情况较少 (解压 / 压缩的情况较少)
对于单个文件 较大 ,又想压缩减少磁盘空间 , 并且兼容之前的应用程序的情况
总结 : 对于压缩解压速度没有要求的情况下


(3)Lzo
优点
压缩解压速度比较快 , 压缩率也可以
支持切片 是hadoop 比较流行的压缩格式
可以在linux 下安装 lzo命令 使用方便
缺点
压缩率比Gzip低一些
hadoop 本身不支持, 需要自己安装
使用Lzo 格式的文件时需要做一些特殊处理(为了支持 Split 需要建立索引 , 还需要家将 InputFormat 指定为Lzo 格式 [特殊]
使用场景
压缩以后还大于 200M 的文件 , 且文件越大 Lzo 的优势越明显
(原因很简单 , 四种压缩方式 只有BZip2 , Gzip 支持切片 , 然后 BZip2 你懂的 , 速度贼慢 , 只能用于特定的场景, 所以 Lzo 是比较经常用的 )
总结 : 压缩后文件还是比较大 需要切片的情况下 推荐使用


(4)Snappy
优点
高压缩解压速度 , 压缩率还可以
缺点
不能切片
压缩率比Gzip小
hadoop本身不支持 需要安装
使用场景
当Mapeduce的Map阶段输出的数据比较大的时候 , 作为Map到Reduce的中间数据的压缩格式
作为一个MapReduce作业的输出和另一个MapReduce的输入
总结 : 因为 压缩率不怎么样 还不能切片 , 所以在一般的作为输入文件压缩时可以用 GZip 和 Lzo 都比Snappy

3.yarn参数调优。

下载

wget http://public-repo-1.hortonworks.com/HDP/tools/2.6.0.3/hdp_manual_install_rpm_helper_files-2.6.0.3.8.tar.gz

解压

tar -zxvf hdp_manual_install_rpm_helper_files-2.6.0.3.8.tar.gz

4.打包运行在服务器,可以参考官网的例子。

5.map数和reduce数由什么决定?

map数量由splitSize来决定的,reduce数量,由partition决定。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值