• 管理HDFS中的文件
  • 分析MapReduce框架中的组件
  • 读写输入输出数据
 
1、HDFS文件操作
 
[命令行方式]
 
Hadoop的文件命令采取的形式为:
hadoop fs -cmd <args>
其中,cmd是具体的文件命令,而<args>是一组数目可变的参数。
 
(1)添加文件和目录
     HDFS有一个默认的工作目录/user/$USER,其中$USER是你的登录用户名。不过这个目录不会自动建立,让我们用mkdir命令创建它。Hadoop的mkdir命令会自动创建父目录,类似于UNIX中使用-p选项的mkdir命令。
     hadoop fs -mkdir /user/chuck
     
     如果想看到所有的子目录,则可以使用hadoop的lsr命令,类似于UNIX中打开-r选项的ls:
     hadoop fs -lsr /
     [输出结果显示出属性信息,比如权限、所有者、组、文件大小以及最后修改日期,所有这些都类似于UNIX的概念。显示“1”的列给出文件的复制因子。因为复制因子不适用于目录,故届时该列仅会显示一个破折号(-)]
 
     在本地文件系统中创建一个名为examle.txt的文本文件,用hadoop的put命令将它从本地文件系统复制到HDFS中:
     hadoop fs -put example.txt ./
 
 
(2)获取文件
     从HDFS中复制文件到本地文件系统:
     hadoop fs -get example.txt ./
 
     显示HDFS中文件的内容:
     hadoop fs -cat example.txt
     [可以在hadoop的文件命令中使用UNIX的管道,将其结果发送给其他的UNIX命令做进一步处理]
 
     查看最后一千字节:
     hadoop fs -tail example.txt
 
(3)删除文件
     删除HDFS中的文件:
     hadoop fs -rm example.txt
    [ rm命令还可以用于删除空目录]
 
     删除目录(目录不为空):
     hadoop fs -rmr /user/chuck
 
(4)查阅帮助
     hadoop fs -help <cmd>
 
[编程方式]
 
hadoop命令行工具中有一个getmerge命令,用于把一组HDFS文件在复制到本地计算机以前进行合并,下面开发的是实现把本地计算机文件复制到HDFS以前进行合并:
 
 

代码清单 PutMerge程序
 
 import java.io.IOException;

 import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; public class PutMerge { public static void main(String[] args) throws IOException { Configuration conf = new Configuration();
FileSystem hdfs = FileSystem.get(conf);
FileSystem local = FileSystem.getLocal(conf); Path inputDir = new Path(args[0]); //(1)设定输入目录和输出文件
Path hdfsFile = new Path(args[1]); try {
FileStatus[] inputFiles = local.listStatus(inputDir); //(2)得到本地文件列表
FSDataOutputStream out = hdfs.create(hdfsFile); //(3)生成HDFS输出流 for (int i=0; i<inputFiles.length; i++) {
System.out.println(inputFiles[i].getPath().getName());
FSDataInputStream in = local.open(inputFiles[i].getPath()); //(4)打开本地输入流
byte buffer[] = new byte[256];
int bytesRead = 0;
while( (bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
in.close();
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
 
(1)根据用户定义的参数设置本地目录和HDFS的目标文件;
(2)提取本地输入目录中每个文件的信息;
(3)创建一个输出流写入到HDFS文件;
(4)遍历本地目录中的每个文件,打开一个输入流来读取该文件
 

 
FileSystem类还有些方法用于其他标准文件操作,如delete()、exists()、mkdirs()和rename()。
 
2、剖析MapReduce程序
 
 
MapReduce程序通过操作键/值对来处理数据,一般形式为:
map:(k1, v1) ——> list(k2, v2)
reduce:(k2, list(v2)) ——> list(k3,v3)
 
  1. 输入数据;
  2. 输入数据被分布在节点上;
  3. 每个map任务处理一个数据分片;
  4. Mapper输出中间数据;
  5. 节点间的数据交换在“洗牌”阶段完成;
  6. 相同key的中间数据进入相同的reducer;
  7. 存储Reducer的输出。
 
     虽然我们可以并且的确经常把某些键与值称为整数、字符串等,但它们实际上并不是Integer、String等那些标准的Java类。这是因为为了让键/值对可以在集群上移动,MapReduce框架提供了一种序列化键/值对的方法。因此,只有那些支持这种序列化的类能够在这个框架中充当键或者值。
 
     更具体而言,实现Writable接口的类可以是值,而实现WritableComparable<T>接口的类既可以是键也可以是值。注意WritableComparable<T>接口是Writable和java.lang.Comparable<T>接口的组合。对于键而言,我们需要这个比较,因为它们将在Reduce阶段进行排序,而值仅会被简单地传递。
 
     Hadoop带有一些预定义的类用于实现WritableComparable,包括面向所有基本数据类型的封装类,如下表:
 
类
描述
BooleanWritable
标准布尔变量的封装
ByteWritable
单字节数的封装
DoubleWritable
双字节数的封装
FloatWritable
浮点数的封装
IntWritable
整数的封装
LongWritable
长整数的封装
Text
使用UTF8格式的文本封装
NullWritable
无键值的占位符
 
     键和值所采用的数据类型可以超过Hadoop自身所支持的基本类型,可以自定义数据类型,只要它实现了Writable(或WritableComparable<T>)接口。
 

代码清单 示例实现WritableComparable接口的类
 
 import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; import org.apache.hadoop.io.WritableComparable; public class Edge implements WritableComparable<Edge> { private String departureNode;
private String arrivalNode; public String getDepartureNode() { return departureNode;} @Override
public void readFields(DataInput in) throws IOException { //(1)说明如何读入数据
departureNode = in.readUTF();
arrivalNode = in.readUTF();
} @Override
public void write(DataOutput out) throws IOException { //(2)说明如何写入数据
out.writeUTF(departureNode);
out.writeUTF(arrivalNode);
} @Override
public int compareTo(Edge o) { //(3)定义数据排序
return (departureNode.compareTo(o.departureNode) != 0)
? departureNode.compareTo(o.departureNode)
: arrivalNode.compareTo(o.arrivalNode);
}
}
 
这个Edge类实现了Writable接口的readFields()及write()方法。它们与Java中的DataInput和DataOutput类一起用于类中内容的串行化。而Comparable接口中的实现是compareTo()方法。如果被调用的Edge小于、等于或者大于给定的Edge,这个方法会分别返回-1,0,1。

 
[Mapper]
 
     一个类要作为mapper,需继承MapReducebase基类并实现Mapper接口。并不奇怪,mapper和reducer的基类均为MapReduceBase类。它包含类的构造与解构方法。
  • void configure(JobConfjob):该函数提取XML配置文件或者应用程序主类中的参数,在数据处理之前调用该函数。
  • void close():作为map任务结束前的最后一个操作,该函数完成所有的结尾工作,如关闭数据库连接、打开文件等。
 
     Mapper接口负责数据处理阶段。它采用的形式为Mapper<k1,v1,k2,v2>Java泛型,这里键类和值类分别实现WritableComparable和Writable接口。Mapper只有一个方法——Map,用于处理一个单独的键/值对。
     void map (k1 key, v1 value, OutputCollector<k2,v2> output, Reporter reporter) throws IOException
 
     该函数处理一个给定的键/值对 (k1,v1),生成一个键/值对(k2,v2)的列表(该列表也可能为空)。OutputCollector接收这个映射过程的输出,Reporter可以提供对mapper相关附加信息的记录,形成任务进度。
 
     Hadoop提供了一些有用的mapper实现,如下表:
 
类
描述
IdentityMapper<k,v>
实现Mapper<k,v,k,v>将输入直接映射到输出
InverseMapper<k,v>
实现Mapper<k,v,v,k>反转键/值对
RegexMapper<k>
实现Mapper<k,text,text,LongWritable>,为每个常规表达式的匹配项生成一个(match,1)对
TokenCountMapper<k>
实现Mapper<k,text,text,LongWritable>,当输入的值为分词时,生成一个(token,1)对
 
 
[Reducer]
 
     reducer的实现和mapper一样必须首先在MapReduce基类上扩展,允许配置和清理。此外,它还必须实现Reducer接口使其具有如下的单一方法:
     void reduce(k2 key, Iterator<v2> values, OutputCollector<k3,v3> output, Reporter reporter) throws IOException
 
     当reducer任务接收来自各个mapper的输出时,它按照键/值对中的键对输入数据进行排序,并将相同键的值归并。然后调用reduce()函数,并通过迭代处理那些与指定键相关联的值,生成一个(可能为空的)列表(k3,v3)。OutputCollector接收reduce阶段的输出,并写入输出文件。Reporter可提供对reducer相关附加信息的记录,形成任务进度。
 
     Hadoop提供了一些基本的reducer实现,如下表:
 
类
描述
IdentityReudcer<k,v>
实现Reducer<k,v,k,v>将输入直接映射到输出
LongSumReducer<k>
实现<k,LongWritable,k,LongWritable>, 计算与给定键相对应的所有值的和
 
 
[Partitioner:重定向Mapper输出]
 
     当使用多个reducer时,我们就需要采取一些办法来确定mapper应该把键/值对输出给谁。默认的作法是对键进行散列来确定reducer。hadoop通过HashPartitioner类强制执行这个策略。但有时HashPartitioner会让你出错。
 
 public class EdgePartitioner implements Partitioner<Edge, Writable>
{
@verride
public int getPartition(Edge key, Writable value, int numPartitions)
{
return key.getDepartureNode().hashCode() % numPartitions;
} @verride
public void configure(JobConf conf) { }
}
 
      一个定制的partitioner只需要实现configure()和getPartition()两个函数。前者将hadoop对作业的配置应用在patittioner上,而后者返回一个介于0和reducer任务数之间的整数,指向键/值对将要发送的reducer。
 
     在map和reduce阶段之间,一个MapReduce应用必然从mapper任务得到输出结果,并把这些结果发布给reduce任务。该过程通常被称为洗牌。
 
 
[Combiner:本地reduce]
 
在许多MapReduce应用场景中,我们不妨在分发mapper结果之前做一下“本地Reduce”。
 
 
[预定义的mapper和reducer类的单词计数]
 

代码清单 修改的WordCount例程
 
 import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.lib.TokenCountMapper;
import org.apache.hadoop.mapred.lib.LongSumReducer; public class WordCount2 {
public static void main(String[] args) {
JobClient client = new JobClient();
JobConf conf = new JobConf(WordCount2.class); FileInputFormat.addInputPath(conf, new Path(args[0]));
FileOutputFormat.setOutputPath(conf, new Path(args[1])); conf.setOutputKeyClass(Text.class);
conf.setOutputValueClass(LongWritable.class);
conf.setMapperClass(TokenCountMapper.class);
conf.setCombinerClass(LongSumReducer.class);
conf.setReducerClass(LongSumReducer.class); client.setConf(conf);
try {
JobClient.runJob(conf);
} catch (Exception e) {
e.printStackTrace();
}
}
}
 

 
3、读和写
 
[InputFormat]
 
     hadoop分割与读取输入文件的方式被定义在InputFormat接口的一个实现中。TextInputFormat是InputFormat的默认实现,当你想要一次获取一行内容而输入数据又没有确定的键值时,这种数据格式通常会非常有用。
 
常用的InputFormat类,如下表:
 
InputFormat
描述
TextInputFormat
在文本文件中每一行均为一个记录。键(key)为一行的字节偏移,而值(value)为一行的内容
key: LongWritable
value: Text
KeyValueTextInputFormat
在文本文件中的每一行均为一个记录。以每行的第一个分隔符为界,分隔符之前的是键(key),之后的是值(value)。分离器在属性key.value.separator.in.input.line中设定,默认为制表符(\t)。
key: Text
Value: Text
SequenceFileInputFormat<k,v>
用于读取序列文件的InputFormat。键和值由用户定义。序列文件为hadoop专用的压缩二进制文件格式。它专用于一个MapReduce作业和其他MapReduce作业之间传送数据。
key: K(用户定义)
value: V(用户定义)
NLineInputFormat
与TextInputFormat相同,但每个分片一定有N行。N在属性mapred.line.input.format.linespermap中设定,默认为1.
key: LongWritable
value: Text
 
可以设置JobConf对象使用KeyValueTextInputFormat类读取这个文件:
     conf.setInputFormat(KeyValueTextInputFormat.class);
 
回想一下,我们之前在mapper中曾使用LongWritable和Text分别作为键(key)和值(value)的类型。在TextInputFormat中,因为值为用数字表示的偏移量,所以LongWritable是一个合理的键类型。而当使用KeyvalueTextInputFormat时,无论是键和值都为Text类型,你必须改变mapper的实现以及map()方法来适应这个新的键(key)类型。
 
生成一个定制的InputFormat:略
 
 
[OutputFormat]
 
当MapReduce输出数据到文件时,使用的是OutputForamt类,它与inputForamt类相似。因为每个reducer仅需将它的输出写入自己的文件中,输出无需分片。输出文件放在一个公用目录中,通常命名为part-nnnnn,这里nnnnn是reducer的分区ID。RecordWriter对象将输出结果进行格式化,而RecordReader对输入格式进行解析。
 
常用的OutputFormat类,如下表:
 
OutputFormat
描述
TextOutputFormat<k,v>
将每个记录写为一行文本。键和值以字符串的形式写入,并以制表符(\t)分隔。这个分隔符可以在属性mapred.textoutputformat.separator中修改
SequenceFileOutputFormat<k,v>
以hadoop专有序列文件格式写入键/值对。与SequenceFileInputForamt配合使用
NullOutputFormat<k,v>
无输出
 
 
  [转载请注明] http://www.cnblogs.com/zhengrunjian/
 
 
 
 
 
 
 
 
 
 

[hadoop in Action] 第3章 Hadoop组件的更多相关文章

  1. [Hadoop in Action] 第1章 Hadoop简介

    编写可扩展.分布式的数据密集型程序和基础知识 理解Hadoop和MapReduce 编写和运行一个基本的MapReduce程序   1.什么是Hadoop   Hadoop是一个开源的框架,可编写和运 ...

  2. [Hadoop in Action] 第7章 细则手册

    向任务传递定制参数 获取任务待定的信息 生成多个输出 与关系数据库交互 让输出做全局排序   1.向任务传递作业定制的参数        在编写Mapper和Reducer时,通常会想让一些地方可以配 ...

  3. [Hadoop in Action] 第6章 编程实践

    Hadoop程序开发的独门绝技 在本地,伪分布和全分布模式下调试程序 程序输出的完整性检查和回归测试 日志和监控 性能调优   1.开发MapReduce程序   [本地模式]        本地模式 ...

  4. [Hadoop in Action] 第5章 高阶MapReduce

    链接多个MapReduce作业 执行多个数据集的联结 生成Bloom filter   1.链接MapReduce作业   [顺序链接MapReduce作业]   mapreduce-1 | mapr ...

  5. [Hadoop in Action] 第4章 编写MapReduce基础程序

    基于hadoop的专利数据处理示例 MapReduce程序框架 用于计数统计的MapReduce基础程序 支持用脚本语言编写MapReduce程序的hadoop流式API 用于提升性能的Combine ...

  6. Hadoop专业解决方案-第13章 Hadoop的发展趋势

    一.前言: 非常感谢Hadoop专业解决方案群:313702010,兄弟们的大力支持,在此说一声辛苦了,经过两周的努力,已经有啦初步的成果,目前第13章 Hadoop的发展趋势小组已经翻译完成,在此对 ...

  7. [hadoop读书笔记] 第四章 Hadoop I/O操作

    P92 压缩 P102 序列化 序列化:将结构化对象转为字节流便于在网上传输或写到磁盘进行永久性存储的过程 用于进程之间的通信或者数据的永久存储 反序列化:将字节流转为结构化对象的逆过程 Hadoop ...

  8. [Hadoop in Action] 第2章 初识Hadoop

    Hadoop的结构组成 安装Hadoop及其3种工作模式:单机.伪分布和全分布 用于监控Hadoop安装的Web工具   1.Hadoop的构造模块   (1)NameNode(名字节点)       ...

  9. Hadoop专业解决方案-第12章 为Hadoop应用构建企业级的安全解决方案

    一.前言: 非常感谢Hadoop专业解决方案群:313702010,兄弟们的大力支持,在此说一声辛苦了,春节期间,项目进度有所延迟,不过元宵节以后大家已经步入正轨, 目前第12章 为Hadoop应用构 ...

随机推荐

  1. Math.random()

    Math.random() 日期时间函数(需要用变量调用):var b = new Date(); //获取当前时间b.getTime() //获取时间戳b.getFullYear() //获取年份b ...

  2. ASP.NET MVC中利用AuthorizeAttribute实现访问身份是否合法以及Cookie过期问题的处理

    话说来到上海已经快半年了,时光如白驹过隙,稍微不注意,时间就溜走了,倒是没有那么忙碌,闲暇之际来博客园还是比较多的,记得上次在逛博问的时候看到有同志在问MVC中Cookie过期后如何作相关处理,他在阐 ...

  3. Failure to find xxx in xxx was cached in the local repository, resolution will not be reattempted until the update interval of nexus has elapsed or updates are forced @ xxx

    问题: 在linux服务器上使用maven编译war时报错: 16:41:35 [FATAL] Non-resolvable parent POM for ***: Failure to find * ...

  4. ★Kali信息收集~★6.Dmitry:汇总收集

    概述: DMitry(Deepmagic Information Gathering Tool)是一个一体化的信息收集工具.它可以用来收集以下信息: 1. 端口扫描 2. whois主机IP和域名信息 ...

  5. Node+fs+定时器(node-schedule)+MySql

    目标:将本人写博客时候的截图保存到桌面的图片 执行保存到指定文件进行整理 并写入数据库 先看最终的目录结构: package.json文件: { "name": "zqz ...

  6. springmvc+jpa实现分页的两种方式

    1.工具类 public final class QueryTool { public static PageRequest buildPageRequest(int pageNumber, int ...

  7. 原生Ajax总结

    HTTP协议 传统的请求和Ajax请求 Ajax定义 Asynchronous JavaScript and XML. Ajax异步的,JavaScript程序希望与服务器直接通信而不需要重新加载页面 ...

  8. mysql交互式连接&非交互式连接

    交互式操作:通俗的说,就是你在你的本机上打开mysql的客户端,就是那个黑窗口,在黑窗口下进行各种sql操作,当然走的肯定是tcp协议. 非交互式操作:就是你在你的项目中进行程序调用.比如一边是tom ...

  9. 构建自己的PHP框架--构建模版引擎(1)

    前段时间太忙,导致好久都没有更新博客了,今天抽出点时间来写一篇. 其实这个系列的博客很久没有更新了,之前想好好规划一下,再继续写,然后就放下了,今天再捡起来继续更新. 今天我们来说一下,如何构建自己的 ...

  10. 《你不知道的JavaScript》整理(一)——作用域、提升与闭包

    最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,里面分析了很多基础性的概念. 可以更全面深入的理解JavaScript深层面的知识点. 一.函数作用域 ...