Hadoop实战读书笔记(6)

putmerge程序的大体流程是?

1、根据用户定义的参数设置本地目录和HDFS的目录文件

2、提取本地输入目录中每个文件的信息

3、创建一个输出流写入到HDF文件

4、遍历本地目录中的每个文件,打开一个输入流来读取该文件,剩下就是一个标准的Java文件复制过程了

具体程序如下:

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

Configuration conf = new Configuration();

FileSystem hdfs = FileSystem.get(conf);

FileSystem local = FieSystem.getLocal(conf);

// 设定输入目录与输出文件

Path inputDir = new Path(args[0]);

Path hdfsFile = new Path(args[1]);

try {

// 得到本地文件列表

FileStatus[] inputFiles = local.listStatus(inputDir);

// 生成HDFS输出流

FSDataOutputStream out = hdfs.create(hdfsFile);

for (int i = 0; i < inputFiles.length; i++) {

System.out.println(inputFiles[i].getPath().getName());

// 打开本地输入流

FSDataInputStream in = local.open(inputFiles[i].getPath());

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();

}

}

那么现在有数据了,还要对它进行处理、分析以及做其他的操作。

MapReduce程序通过操作键/值对来处理数据,一般形式为

map: (K1, V1) -> list(K2, V2)

reduce:(K2, list(V2)) -> list(K3, V3)

Hadoop数据类型有哪些?

MapReduce框架并不允许它们是任意的类。

虽然我们经常把某些键与值称为整数、字符串等,但它们实际上并不是Integer、String等哪些标准的Java类。为了让键/值对可以在集群上移动,MapReduce框架提供了一种序列化键/值对的方法。因此,只有那些支持这种序列化的类能够在这个框架中充当键或者值。

更具体的Hadoop类型说明

实现Writable接口的类可以是值

而实现WritableComparable<T>接口的类既可以是键也可以是值

注意WritableComparable<T>接口是Writable和java.lang.Comparable<T>接口的组合,对于键而言,我们需要这个比较,因为它们将在Reduce阶段进行排序,而值仅会被简单地传递。

键/值对经常使用的数据类型列表,这些类均实现WritableComparable接口



描述


BooleanWritable


标准布尔变量的封装


ByteWritable


单字节数的封装


DoubleWritable


双字节数的封装


FloatWritable


浮点数的封装


IntWritable


整数的封装


LongWritable


Long的封装


Text


使用UTF-8格式的文本封装


NullWritable


无键值时的站位符

如何自定义数据类型?

只要它实现了Writable(或WritableComparable<T>)接口。

定义一个Edge类型用于表示一个网络的边界

public class Edge implements WritableComparable<Efge> {

private String departureNode;

private String arrivalNode;

public String getDepartureNode() {

return departureNode;

}

// 说明如何读入数据

@Override

public void readFields(DataInput in) throws IOException {

departureNode = in.readUTF();

arrivalNode = in.readUTF();

}

// 说明如何写出数据

@Override

public void write(DataOutput out) throws IOException {

out.writeUTF(departureNode);

out.writeUTF(arrivalNode);

}

// 定义数据排序

@Override

public int compareTo(Edge o) {

return (departureNode.compareTo(o.departureNode) != 0)

? departureNode.compareTo(o.departureNode)

: arrivalNode.compareTo(o.arrivalNode);

}

}

Mapper类是什么?

一个类要作为mapper,需继承MapReduceBase基类并实现Mapper接口。

mapper和reducer的基类均为MapReduceBase类

其中包含一些函数或方法:

1、void configure(JobConf job),该函数提取XML配置文件或者应用程序主类中的参数,在数据处理之前调用该函数。

2、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

上面这个map函数的参数都是什么意思?

该函数处理一个给定的键/值对 (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,需继承MapReduceBase基类并实现Reducer接口。

以便于允许配置和清理。

此外,它还必须实现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实现



描述


IdentityReducer<K, V>


实现Reducer<K,   V, K, V>, 将输入直接映射到输出


LongSumReducer<K>


实现<K,   LongWritable, K, LongWritable>,   计算与给定键相对应的所有值的和

注:虽然我们将Hadoop程序称为MapReduce应用,但是在map和reduce两个阶段之间还有一个极其重要的步骤:将mapper的结果输出给不同的reducer。这就是partitioner的工作。

初次使用MapReduce的程序员通常有一个误解?

仅需要一个reducer? 采用单一的reducer可以在处理之前对所有的数据进行排序。

No,采用单一的reducer忽略了并行计算的好处。

那么就应该使用多个reducer是么?但需要解决一个问题,如何确定mapper应该把键/值对输出给谁。

默认的作法是对键进行散列来确定reducer。Hadoop通过HashPartitioner类强制执行这个策略。但有时HashPartitioner会出错。

 

HashPartitioner会出什么错?

假如你使用Edge类来分析航班信息来决定从各个机场离港的乘客数目,这些数据可能是:

(San Francisco, Los Angeles) Chuck Lam

(San Francisco, Dallas) James Warren

如果你使用HashPartitioner,这两行可以被送到不同的reducer, 离港的乘客数目被处理两次并且两次都是错误的

如何为你的应用量身定制partitioner呢?

上面的情况,我希望具有相同离港地的所有edge被送往相同的reducer,怎么做呢?只要对Edge类的departureNode成员进行散列就可以了:

public class EdgePartitioner implements Partitioner<Edge, Writable> {

@Override

public int getPartition (Edge key, Writable value, int numPartitions) {

return key.getDepartureNode().hashCode() % numPartitions;

}

@Override

public void configure(JobConf conf) { }

}

一个定制的partitioner只需要实现configure()和getPartition()两个函数,前者将Hadoop对作业的配置应用在patitioner上,而后者返回一个介于0和reduce任务数之间的整数,指向键/值对将要发送的reducer

 

Combiner:本地reduce

在许多MapReduce应用场景中,我们不妨在分发mapper结果之前做一下 "本地Reduce"。再考虑一下WordCount的例子,如果作业处理的文件中单词 "the" 出现了574次,存储并洗牌一次 ("the", 574) 键/值对比许多次 ("the", 1) 更为高效。这种处理步骤被称为合并。

 

预定义mapper和Reducer类的单词计数

public class WordCount {

public static void main (String[] args) {

JobClient client = new JobClient();

JobConf conf = new JobConf(WordCount.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); // Hadoop自己的TokenCountMapper

conf.setCombinerClass(LongSumReducer.class);

conf.setReducerClass(LongSumReduver.class); // Hadoop自己的LongSumReducer

client.setConf(conf);

try {

JobClient.runJob(conf);

} catch (Exception e) {

e.printStackTrace();

}

}

}

使用Hadoop预定义的类TokenCountMapper和LongSumReducer,编写MapReduce分厂的容易,Hadoop也支持生成更复杂的程序,这里只是强调Hadoop允许你通过最小的代码量快速生成实用的程序。

时间: 2024-08-27 12:28:23

Hadoop实战读书笔记(6)的相关文章

Hadoop实战读书笔记(8)

什么是开发数据集? 一个流行的开发策略是为生产环境中的大数据集建立一个较小的.抽样的数据子集,称为开发数据集.这个开发数据集可能只有几百兆字节.当你以单机或者伪分布式模式编写程序来处理它们时,你会发现开发周期很短,在自己的机器上运行程序也很方便,而且还可以在独立的环境中进行调试. 为什么选择专利引用数据做测试? 1.因为它们与你将来会遇到的大多数数据类型相似 2.专利引用数据所构成的关系图与网页链接以及社会网络图可谓大同小异 3.专利发布以时间为序,有些特性类似于时间序列 4.每个专利关联到一个

Hadoop实战读书笔记(7)

输入数据概要 输入数据通常驻留在较大的文件中,通常几十或者数百GB,甚至更大.MapReduce处理的基本原则之一是将输入数据分割成块.这些块可以在多台计算机上并行处理,在Hadoop的术语中这些块被称为输入分片(Input Split).每个分片应该足够小以实现更细粒度的并行.(如果所有的输入数据都在一个分片中,那就没有并行了.) 另一方面,每个分片也不能太小,否则启动与停止各个分片处理所需的开销将占去很大一部分执行时间. 所以说: 1.单个文件要足够的大,这样才能被分片,才会有并行. 2.分

Hadoop实战读书笔记(5)

HDFS文件操作 你可以把一个大数据集(100TB)在HDFS中存储为单个文件,而大多数其他的文件系统无力实现这一点.虽然该文件存在多个副本分布在多台机器上来支持并行处理,你也不必考虑这些细节. HDFS (Hadoop Distribution File System)文件系统到底是一个怎样的文件系统? 并不是一个Unix文件系统,不支持像ls和cp这种标准的Unix文件命令,也不支持如fopen()和fread()这样的标准文件读写操作.但是Hadoop提供了一套与Linux文件命令类似的命

Hadoop实战读书笔记(9)

如何将一个反向引用索引的程序的Reducer输出的类型改为IntWritable public static class Reduce extends MapReduceBase implements Reducer<Text, Text, Text, IntWritable> { public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, IntWritable> output,

R实战读书笔记四

第三章 图形入门 本章概要 1 创建和保存图形 2 定义符号.线.颜色和坐标轴 3 文本标注 4 掌控图形维数 5 多幅图合在一起 本章所介绍内容概括如下. 一图胜千字,人们从视觉层更易获取和理解信息. 图形工作 R具有非常强大的绘图功能,看下面代码. > attach(mtcars) > plot(wt, mpg) > abline(lm(mpg~wt)) > title("Regression of MPG on Weight") > detach(m

JAVA并发编程实战 读书笔记(二)对象的共享

<java并发编程实战>读书摘要 birdhack 2015年1月2日 对象的共享 JAVA并发编程实战读书笔记 我们已经知道了同步代码块和同步方法可以确保以原子的方式执行操作,但一种常见的误解是,认为关键之synchronized只能用于实现原子性或者确定临界区.同步还有另一个重要的方面:内存可见性. 1.可见性 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程

Spring3.x企业开发应用实战读书笔记 —— 第三章IoC容器概述

声明:    本篇博客绝大多数内容为<Spring3.x企业开发应用实战>一书原内容,所有版权归原书作者所有!,仅供学习参考,勿作他用! 3.2 相关Java基础知识 Java语言允许通过程序化的方式间接对Class对象实例操作,Class文件由类装载器装在后,在JVM(Java虚拟机)中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息: 如构造函数.属性和方法等.Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能,这就为使用程

机器学习实战读书笔记(三)决策树

3.1 决策树的构造 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据. 缺点:可能会产生过度匹配问题. 适用数据类型:数值型和标称型. 一般流程: 1.收集数据 2.准备数据 3.分析数据 4.训练算法 5.测试算法 6.使用算法 3.1.1 信息增益 创建数据集 def createDataSet(): dataSet = [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, '

R语言实战读书笔记(二)创建数据集

2.2.2 矩阵 matrix(vector,nrow,ncol,byrow,dimnames,char_vector_rownames,char_vector_colnames) 其中: byrow=TRUE/FALSE,表示按行填充还是按列填充,默认情况下是按列填充 2.2.4 数据框 1.attach,detach()和with() attach():将数据框加入搜索路径 detach():将数据框移除出搜索路径 with():赋值仅在括号内有效,如果想在括号外生效也可以,用<<- 2.