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. MATLAB二分法函数求根

    function xc = bisect(f,a,b,tol) ind = b-a; while ind > tol xx = (a+b)/; b = xx; else a = xx; end ...

  2. MapServer和GeoServer对比

    https://blog.csdn.net/theonegis/article/details/45823099

  3. 【repost】Javascript操作DOM常用API总结

    Javascript操作DOM常用API总结 文本整理了javascript操作DOM的一些常用的api,根据其作用整理成为创建,修改,查询等多种类型的api,主要用于复习基础知识,加深对原生js的认 ...

  4. _编程语言_C++_Lambda函数与表达式

    C++11提供了对匿名函数的支持,称为Lambda表达式函数 Lambda 表达式把函数看作对象.Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值 ...

  5. oracle数据库 ORA-01017的解决办法

    alter user 用户名 identified by 新密码:

  6. iOS笔记之UIKit_UIButton

    //UIButton的基本属性 _btn = [UIButton buttonWithType:UIButtonTypeCustom]; _btn.frame = CGRectMake(0, 200, ...

  7. Python自动化开发 - 函数

    本节内容 函数背景介绍 函数是什么 参数与局部变量 返回值 递归函数 匿名函数 函数式编程介绍 高阶函数 一.函数背景介绍 老板让你写一个监控程序,监控服务器的系统状况,当cpu/memory/dis ...

  8. iOS_UIWebView字体大小、字体颜色、背景色

    前段时间需要修改webView背景色,上stackoverflow搜了很久没有找到结果,百度搜索,各种转载,各种坑爹,搜出来的都只有字体大小和字体颜色,页面背景没有看到,本人发布方法,希望可以帮助到更 ...

  9. 在 Centos7 的KVM上启用嵌套虚拟化

    1.嵌套虚拟化意味着在虚拟机内配置虚拟化环境.换句话说,我们可以说嵌套虚拟化是虚拟机管理程序hypervisor的一个特性,它允许我们通过虚拟化管理程序(宿主机)的硬件加速在虚拟服务器内安装和运行虚拟 ...

  10. Winform DataGridView控件在业务逻辑上的简单使用

    需要对文字列表进行处理,然后用到DataGridView控件来处理,记录一下.效果如下: 主要是想通过禁用和取消单元格选择来使图标单元格呈现出鼠标点击的效果.因为有个单元格选择的问题困扰着我. 是这样 ...