1、前言

HDF文件是遥感应用中一种常见的数据格式,因为其高度结构化的特点,笔者曾被怎样使用Hadoop处理HDF文件这个问题困扰过相当长的一段时间。于是Google各种解决方式,但都没有找到一种理想的处理办法。也曾參考过HDFGroup官方发的一篇帖子(网址在这里),里面提供了使用Hadoop针对大、中、小HDF文件的处理思路。尽管依据他提供的解决的方法,按图索骥,肯定能解决怎样使用Hadoop处理HDF文件这个问题,但个人感觉方法偏复杂且须要对HDF的数据格式有较深的理解,实现起来不太easy。于是乎,笔者又继续寻找解决方式,最终发现了一种办法,以下将对该方法进行详细说明。

2、MapReduce主程序

这里主要使用到了netcdf的库进行hdf数据流的反序列化工作(netcdf库的下载地址)。与HDF官方提供的Java库不同,netcdf仅利用Java进行HDF文件的读写操作,且这个库支持多种科学数据,包含HDF4、HDF5等多种格式。而HDF的官方Java库中,底层实际仍是用C进行HDF文件的操作。以下贴出MapReduce的Mapper函数代码:

package example;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.util.List; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; import ucar.ma2.ArrayShort;
import ucar.nc2.Dimension;
import ucar.nc2.Group;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable; public class ReadMapper extends
Mapper<Text, BytesWritable, Text, BytesWritable> { public void map(Text key, BytesWritable value, Context context)
throws IOException, InterruptedException {
String fileName = key.toString();
NetcdfFile file = NetcdfFile.openInMemory("hdf4", value.get());
Group dataGroup = (file.findGroup("MOD_Grid_monthly_1km_VI")).findGroup("Data_Fields");
//读取到1_km_monthly_red_reflectance的变量
Variable redVar = dataGroup.findVariable("1_km_monthly_red_reflectance");
short[][] data = new short[1200][1200];
if(dataGroup != null){
ArrayShort.D2 dataArray;
//读取redVar中的影像数据
dataArray = (ArrayShort.D2) redVar.read();
List<Dimension> dimList = file.getDimensions();
//获取影像的y方向像元个数
Dimension ydim = dimList.get(0);
//获取影像的x方向像元个数
Dimension xdim = dimList.get(1);
//遍历整个影像,读取出像元的值
for(int i=0;i<xdim.getLength();i++){
for(int j=0;j<ydim.getLength();j++){
data[i][j] = dataArray.get(i, j);
}
}
}
System.out.print(file.getDetailInfo());
}
}

注意程序中的NetcdfFile.openInMemory方法,该静态方法支持从byte[]中构造HDF文件,从而实现了HDF文件的反序列化操作。以下贴出主程序的演示样例代码:

package example;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.NullOutputFormat; import example.WholeFileInputFormat; public class ReadMain {
public boolean runJob(String[] args) throws IOException,
ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
// conf.set("mapred.job.tracker", Utils.JOBTRACKER);
String rootPath= "/opt/hadoop-2.3.0/etc/hadoop";
//String rootPath="/opt/hadoop-2.3.0/etc/hadoop/";
conf.addResource(new Path(rootPath+"yarn-site.xml"));
conf.addResource(new Path(rootPath+"core-site.xml"));
conf.addResource(new Path(rootPath+"hdfs-site.xml"));
conf.addResource(new Path(rootPath+"mapred-site.xml"));
Job job = new Job(conf); job.setJobName("Job name:" + args[0]);
job.setJarByClass(ReadMain.class); job.setMapperClass(ReadMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(BytesWritable.class); job.setInputFormatClass(WholeFileInputFormat.class);
job.setOutputFormatClass(NullOutputFormat.class);
FileInputFormat.addInputPath(job, new Path(args[1]));
FileOutputFormat.setOutputPath(job, new Path(args[2]));
boolean flag = job.waitForCompletion(true);
return flag;
} public static void main(String[] args) throws ClassNotFoundException,
IOException, InterruptedException {
String[] inputPaths = new String[] { "normalizeJob",
"hdfs://192.168.168.101:9000/user/hduser/hdf/MOD13A3.A2005274.h00v10.005.2008079143041.hdf",
"hdfs://192.168.168.101:9000/user/hduser/test/" };
ReadMain test = new ReadMain();
test.runJob(inputPaths);
} }

关于MapReduce主程序有几点值得说明一下:

1、MapReduce数据的输入格式为WholeFileInputFormat.class,即不正确数据进行切分。关于该格式,能够參考另外一篇博客:怎样通过Java程序提交Yarn的计算任务,这里不再赘述。

2、本人用的是Yarn2.3.0来运行计算任务,假设用老版本号的hadoop,如1.2.0,则把以上主程序中的conf.addResource部分的代码删掉就可以。

3、以上MapReduce程序中,仅仅用到了Map函数,未设置Reduce函数。

4、以上程序用到的为HDF4格式的数据,按理说,HDF5格式的数据应该也是支持的。

3、HDF数据的格式

因为HDF数据高度结构化,因此在netcdf库的使用中,须要使用类似于"标签"的方式来訪问HDF中的详细数据。以下贴出netcdf中读出来的HDF数据的详细格式信息(即使用file.getDetailInfo()函数,打印出来的信息):

注意,ReadMapper函数中出现的类似于“MOD_Grid_monthly_1km_VI”、"Data_Fields"等信息,即依据下面HDF数据的格式信息得到的。

netcdf D:/2005-274/MOD13A3.A2005274.h00v08.005.2008079142757.hdf {
variables:
char StructMetadata.0(32000); char CoreMetadata.0(40874); char ArchiveMetadata.0(6530); group: MOD_Grid_monthly_1km_VI {
variables:
short _HDFEOS_CRS;
:Projection = "GCTP_SNSOID";
:UpperLeftPointMtrs = -2.0015109354E7, 1111950.519667; // double
:LowerRightMtrs = -1.8903158834333E7, -0.0; // double
:ProjParams = 6371007.181, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0; // double
:SphereCode = "-1"; group: Data_Fields {
dimensions:
YDim = 1200;
XDim = 1200;
variables:
short 1_km_monthly_NDVI(YDim=1200, XDim=1200);
:long_name = "1 km monthly NDVI";
:units = "NDVI";
:valid_range = -2000S, 10000S; // short
:_FillValue = -3000S; // short
:scale_factor = 10000.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_EVI(YDim=1200, XDim=1200);
:long_name = "1 km monthly EVI";
:units = "EVI";
:valid_range = -2000S, 10000S; // short
:_FillValue = -3000S; // short
:scale_factor = 10000.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_VI_Quality(YDim=1200, XDim=1200);
:_Unsigned = "true";
:long_name = "1 km monthly VI Quality";
:units = "bit field";
:valid_range = 0S, -2S; // short
:_FillValue = -1S; // short
:Legend = "\n\t Bit Fields Description (Right to Left): \n\t[0-1] : MODLAND_QA [2 bit range]\n\t\t 00: VI produced, good quality \n\t\t 01: VI produced, but check other QA \n\t\t 10: Pixel produced, but most probably cloudy \n\t\t 11: Pixel not produced due to other reasons than clouds \n\t[2-5] : VI usefulness [4 bit range] \n\t\t 0000: Highest quality \n\t\t 0001: Lower quality \n\t\t 0010..1010: Decreasing quality \n\t\t 1100: Lowest quality \n\t\t 1101: Quality so low that it is not useful \n\t\t 1110: L1B data faulty \n\t\t 1111: Not useful for any other reason/not processed \n\t[6-7] : Aerosol quantity [2 bit range] \n\t\t 00: Climatology \n\t\t 01: Low \n\t\t 10: Average \n\t\t 11: High (11) \n\t[8] : Adjacent cloud detected; [1 bit range] \n\t\t 1: Yes \n\t\t 0: No \n\t[9] : Atmosphere BRDF correction performed [1 bit range] \n\t\t 1: Yes \n\t\t 0: No \n\t[10] : Mixed clouds [1 bit range] \n\t\t 1: Yes \n\t\t 0: No \n\t[11-13] : Land/Water Flag [3 bit range] \n\t\t 000: Shallow ocean \n\t\t 001: Land (Nothing else but land) \n\t\t 010: Ocean coastlines and lake shorelines \n\t\t 011: Shallow inland water \n\t\t 100: Ephemeral water \n\t\t 101: Deep inland water \n\t\t 110: Moderate or continental ocean \n\t\t 111: Deep ocean \n\t[14] : Possible snow/ice [1 bit range] \n\t\t 1: Yes \n\t\t 0: No \n\t[15] : Possible shadow [1 bit range] \n\t\t 1: Yes \n\t\t 0: No \n"; short 1_km_monthly_red_reflectance(YDim=1200, XDim=1200);
:long_name = "1 km monthly red reflectance";
:units = "reflectance";
:valid_range = 0S, 10000S; // short
:_FillValue = -1000S; // short
:scale_factor = 10000.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_NIR_reflectance(YDim=1200, XDim=1200);
:long_name = "1 km monthly NIR reflectance";
:units = "reflectance";
:valid_range = 0S, 10000S; // short
:_FillValue = -1000S; // short
:scale_factor = 10000.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_blue_reflectance(YDim=1200, XDim=1200);
:long_name = "1 km monthly blue reflectance";
:units = "reflectance";
:valid_range = 0S, 10000S; // short
:_FillValue = -1000S; // short
:scale_factor = 10000.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_MIR_reflectance(YDim=1200, XDim=1200);
:long_name = "1 km monthly MIR reflectance";
:units = "reflectance";
:valid_range = 0S, 10000S; // short
:_FillValue = -1000S; // short
:Legend = "\n\t The MIR band saved in the VI product is MODIS band 7 \n\t\t Bandwidth : 2105-2155 nm \n\t\t Band center: 2130 nm \n";
:scale_factor = 10000.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_view_zenith_angle(YDim=1200, XDim=1200);
:long_name = "1 km monthly view zenith angle";
:units = "degrees";
:valid_range = -9000S, 9000S; // short
:_FillValue = -10000S; // short
:scale_factor = 100.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_sun_zenith_angle(YDim=1200, XDim=1200);
:long_name = "1 km monthly sun zenith angle";
:units = "degrees";
:valid_range = -9000S, 9000S; // short
:_FillValue = -10000S; // short
:scale_factor = 100.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int short 1_km_monthly_relative_azimuth_angle(YDim=1200, XDim=1200);
:long_name = "1 km monthly relative azimuth angle";
:units = "degrees";
:valid_range = -3600S, 3600S; // short
:_FillValue = -4000S; // short
:scale_factor = 10.0; // double
:scale_factor_err = 0.0; // double
:add_offset = 0.0; // double
:add_offset_err = 0.0; // double
:calibrated_nt = 5; // int byte 1_km_monthly_pixel_raliability(YDim=1200, XDim=1200);
:long_name = "1 km monthly pixel raliability";
:units = "rank";
:valid_range = 0B, 3B; // byte
:_FillValue = -1B; // byte
:Legend = "\n\t Rank Keys: \n\t\t[-1]: Fill/No Data-Not Processed. \n\t\t [0]: Good data - Use with confidence \n\t\t [1]: Marginal data - Useful, but look at other QA information \n\t\t [2]: Snow/Ice - Target covered with snow/ice\n\t\t [3]: Cloudy - Target not visible, covered with cloud \n"; }
}
// global attributes:
:HDFEOSVersion = "HDFEOS_V2.9";
:_History = "Direct read of HDF4 file through CDM library; HDF-EOS StructMetadata information was read";
:HDF4_Version = "4.2.1 (NCSA HDF Version 4.2 Release 1-post3, January 27, 2006)";
:featureType = "GRID";
}

Hadoop处理HDF文件的更多相关文章

  1. Hadoop之HDFS文件操作常有两种方式(转载)

    摘要:Hadoop之HDFS文件操作常有两种方式,命令行方式和JavaAPI方式.本文介绍如何利用这两种方式对HDFS文件进行操作. 关键词:HDFS文件    命令行     Java API HD ...

  2. hadoop对于压缩文件的支持及算法优缺点

    hadoop对于压缩文件的支持及算法优缺点   hadoop对于压缩格式的是透明识别,我们的MapReduce任务的执行是透明的,hadoop能够自动为我们 将压缩的文件解压,而不用我们去关心. 如果 ...

  3. Hadoop HDFS分布式文件系统设计要点与架构

      Hadoop HDFS分布式文件系统设计要点与架构     Hadoop简介:一个分布式系统基础架构,由Apache基金会开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群 ...

  4. 在本机eclipse中创建maven项目,查看linux中hadoop下的文件、在本机搭建hadoop环境

    注意 第一次建立maven项目时需要在联网情况下,因为他会自动下载一些东西,不然突然终止 需要手动删除断网前建立的文件 在eclipse里新建maven项目步骤 直接新建maven项目出了错      ...

  5. Hadoop基础-镜像文件(fsimage)和编辑日志(edits)

    Hadoop基础-镜像文件(fsimage)和编辑日志(edits) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看日志镜像文件(如:fsimage_00000000000 ...

  6. Python解析HDF文件 分类: Python 2015-06-25 00:16 743人阅读 评论(0) 收藏

    前段时间因为一个业务的需求需要解析一个HDF格式的文件.在这之前也不知道到底什么是HDF文件.百度百科的解释如下: HDF是用于存储和分发科学数据的一种自我描述.多对象文件格式.HDF是由美国国家超级 ...

  7. 如何利用Hadoop存储小文件

    **************************************************************************************************** ...

  8. 【大数据系列】hadoop上传文件报错_COPYING_ could only be replicated to 0 nodes

    使用hadoop上传文件 hdfs dfs -put  XXX 17/12/08 17:00:39 WARN hdfs.DFSClient: DataStreamer Exception org.ap ...

  9. Hadoop Maven pom文件示例

    Hadoop Maven pom文件示例 @(Hadoop) <?xml version="1.0" encoding="UTF-8"?> < ...

随机推荐

  1. Django写的投票系统1(转)

    当然主要是从django的帮助文档里面来的,权当是翻译吧 这个投票系统的主要功能有 1.一个前台页面,可以让用户来投票 2.一个管理员页面,可以用来添加.修改.删除投票 首页第一步要确定你已经安装了D ...

  2. SEAndroid安全机制中的进程安全上下文关联分析

    前面一篇文章分析了文件安全上下文关联过程.可是在SEAndroid中,除了要给文件关联安全上下文外,还须要给进程关联安全上下文.由于仅仅有当进程和文件都关联安全上下文之后,SEAndroid安全策略才 ...

  3. Ucan23操作系统项目地址

    期间耽误了近半年的时间.在昨天最终完毕了Ucan23OS, 项目托管在GitHub上,地址为: https://github.com/howardking/UCAN23OS 以下为操作系统的执行截图 ...

  4. 【HDU】4888 Redraw Beautiful Drawings 网络流【推断解是否唯一】

    传送门:pid=4888">[HDU]4888 Redraw Beautiful Drawings 题目分析: 比赛的时候看出是个网络流,可是没有敲出来.各种反面样例推倒自己(究其原因 ...

  5. [置顶] Guava学习之Multimap

    相信大家对Java中的Map类及其之类有大致的了解,Map类是以键值对的形式来存储元素(Key->Value),但是熟悉Map的人都知道,Map中存储的Key是唯一的.什么意思呢?就是假如我们有 ...

  6. Android数据库高手秘籍(五)——LitePal的存储操作

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/39345833 经过前面几篇文章的学习,我们已经把LitePal的表管理模块的功能都 ...

  7. Webservice-初级实例(二)

    去年这个时候在亿阳工作,经理让我做数据同步功能,用到WS,于是草草研究之后,就投入使用了.前两天同事给我讲解分配给我的项目时,讲到其中一块是数据同步功能,我不禁一笑,同事问笑什么,我说世界真是奇妙,去 ...

  8. 【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...

  9. FZUOJ Problem 2178 礼品配送

    Problem 2178 礼物分配 题目链接: Click Here~ Problem Description 在双胞胎兄弟Eric与R.W的生日会上,他们共收到了N个礼物,生日过后他们决定分配这N个 ...

  10. SqlServer表EXCEL数据复制的另一种方法

    一个.SqlServer表中的数据复制到excel 1.新建查询,用sql语句把表数据读出来 2.然后,选择数据,右键.复制(也能够点击连同标题复制),拷贝到记事本中(不然会乱码) 3.然后再把记事本 ...