weather案例, 简单分析每年的前三个月的最高温即可, 使用自定义的分组和排序

设计分析

    • 设定多个reduce

      • 每年的数据都很多,如果按照默认情况处理,统计性能是非常慢(因为默认只有一个reduce),所以我们需要重新分配reduceTask,将一年的数据交给一个reduceTask处理,
    • 分区 
      • 那个数据交给哪个reduceTask处理是有Patitioner决定(patition对每个map输出的数据分配置一个分区号这个分区号决定map输出数据送到那个reudeTask),
    • 自定义分区 
      • 由于我们是将一年的数据交给一个reduce处理,但是默认分区是按照key.hashCode()的值 模 reduceTask数量得到分区号,所以我们需要重写分区,
    • 自定义排序

      • 由于我们是要每月最该的三个温度,所以需要对温度进行排序,所以在洗牌(shuffler)过程中自定义sort,
    • 自定义分组

      • 分组的目的:是按照实际的需求,将数据分成一个个组, 传给reduceTask,我们的需求是统计每年每月温度最高的三个,如果一组数据就是这一年的数据,我们对着一年的数据进行统计,是很复杂的,如果我们将每月的数据分成一个组,这样就会方便多了, 默认的分组是按照key是否相同进行分组,所以我们要自定义分组
    • 自定义key 
      • 默认的partition是根据key的hashcode模reduceTask数量,得到分区号
      • 默认的排序是根据key的字典排序
      • 默认的分组是根据key相同,进行比较进行分组
      • 这几个都与key与联系, 所以我们需要影响这些步骤的因素添加到key中,
      • 根据上面分析,partition与年有关,sort与温度有关,分组和月份有关
      • 总结:所以key中需要包含year, month, T

1, MyKey,

因为对温度进行分组, 排序, pardition操作, 所以默认的字典顺序不能满足需求

*** 自定义的key中的数据, 必须在构造中进行初始化, 否则报 NullpointException

package com.wenbronk.weather;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; import org.apache.hadoop.io.WritableComparable; /**
* 自定义key, 对key进行分组
* 实现writableComparble方法, 可序列化并比较是否同一个对象
* @author root
*
*/
public class MyKey implements WritableComparable<MyKey> { private int year;
private int month;
private double hot; public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public double getHot() {
return hot;
}
public void setHot(double hot) {
this.hot = hot;
} /**
* 反序列化
*/
@Override
public void readFields(DataInput arg0) throws IOException {
this.year = arg0.readInt();
this.month = arg0.readInt();
this.hot = arg0.readDouble();
} /**
* 序列化
*/
@Override
public void write(DataOutput arg0) throws IOException {
arg0.writeInt(year);
arg0.writeInt(month);
arg0.writeDouble(hot);
} /**
* 比较, 判断是否同一个对象, 当对象作为key时
*/
@Override
public int compareTo(MyKey o) {
int c1 = Integer.compare(this.year, o.getYear());
if (c1 == ) {
int c2 = Integer.compare(this.month, o.getMonth());
if (c2 == ) {
return Double.compare(this.hot, o.getHot());
}
}
return ;
} }

2, sort

package com.wenbronk.weather;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator; /**
* 自定义排序
* @author root
*/
public class MySort extends WritableComparator { /**
* 在构造方法中, 通过调用父类构造创建MyKey
* MyKey.class : 比较的对象
* true : 创建这个对象
*/
public MySort() {
super(MyKey.class, true);
} /**
* 自定义排序方法
* 传入的比较对象为 map 输出的key
*
* 年相同比较月, 月相同, 温度降序
*/
@Override
public int compare(WritableComparable a, WritableComparable b) {
MyKey key1 = (MyKey) a;
MyKey key2 = (MyKey) b; int r1 = Integer.compare(key1.getYear(), key2.getYear());
if (r1 == ) {
int r2 = Integer.compare(key1.getMonth(), key2.getMonth()); if (r2 == ) {
// 温度降序
return - Double.compare(key1.getHot(), key2.getHot());
}else {
return r2;
}
}
return r1;
} }

3, group

package com.wenbronk.weather;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator; /**
* 自定义分组
* @author root
*
*/
public class MyGroup extends WritableComparator { public MyGroup() {
super(MyKey.class, true);
} /**
* 年, 月相同, 则为一组
*/
@Override
public int compare(WritableComparable a, WritableComparable b) {
MyKey key1 = (MyKey) a;
MyKey key2 = (MyKey) b; int r1 = Integer.compare(key1.getYear(), key2.getYear());
if (r1 == ) {
return Integer.compare(key1.getMonth(), key2.getMonth());
}
return r1;
} }

4, parditon

package com.wenbronk.weather;

import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.mapreduce.lib.partition.HashPartitioner; /**
* 自定义partition, 保证一年一个reducer进行处理
* 从map接收值
* @author root
*
*/
public class MyPartition extends HashPartitioner<MyKey, DoubleWritable> { /**
* maptask每输出一个数据, 调用一次此方法
* 执行时间越短越好
* 年的数量是确定的, 可以传递reduceTask数量, 在配置文件可设置, 在程序执行时也可设置
*
*/
@Override
public int getPartition(MyKey key, DoubleWritable value, int numReduceTasks) {
// 减去最小的, 更精确
return (key.getYear() - ) % numReduceTasks;
} }

5, 执行类

package com.wenbronk.weather;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; /**
* 执行mapreduce 统计每年温度的前三个
*
* @author wenbronk
*
*/
public class RunMapReduce { public static void main(String[] args) throws Exception {
// 初始化时加载src或classpath下所有的配置文件
Configuration configuration = new Configuration(); // 本地执行
configuration.set("fs.default", "hdfs://wenbronk.hdfs.com:8020 ");
configuration.set("yarn.resourcemanager", "hdfs://192.168.208.106"); // 服务器执行
// configuration.set("mapred.jar", "‪C:/Users/wenbr/Desktop/weather.jar");
// configuration.set("mapred.jar", "E:\\sxt\\target\\weather.jar");
// configuration.set("mapreduce.app-submission.cross-platform", "true");
//
// configuration.set("mapreduce.framework.name", "yarn");
// configuration.set("yarn.resourcemanager.address", "192.168.208.106:"+8030);
// configuration.set("yarn.resourcemanager.scheduler.address", "192.168.208.106:"+8032); // 得到执行的任务
Job job = Job.getInstance();
// 入口类
job.setJarByClass(RunMapReduce.class); // job名字
job.setJobName("weather"); // job执行是map执行的类
job.setMapperClass(WeatherMapper.class);
job.setReducerClass(WeatherReduce.class);
job.setMapOutputKeyClass(MyKey.class);
job.setMapOutputValueClass(DoubleWritable.class); // 使用自定义的排序, 分组
job.setPartitionerClass(MyPartition.class);
job.setSortComparatorClass(MySort.class);
job.setGroupingComparatorClass(MyGroup.class);
// job.setJar("E:\\sxt\\target\\weather.jar"); //设置 分区数量
job.setNumReduceTasks(); // **** 使用插件上传data.txt到hdfs/root/usr/data.txt //****使得左边为key, 右边为value, 此类默认为 "\t" 可以自定义
// 或者 config.set("mapreduce.input.keyvaluelinerecordreader.key.value.separator", "\t");
job.setInputFormatClass(KeyValueTextInputFormat.class); // 使用文件
FileInputFormat.addInputPath(job, new Path("E:\\sxt\\1-MapReduce\\data\\weather.txt"));
// FileInputFormat.addInputPath(job, new Path("/root/usr/weather.txt")); // 使用一个不存在的目录进行
Path path = new Path("/root/usr/weather");
// 如果存在删除
FileSystem fs = FileSystem.get(configuration);
if (fs.exists(path)) {
fs.delete(path, true);
} // 输出
FileOutputFormat.setOutputPath(job, path); boolean forCompletion = job.waitForCompletion(true); if (forCompletion) {
System.out.println("success");
}
} /**
* key: 将 LongWritalbe 改成 Text类型的
*
* 将输入更改为需要的 key, value, mapper所做的事情
*
* @author wenbronk
*/
static class WeatherMapper extends Mapper<Text, Text, MyKey, DoubleWritable> {
/**
* 转换字符串为日期对象
*/
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /**
* 将键值取出来, 封装为key 每行第一个分隔符"\t"左侧为key, 右侧有value, 传递过来的数据已经切割好了
*/
@Override
protected void map(Text key, Text value, Mapper<Text, Text, MyKey, DoubleWritable>.Context context)
throws IOException, InterruptedException {
try {
Date date = formatter.parse(key.toString());
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH); double hot = Double.parseDouble(value.toString().substring(, value.toString().lastIndexOf("c"))); MyKey mykey = new MyKey();
mykey.setYear(year);
mykey.setMonth(month);
mykey.setHot(hot); context.write(mykey, new DoubleWritable(hot));
} catch (ParseException e) {
e.printStackTrace();
}
}
} /**
* 经过partition, 分组, 排序, 传递数据给reducer 需要自定义partition, 保证一年一个reduce 自定义排序,
* 保证按照年, 月, 温度 自定义分组, 年月相同, 一个组
* 传进来的温度, 为已经排好序的
* @author root
*/
static class WeatherReduce extends Reducer<MyKey, DoubleWritable, Text, NullWritable> {
NullWritable nullWritable = NullWritable.get();
@Override
protected void reduce(MyKey arg0, Iterable<DoubleWritable> arg1,
Reducer<MyKey, DoubleWritable, Text, NullWritable>.Context arg2)
throws IOException, InterruptedException { int i = ;
for (DoubleWritable doubleWritable : arg1) {
i++;
String msg = arg0.getYear() + "\t" + arg0.getMonth() + "\t" + doubleWritable.get();
// key中已经包含需要的结果了
arg2.write(new Text(msg), NullWritable.get());
// 每个月的前三个
if (i == ) {
break;
}
} }
} }

初始文档

-- ::    34c
-- :: 36c
-- :: 32c
-- :: 37c
-- :: 23c
-- :: 41c
-- :: 27c
-- :: 45c
-- :: 46c
-- :: 47c

系列来自尚学堂视频

https://blog.csdn.net/wuxintdrh/article/details/54917232

18-hadoop-weather案例的更多相关文章

  1. hadoop经典案例

    hadoop经典案例http://blog.csdn.net/column/details/sparkhadoopdemo.html

  2. Hadoop Mapreduce 案例 wordcount+统计手机流量使用情况

    mapreduce设计思想 概念:它是一个分布式并行计算的应用框架它提供相应简单的api模型,我们只需按照这些模型规则编写程序,即可实现"分布式并行计算"的功能. 案例一:word ...

  3. python + hadoop (案例)

    python如何链接hadoop,并且使用hadoop的资源,这篇文章介绍了一个简单的案例! 一.python的map/reduce代码 首先认为大家已经对haoop已经有了很多的了解,那么需要建立m ...

  4. Hadoop序列化案例实操

    需求 统计每一个手机号耗费的总上行流量.下行流量.总流量. 输入数据: 1 13736230513 192.196.100.1 www.atguigu.com 2481 24681 200 2 138 ...

  5. Linux包系列的知识(附:Ubuntu16.04升级到18.04的案例)

    Linux基础:https://www.cnblogs.com/dunitian/p/4822808.html#linux 之前看到朋友还动不动 apt-get update upgrade,就很纳闷 ...

  6. hadoop 天气案例

    对下面一组气温数据进行处理,得到每个月份最高的两个气温值 2018-12-12 14:30 25c2018-12-12 15:30 26c2017-12-12 12:30 36c2019-01-01 ...

  7. 18 Loader代码案例

    目录结构: MainActivity.java 代码: package com.qf.day18_loader_demo2; import android.app.Activity; import a ...

  8. Hadoop经典案例(排序&Join&topk&小文件合并)

    ①自定义按某列排序,二次排序 writablecomparable中的compareto方法 ②topk a利用treemap,缺点:map中的key不允许重复:https://blog.csdn.n ...

  9. 18.Selenium+Python案例 -- 豆瓣

    一.具体代码实现: from selenium import webdriver driver = webdriver.Firefox() driver.get('https://www.douban ...

  10. hadoop面试题答案

    Hadoop 面试题,看看书找答案,看看你能答对多少(2) 1. 下面哪个程序负责 HDFS 数据存储.a)NameNode  b)Jobtracker  c)Datanode d)secondary ...

随机推荐

  1. java基础-day15

    第01天 java面向对象 今日内容介绍 u 包和权限修饰符 u 内部类 第1章   包和权限修饰符 1.1      包的概述 java的包,其实就是我们电脑系统中的文件夹,包里存放的是类文件. 当 ...

  2. POJ1446 Girls and Boys

    Girls and Boys Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 12747   Accepted: 5678 D ...

  3. 二分搜素——(lower_bound and upper_bound)

    因为每个人二分的风格不同,所以在学习二分的时候总是被他们的风格搞晕.有的人二分风格是左闭右开也就是[L,R),有的人是左开右闭的(L,R]. 二分的最基本条件是,二分的序列需要有单调性. 下面介绍的时 ...

  4. bootstrap阶段测验【答案】

    <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...

  5. Android中去掉标题栏

    在Android中去掉标题栏有三种方法,它们也有各自的特点. 1.在代码里实现 this.requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏 记 ...

  6. 异步多线程 Thread ThreadPool Task

    一.线程 Thread ThreadPool 线程是Windows任务调度的最小单位,线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以 ...

  7. Android-HttpClient-Get与Post请求登录功能

    HttpClient 是org.apache.http.* 包中的: 第一种方式使用httpclient-*.jar (需要在网上去下载httpclient-*.jar包) 把httpclient-4 ...

  8. MAC系统下用Idea创建spring boot工程 基于maven

    1.创建项目 打开idea编辑器,选择file  -> new -> project 点击next 依次填入group,artifact 填写完成之后再点击“next” 根据自己的需求在最 ...

  9. js 将一个数组插入到另一个数组的方法

    JavaScript将一个数组插入到另一个数组的方法.分享给大家供大家参考.具体分析如下: 1.通过Array.prototype.push.apply方法将一个数组插入到另外一个数组,下面的代码将数 ...

  10. 02_python_while循环/格式化输出/逻辑运算

    一. while循环 1.基本形式 while 条件: 循环体 # 判断条件是否为真,如果真,执行代码块.然后再次判断条件是否为真.如果真继续执行代码块...直到条件变成了假.循环退出 ps:死循环 ...