MapReduce编程规范、计数统计和分区详解

Map 阶段 2 个步骤

  1. 设置 InputFormat 类, 将数据切分为 Key-Value(K1和V1) 对, 输入到第二步
  2. 自定义 Map 逻辑, 将第一步的结果转换成另外的 Key-Value(K2和V2) 对, 输出结果

Shuffle 阶段 4 个步骤

  1. 对输出的 Key-Value 对进行分区
  2. 对不同分区的数据按照相同的 Key 排序
  3. (可选) 对分组过的数据初步规约, 降低数据的网络拷贝
  4. 对数据进行分组, 相同 Key 的 Value 放入一个集合中

Reduce 阶段 2 个步骤

  1. 对多个 Map 任务的结果进行排序以及合并, 编写 Reduce 函数实现自己的逻辑, 对输入的 Key-Value 进行处理, 转为新的 Key-Value(K3和V3)输出
  2. 设置 OutputFormat 处理并保存 Reduce 输出的 Key-Value 数据

计数统计:

 继承Mapper类
 import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;


/*继承Mapper类
* */
public class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable> {

@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
   //将传入的k1拆分成一个字符串数组
    String[] split = value.toString().split(",");
    2:遍历数组,组装 K2(Stiring 为Text) 和 V2(1),写入到上下文中
    for (String s : split) {
        context.write(new Text(s),new LongWritable(1));
    }
}
}

继承Reducer类

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;

/*继承Reduce类
*   老的 KEYIN:  K2类型
   VALULEIN: V2类型

KEYOUT: K3类型
VALUEOUT:V3类型
* */
public class MyReduce extends Reducer<Text,LongWritable,Text,LongWritable> {

/* 参数:
    key : 新K2
    values: 集合 新 V2 <1,1,1,1>
    context :表示上下文对象*/
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        //将k2变成K3

    long count =0;
    for (LongWritable value : values) {
        count += value.get();
    }
    //将新的组装的k3 v3赋值给上下文
    context.write(key,new LongWritable(count));
}
}

定义主类, 描述 Job 并提交 Job

 import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
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.TextInputFormat;
	import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import java.net.URI;

/*
* MapReduce练习
*  定义主类, 描述 Job 并提交 Job
* */
public class Mytest extends Configured implements Tool {
//该方法用于指定一个Job任务
@Override
public int run(String[] strings) throws Exception {
    //创建一个Job任务对象
    Job job = Job.getInstance(super.getConf(), Mytest.class.getName());
    //配置job任务对象(8个步骤)
    //第一步:指定文件的读取方式和读取路径
    job.setInputFormatClass(TextInputFormat.class);
    TextInputFormat.addInputPath(job,new Path("hdfs://node01:8020/mulu/wordcount.txt"));
    //第二步:指定Map阶段的处理方式和数据类型
    job.setMapperClass(MyMapper.class);
    //设置Map阶段K2的类型
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(LongWritable.class);
    //第3到6步采用默认
    //第七步指定reduce阶段的处理方式和数据类型
    job.setReducerClass(MyReduce.class);
    //设置K3V3的输出类型
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(LongWritable.class);
    //第8步设置输出路径和类型
    job.setOutputFormatClass(TextOutputFormat.class);

    //路径
    Path path = new Path("hdfs://node01:8020/MY");
    TextOutputFormat.setOutputPath(job,path);

    //获取FileSystem
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020/MY"), new Configuration());

    boolean b = fileSystem.exists(path);
    if(b){
        fileSystem.delete(path,true);
    }
    //等待任务接收
    boolean b1 = job.waitForCompletion(true);
    return b1?0:1;
}

public static void main(String[] args) throws Exception {
    Configuration configuration = new Configuration();

    //启动任务
    int run = ToolRunner.run(configuration, new Mytest(), args);
    System.exit(run);
}
}

分区

继承Mapper类
/*定义一个mapper ,不做处理,只接收数据*/
public class MyMapperone  extends Mapper<LongWritable,Text,Text,NullWritable>{
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

    Counter counter = context.getCounter("MY_LEIXI", "MY_COUNT");
    counter.increment(1L);
    //key的值和k1的value一样,value 为空
    context.write(value,NullWritable.get());
}

继承Partitioner类(分区)

/*进行分区*/
public class MyPartitioner extends Partitioner<Text,NullWritable>{
@Override
public int getPartition(Text text, NullWritable nullWritable, int i) {
    //获取需要的数据,索引为5的数据
    String s = text.toString().split("\t")[5];
    if(Integer.parseInt(s) >15){
        return 1;
    }
    return 0;
}

继承Reducer类

	/*Reducer ,分区之后的数据为索引第5的数据,不需要进行转换可以直接输出
* */
	public class MyReducer extends 	Reducer<Text,NullWritable,Text,NullWritable> {
@Override
protected void reduce(Text key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {

    context.write(key,NullWritable.get());
}

定义主类, 描述 Job 并提交 Job

//分区后job定义和操作
public class FenQu extends Configured implements Tool{
@Override
public int run(String[] strings) throws Exception {
    //创建job对象
    Job job = Job.getInstance(super.getConf(), FenQu.class.getName());
    //对JOB进行操作
    //第一步:设置输入类型和输入的路径
    job.setInputFormatClass(TextInputFormat.class);
    TextInputFormat.setInputPaths(job,new Path("hdfs://node01:8020/mulu/partition.csv"));

    //第二步:设置mapper类和输出的数据类型
    job.setMapperClass(MyMapperone.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(NullWritable.class);

    //第三部(指定分区)
    job.setPartitionerClass(MyPartitioner.class);
    //第4.5.6 省略
    //第7步指定输出的Reducer类和数据类型
    job.setReducerClass(MyReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(NullWritable.class);

    //设置分区的ReduceTasks个数
    job.setNumReduceTasks(2);
    //第8步:指定输出类和路径
    job.setOutputFormatClass(TextOutputFormat.class);
    TextOutputFormat.setOutputPath(job,new Path("hdfs://node01:8020/MY2"));

    boolean b = job.waitForCompletion(true);


    return b?0:1;
    }

public static void main(String[] args) throws Exception {
    Configuration configuration = new Configuration();
    //启动任务
    int run = ToolRunner.run(configuration, new FenQu(), args);
    //退出
    System.exit(run);
    }
    }

集群运行模式

  1. 将 MapReduce 程序提交给 Yarn 集群, 分发到很多的节点上并发执行
  2. 处理的数据和输出结果应该位于 HDFS 文件系统
  3. 提交集群的实现步骤: 将程序打成JAR包,并上传,然后在集群上用hadoop命令启动
    hadoop jar 打包上传的文件路径 主方法的路径

本地运行模式

  1. MapReduce 程序是在本地以单进程的形式运行
  2. 处理的数据及输出结果在本地文件系统(输入输出的路径改成本地即可)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值