版权说明:  本文章版权归本人及博客园共同所有,转载请标明原文出处(http://www.cnblogs.com/mikevictor07/),以下内容为个人理解,仅供参考。

一、简介

该实例统计国内各个站点的最高温度(为节省篇幅只以温度为例,可稍作修改即可统计气压与风速),数据来源于汇总在NCDC的天气气球数据集中(包含世界大量数据集,该实例只分析国内站点,数据对外公开,可下载)。

二、数据准备与预处理

从NCDC下载的天气气球数据集(ftp://ftp.ncdc.noaa.gov/pub/data/igra或http://www1.ncdc.noaa.gov/pub/data/igra/ , 压缩为gz包)如下,可见并不适合Hadoop的MR模块处理,需要进行预处理(本例下载数据gz包总大小为293MB,解压缩后为1.43GB):

#5928719630901009999   5
10 85000 1481B 202B-9999 190 20
10 70000 3139B 142B-9999 180 20
10 50000 5880B -55B-9999 60 30
10 40000 7605B -142B-9999 100 40
10 30000 9750B -255B-9999 100 70
#5928719630901129999 7
10 85000 1481B 215B-9999 320 20
10 70000 3142B 132B-9999 300 10
10 50000 5889B -35B-9999 50 30
10 40000 7620B -125B-9999 100 40
10 30000 9759B -275B-9999 70 60
10 20000 12561B -482B-9999 90 110
10 10000 16788B -785B-9999 90 100

首先需要阅读下载相关目录的readme.txt,才能站点相关字段的含义,温度数据已经*10(为了保留一位小数)

以该数据为例(其中的 9999一般代表数据缺失):

#5052719630901009999 5
10 85000 1314B 68B-9999-9999-9999

数据头部
标识 站点编号 日期 观察起始时间 观察结束时间 记录数
# 50527 19630901 00 9999 5
数据记录          
Major Level Minor Level 气压(Pa)3-8 气压标识 位势高度(米)10-14 位势高度标识 温度*10(16- 20位) 温度标识 露点下降 风力方向 风速(m/s)
1 0 85000 空格 1314 B 68 B -9999 -9999 -9999

由于MapReduce一行行处理数据,而该数据记录部分依赖于数据头部,MR对数据进行分区时对它们分开的可能性非常大,所以每条数据记录部分必须加上头部的部分信息(根据需要确定),即预处理,对数据预处理的结果可输出到本地,然后再拷贝至HDFS。

在本例中,数据头部只关注<站点编号>、<日期>,数据头部与数据记录形成的新格式如下:

预处理后的数据格式              
505271963090110 85000  1314B   68B-9999-9999-9999                
站点编号 日期 Major Level Minor Level 气压(Pa) 气压标识 位势高度(米)10-14位 位势高度标识 温度*10 温度标识 露点下降 风力方向 风速(m/s)
50527 19630901 1 0 85000 空格 1314 B 68 B -9999 -9999 -9999

即如下面格式的新格式:

592871963090110 85000  1481B  202B-9999  190   20
592871963090110 70000 3139B 142B-9999 180 20
592871963090110 50000 5880B -55B-9999 60 30

三、数据拷贝至HDFS

数据从本地拷贝至HDFS可以通过编码,也可使用eclipse的hadoop插件进行(该插件目前一般需要根据自己的环境编译得到jar放入eclipse的plugins文件夹下,过程稍微繁琐),

当然也可以使用bin/hadoop工具copyFromLocal进行(不过需要先复制到集群中的任意一台机器),本例中把数据存放在HDFS的 /weatherballoon 目录下,以下代码可供参考:

core-site.xml:不同的配置文件方便本地测试和集群切换,在MR程序调试的时候很有用

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://hbase-01:9000</value>
</property>
</configuration>
public class CopyFromLocalMain {

    private static Configuration config = new Configuration();

    public static void main(String[] args) throws Exception {
config.addResource("core-site.xml");
File inputDir = new File("d:/weatherballoon/input/");
String hdfsDir = "/weatherballoon/input/"; if (!inputDir.exists()) {
System.err.println(inputDir.getAbsolutePath() + " directory not exist .");
System.exit(-1);
}
File[] files = inputDir.listFiles();
if (files == null) {
System.err.println(inputDir.getAbsolutePath() + " directory is empty .");
System.exit(-1);
} for (File file : files) {
copyFileToHdfs(file, hdfsDir + file.getName());
}
System.out.println("Copy finished, total: " + files.length);
}
public static void copyFileToHdfs(File local,String dest) throws IOException{
InputStream in = new BufferedInputStream(new FileInputStream(local));
FileSystem fs = FileSystem.get(config);
FSDataOutputStream out = fs.create(new Path(dest));
IOUtils.copyBytes(in, out, 4096, true);
out.close();
}
}

数据拷贝完毕后可访问HDFS的namenode查看状态(默认50070端口),本例状态如下图:

四、编写MapReduce程序

目前的数据格式已经每行之间无依赖性,首先编辑Mapper部分,该部分用于把站点ID作为key的数据集存入OutputCollector中:

public class MaxTemperatureMapper
extends MapReduceBase implements Mapper<LongWritable, Text, Text, RecordValue>{ public static final int DATA_LENGTH = 49; //预处理后的数据行长度 @Override
public void map(LongWritable key, Text value,
OutputCollector<Text, RecordValue> output, Reporter reporter) throws IOException { //505271963090110 85000 1314B 68B-9999-9999-9999
String line = value.toString();
if (line.length() != DATA_LENGTH) {
System.out.println("------------->Error record : " + line);
return;
} String stationId = line.substring(0, 5);
String date = line.substring(5, 13);
String temp = line.substring(28, 33);
if (!missing(temp)) {
int temperature = Integer.parseInt(temp.trim());
output.collect(new Text(stationId), new RecordValue(date, temperature));
}
} private boolean missing(String temp) {
return temp.equals("-9999");
} }

Mapper中输出的Value值为自定义的类型(即RecordValue),因为需要同时记录日期和温度,如果要自定义类型,则必须实现Writable(如Hadoop自带的LongWritable,IntWritable,Text等)。

实现该接口使得对象能够序列化在不同机器间传输(进程间采用RPC通信,Hadoop采用Avro序列化,其他比较流行的序列化框架有Apache Thrift和Google protocol buffers),

一般建议实现WritableComparable接口,该接口中有个compareTo 方法的实现对于MapReduce来说是比较重要的,用于基于键的中间结果排序。

也可以实现RawComparator ,即可在字节流中排序,而不需要反序列化,减小额外开销。

RecordValue的实现如下:

public class RecordValue implements WritableComparable<RecordValue>{

    private String date;
private int temperature; public RecordValue(){}
public RecordValue(String date, int temperature) {
this.date = date;
this.temperature = temperature;
}
@Override
public void write(DataOutput out) throws IOException {
out.write(date.getBytes());
out.writeInt(temperature);
}
@Override
public void readFields(DataInput in) throws IOException {
byte[] buff = new byte[8];
in.readFully(buff);
date = new String(buff);
temperature = in.readInt();
}
@Override
public int compareTo(RecordValue o) {
if (date.compareTo(o.getDate()) > 0 || temperature > o.getTemperature()) {
return 1;
}
return -1;
}
@Override
public String toString() {
return " -- " + date + "," + temperature;
} //省略setter getter
}

Mapper部分需要做单元测试,成功后接下面编写Reducer部分:

public class MaxTemperatureReducer extends MapReduceBase implements
Reducer<Text, RecordValue, Text, RecordValue> { @Override
public void reduce(Text key, Iterator<RecordValue> values,
OutputCollector<Text, RecordValue> output, Reporter reporter)
throws IOException { int maxValue = Integer.MIN_VALUE;
String date = "00000000";
while (values.hasNext()) {
RecordValue record = values.next();
int temp = record.getTemperature();
if (temp > maxValue) {
maxValue = temp;
date = record.getDate();
}
}
output.collect(key, new RecordValue(date, maxValue));
} }

当Reduce部分单元测试成功后即可编写驱动程序MaxTemperatureDriver,先用本地小数据集进行测试,配置文件切换为本地配置,如:

public static void main(String[] args) throws IOException {

        String inputPath = "file:///d:/weatherballoon/input/*";
String outputPath = "file:///d:/weatherballoon/output"; File out = new File("d:/weatherballoon/output");
if (out.exists()) {
FileUtils.forceDelete(out); //采用apache common io包
} Configuration conf = new Configuration();
conf.addResource("core-site-local.xml"); JobConf job = new JobConf(conf);
job.setJobName("Max Temperature(NCDC)");
job.setMapperClass(MaxTemperatureMapper.class);
job.setReducerClass(MaxTemperatureReducer.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(RecordValue.class); FileInputFormat.addInputPath(job, new Path(inputPath));
FileOutputFormat.setOutputPath(job, new Path(outputPath));
JobClient.runJob(job);
}

运行程序,如果出错则在本地容易查出错误地方,查看输出结构是否如何预期,下面是本例小部分数据集的输出结果:

50527 -- 20040721,358
50557 -- 20100627,342
50603 -- 19730409,440

温度已经乘以10,故对应的结果如下表格:

站点ID 日期 温度(摄氏度)
50527 20040721 35.8
50557 20100627 34.2
50603 19730409 44.0

五、集群运行

测试成功后可切换至集群运行,更改MaxTemperatureDriver的main,如下:

public static void main(String[] args) throws IOException {

        String inputPath = "/weatherballoon/input/";
String outputPath = "/weatherballoon/output"; Configuration conf = new Configuration(); JobConf job = new JobConf(conf);
job.setJobName("Max Temperature(NCDC)");
job.setMapperClass(MaxTemperatureMapper.class);
job.setReducerClass(MaxTemperatureReducer.class);
job.setJarByClass(MaxTemperatureDriver.class); //!important job.setOutputKeyClass(Text.class);
job.setOutputValueClass(RecordValue.class); FileInputFormat.addInputPath(job, new Path(inputPath));
FileOutputFormat.setOutputPath(job, new Path(outputPath));
JobClient.runJob(job);
}

然后程序打包(编写MANIFEST.MF):

Manifest-Version: 1.0
Class-Path: .
Main-Class: org.mike.hadoop.weatherballoon.MaxTemperatureDriver

eclipse->export->jar并选择MANIFEST.MF文件,把jar上传到集群任一节点,执行如下命令:

hadoop jar MaxTemperature.jar

运行如下图:

成功后即可从HDFS拷贝结果文件至本地查看(或者直接hadoop dfs -cat也可以),本例得到的结果如下(列出小部分):

    -- ,
-- ,
-- ,
-- ,
-- ,
-- ,
-- ,
-- ,
-- ,
-- ,
-- ,

根据NCDN中igra-stations.txt文件得到对应的站点整理后如下:

站点ID 站点名称 日期 最高温度
50527 HAILAR 20040721 35.8
50557 NENJIANG 20100627 34.2
50603 CHIN-BARAG 19730409 44
50745 CHICHIHAR 19990413 38.6
50774 YICHUN 20100624 31.6
50834 TA KO TAI 19920428 42.6
50953 HARBIN 20010604 34.6
51076 ALTAY 19931031 50.6
51133 TA CHENG 19870716 60
51156 HOBOG SAIR 19860309 55.2
51232 BORDER STATION 19800802 22

Finished ..

Hadoop - 国内各站点最高温度、气压和风速统计的更多相关文章

  1. Hadoop的改进实验(中文分词词频统计及英文词频统计)(4/4)

    声明: 1)本文由我bitpeach原创撰写,转载时请注明出处,侵权必究. 2)本小实验工作环境为Windows系统下的百度云(联网),和Ubuntu系统的hadoop1-2-1(自己提前配好).如不 ...

  2. 【Cloud Computing】Hadoop环境安装、基本命令及MapReduce字数统计程序

    [Cloud Computing]Hadoop环境安装.基本命令及MapReduce字数统计程序 1.虚拟机准备 1.1 模板机器配置 1.1.1 主机配置 IP地址:在学校校园网Wifi下连接下 V ...

  3. hadoop自己写的最高温度程序源码

    package com.teset; import java.io.IOException; import java.util.StringTokenizer; import org.apache.h ...

  4. Hadoop国内主要发行版本

    Hadoop主要版本 目前国内使用的不收费的Hadoop版本主要包括以下3个: Apache hadoop Cloudera的CDH Hortonworks版本(Hortonworks Data Pl ...

  5. Linux系统国内镜像站点

    一,更换说明 第一步 备份 如centos, mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup ...

  6. Maven国内下载站点

    鉴于一些原因,从maven中央仓库download依赖包时,被各种折磨,下面就简单看下maven setting.xml的一些简单配置 先贴几个国内可用的maven repository连接: htt ...

  7. eclipse使用国内镜像站点安装插件

    把eclipse 4.x的界面改为经典样式 打开eclipse,菜单栏>windows>preference>general>appearance>theme>cl ...

  8. Android studio & SDK的国内有效站点。

    SDK.TOOLS的国内有效镜像节点: mirrors.zzu.edu.cn/android/repository/ 网上的地址只写了mirrors.zzu.edu.cn,有误,需要补齐后面的子目录才 ...

  9. Hadoop第8周练习—Pig部署及统计访问日志例子

    :搭建Pig环境 :计算每个IP点击次数 内容 运行环境说明 1.1     硬软件环境 线程,主频2.2G,6G内存 l  虚拟软件:VMware® Workstation 9.0.0 build- ...

随机推荐

  1. 匿名属性 anonymous property

    利用匿名属性可以用很简洁的语法来自动声明不可变(immutable)的元组(tuple)类型. 属性:在字段用来表示类型和对象的状态的前提下,希望状态不被随意的更改,字段一般应该设置为private, ...

  2. [转] (CQRS)命令和查询责任分离架构模式(一) 之 什么是CQRS

    什么是CQRS? 这个问题网上可以找到很多资料,未接触过的童鞋请先查看Udi Dahan, Grey Young, Rinat Abdullin,园子里dax.net,以及Jdon社区上的相关文章. ...

  3. 当mysql遇上PHP

    博客提纲 利用PHP连接mySQL数据库 两套接口:面向对象和面向过程 实现写改删查(CUBD)实例 通过prepare语句处理相同类型的不同SQL语句 通过bind_param()绑定参数,及相关注 ...

  4. Linux 开机引导流程

    Linux 开机启动流程 BIOS(Basic Input Output System)是 PC 机启动时加载的第一个软件.其实,它是一组固化到计算机主板上一个芯片上的程序,它保存着计算机最重要的输入 ...

  5. java中常用的并发工具类

    · 1. 等待多线程完成的CountDownLatch 构造函数接收一个int类型的参数作为计数器,如果想等待N个点,就传入N.当调用CountDownLatch的countDown方法时,N就会减一 ...

  6. java 字符串替换函数replaceAll 一次同时替换多个字符串

    public static void main(String[] args) throws Exception { String src = "南京市玄武区北京东路徐州市鼓楼区戏马台&quo ...

  7. Kafka 源代码分析.

    这里记录kafka源代码笔记.(代码版本是0.8.2.1) kafka的源代码如何下载.这里简单说一下. git clone https://git-wip-us.apache.org/repos/a ...

  8. 很好的复习资料: SQL语句到底怎么写 ?

    本文用到的数据库如下: CREATE DATABASE exam; /*创建部门表*/ CREATE TABLE dept( deptno INT PRIMARY KEY, dname VARCHAR ...

  9. 我的学习之路_第二十三章_HTML

    Html : 超级文本语言 ( Hyper text Markup Language ) HTML 文件扩展名是 * .html HTML 结构都是有标签组成 通常情况下标签有开始标签和结束标签组成 ...

  10. Bootstrap table使用心得---thead与td无法对齐的问题

    当使用工具条中的显示/隐藏列的时候, 经常出现表格的列头与内容无法对齐的问题. 1. 去掉option中的height,完美对齐,但当数据较多的时候,table会自动增加height,显示所有数据而不 ...