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. 用 gdb 调试 GCC 程序

    Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的 ...

  2. Linq动态查询与模糊查询 ---转

    Linq动态查询与模糊查询(带源码示例) 继LINQ动态组合查询PredicateExtensions讲解 ----- 在用上面的方法时遇到了些问题 解决 LINQ to Entities 不支持 L ...

  3. JavaScript 获取鼠标点击位置坐标

    在一些DOM操作中我们经常会跟元素的位置打交道,鼠标交互式一个经常用到的方面,令人失望的是不同的浏览器下会有不同的结果甚至是有的浏览器下没结果,这篇文章就上鼠标点击位置坐标获取做一些简单的总结,没特殊 ...

  4. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  5. day09_雷神_模块二

    day09 序列化之json 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊 ...

  6. Python自动化开发 - 内置函数总结

    Python解释器提供了很多内置函数 参考链接:https://docs.python.org/3.6/library/functions.html 一.数学相关 1.绝对值:abs(-1) 2.最大 ...

  7. 如何获取 docker 容器(container)的 ip 地址

    1. 进入容器内部后 cat /etc/hosts 会显示自己以及(– link)软连接的容器IP 2.使用命令 docker inspect --format '{{ .NetworkSetting ...

  8. DFS遍历中forward、backward以及cross边的界定

    再来看以下具体例子:

  9. Docker 持续集成初次体验

    背景 在家的时候,实在不想做其他的,想起之前参加的一场关于docker的座谈会,于是想搞以下docker. 开始 在道客云上搞了一下持续集成,总体来说,比较好用的. 写了一个Go程序,就是之前写的发邮 ...

  10. SignalR2简易数据看板演示

    软件环境: 1.vs2015.windows7..net4.5 演示说明: 当点击按钮的时候,柱状图数值加1并实时变化 1.首先打开vs2015创建一个mvc项目,并安装SignalR2,具体操作可参 ...