• 管理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. .NET 基础一步步一幕幕[方法、结构、枚举]

    方法.结构.枚举 方法: 将一堆代码进行重用的一种机制. 语法: [访问修饰符] 返回类型 <方法名>(参数列表){ 方法主体: } 返回值类型:如果不需要写返回值,写void 方法名:P ...

  2. 【.NET深呼吸】基础:自定义类型转换

    照例,老周在开始吹牛之前,先讲讲小故事,这是朋友提出的建议,老TMD写技术有什么了不起的,人人都会写.后来老周想想,也确实,代码谁不会写,能写到有品位有感悟,就不容易做到.于是,老周接受了该朋友的建议 ...

  3. 移动端HTML5音频与视频问题及解决方案

    最近在研究用视频代替动画,用视频代替精灵动画,我们称这种视频叫做交互视频. 传统的精灵动画: 磁盘空间大,下载慢,尤其是在线播放,会更慢 文件太多,在线播放的时候,太多http请求,会导致响应慢,或者 ...

  4. 原创:CSS3技术-雪碧图自适应缩放与精灵动画方案

    花了一个礼拜完成了慕课网定制的七夕主题效果,其中有一个没实现好的功能,就是雪碧图的自适应缩放 ps: 以下实现都是基于移动端的处理 原图如下: 人物是采用的是雪碧图,通过坐标绝对数据取值 问题很明显, ...

  5. MVC 验证码实现( 简易版)

    现在网站上越来越多的验证码,使用场景也是越来越多,登陆.注册.上传.下载...等等地方,都有可能大量使用到验证码,那么制作验证码到底有多简单呢?我们一起来看下最简易版的验证码实现过程- 验证码的基本步 ...

  6. 前端学HTTP之摘要认证

    前面的话 上一篇介绍的基本认证便捷灵活,但极不安全.用户名和密码都是以明文形式传送的,也没有采取任何措施防止对报文的篡改.安全使用基本认证的唯一方式就是将其与SSL配合使用 摘要认证与基本认证兼容,但 ...

  7. 聊聊ASP.NET Core默认提供的这个跨平台的服务器——KestrelServer

    跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server.KestrelServer利用一个名为KestrelEngine的网络 ...

  8. 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)

    今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...

  9. python基础操作以及hdfs操作

    目录 前言 基础操作 hdfs操作 总结 一.前言        作为一个全栈工程师,必须要熟练掌握各种语言...HelloWorld.最近就被"逼着"走向了python开发之路, ...

  10. 你真的会玩SQL吗?EXISTS和IN之间的区别

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...