[Hadoop] Hadoop学习历程 [持续更新中…]

时间:2021-05-05 05:58:22

[Hadoop] Hadoop学习历程 [持续更新中…]

1. Hadoop FS Shell

  Hadoop之所以可以实现分布式计算,主要的原因之一是因为其背后的分布式文件系统(HDFS)。所以,对于Hadoop的文件操作需要有一套全新的shell指令来完成,而这就是Hadoop FS Shell。它主要是用于对Hadoop平台进行文件系统的管理。

  有关HDFS的介绍博客请移步:Hadoop学习笔记之Hadoop基础

  有关Hadoop FS Shell的学习文档:Hadoop FS Shell学习文档

2. Hadoop Streaming

  我们知道Hadoop集群上的一些MapReduce代码一般是利用Java来进行开发的,那么对于很多像博主一样的不会Java的同学该怎么办呢,是不是我们必须要在使用Hadoop之前要学会Java呢?当然,如果Java对你没有什么帮助的话,你是完全没有必要额外为了Hadoop来学习Java的。Hadoop Streaming就是Hadoop为了帮助用户创建和运行一些特殊的map/reduce作业而开发的一个工具,它可以被看做是一个API,可以使用户很方便地利用一些脚本语言(比如,bash shell或者Python)来写Mapper和Reducer。

  下面是Hadoop Streaming的学习文档:Hadoop Streaming学习文档

3. Hadoop的输入和输出

  Hadoop的输入和输出分别为标准输入和标准输出,这是在学习hadoop时首先要记住的。对于第一次编写hadoop job的同学来说,如果没有认识到这点的重要性的话,可能都不知道hadoop如何在本地进行测试。Hadoop的输入输出是基于标准输入和标准输出的,那么我们在本地测试的时候就要利用bash命令来模拟这个过程,所以常见的unittest形式如下:

cat input | mapper | sort | reducer > output

  其中的sort命令的左右是在模拟reducer输入的过程。对于数据流而言,具有相同key的数据流会聚合在一起(但是value是无序的),而且会被分发给同一个reducer,所以sort命令主要是在模拟这个过程,关于这个问题在下边的combiner和partitioner部分会进行详细介绍。

4. Hadoop MapReduce & Shuffler

  我们学习Hadoop实际上就是在学习一种全新的计算框架,它基于分布式的技术存储,利用MapReduce思想实现海量数据处理的目的。在没有实际接触Hadoop时,很多参考书上都这样说:MapReduce主要为两个阶段:Map阶段和Reduce阶段。这句话确实没有错,但是如果想完全的理解整个MapReduce思想,除了认识上述两个阶段还要深刻理解一个很重要的中间过程——shuffler,其中shuffler包含了combiner和partitioner。

  下图为MapReduce的整体框架,其中shuffler部分的操作介于Mapper和Reducer之间,它的主要功能为处理Mapper的输出并为Reducer提供相应的输入文件,主要操作为combiner和partitioner。

[Hadoop] Hadoop学习历程 [持续更新中…]

  我们可以这样来理解上述的三种中间操作:

  combiner:分为Mapper端和Reducer端,主要作用是将键值对中具有相同key的放在一起;

  partitioner:把键值对按照key分配给reducer。

  combiner和partitioner两者结合可以使得每一个Reducer的输入是按照key进行聚合的,而且同一个key所对应的数据流只会被分配到同一个Reducer,这就极大地简化了Reducer的任务。

  下图为显示了combiner和partitioner两个中间操作的MapReduce框架图,这个例子是做词频统计:

[Hadoop] Hadoop学习历程 [持续更新中…]

  我们可以看到combiner的作用就是按照key将Mapper的输出进行聚合,而partitioner会将所有combiner的结果按照key进行分发,分发给不同的Reducer进行数据的处理。我们在Reducer端可以看到两点:

  第一,所有具有相同key的数据流均被分发到同一个Reducer;

  第二,每个Reducer的输入中数据流是按照key进行聚合的,即具有相同key的数据流是连在一起的。

这样我们在Reducer端就可以很轻松的完成词频统计的任务,我们可以按照数据流的顺序进行词频的统计,如果当前数据流的key与上一个数据流的key相同,那么就将该key对应的词频进行累加,如果不同说明该key已经被统计完成,则进行下一个词的统计即可。

  此外,在hadoop的配置中我们可以为partitioner配置相应的参数来控制partitioner按照不同的列来进行数据的切分,hadoop的默认设置是按照key进行数据的切分。

  其实除了combiner和partitioner以外,还有一些中间操作也需要进行深刻的理解,比如hadoop的sort过程。在这里,我们可以简单了解一下Reducer端的sort,它其实是一种二次排序(secondary sort)。我们知道在hadoop中每个Reducer的输入数据流中,数据流都是按照key聚合好的,但是其对应value则是无序的,即同一个job运行多次,由于Mapper完成的顺序不同,Reducer收到的value的顺序则是不固定的,那么如何才能使得Reducer接收的value成为有序的呢?这就是secondary sort需要解决的问题,它的应用场景常见的有求每个key下的最小/最大value值等。

  此外,我们也可以通过参数来控制secondary sort相应的作用域。

5. Hadoop常见操作

5.1 count操作

  count(计数/统计)是hadoop最为常见的操作之一。它的基本思想是就是上述词频统计的例子所讲述的,由于每个Reducer的输入都是按照key进行聚合的,所以可以根据key来顺序的进行累加。

5.2 join操作

  join(拼接)是hadoop中最为常见的操作之一,它的主要任务就是将多张数据表按照某个字段拼接成一个表。要想写出join操作需要考虑周全,否则会得到意想不到的结果。(PS:我在刚开始run第一个join job的时候,发现输出结果总是不对,检查了mapper和reducer的代码逻辑觉得都没有问题,一直不知道是哪里出问题,最后终于找到了原因,原来是MapReduce参数设置的问题: Mapper的output key fields = 2(按第1,2列排序);Reducer partition fields = 1(按第一列切分给reducer作为输入)。)

  join的思想有很多种,但是常用的一种可以这样来理解:

  mapper阶段:由于数据流来自不同的数据表,所以mapper是将每一个数据流进行打标签(tag),用于区别不同表的数据流;

  reducer阶段:根据mapper中的tag来区分数据流,并对于不同的数据流按照自己的业务需求设计不同的操作,最后将不同的表进行拼接。

  上述的join思想被称为是reducer端拼接。

  join操作还有一个巧妙的应用就是加载大词典,避免直接利用streaming加载一些特别大的词典。比如,我们现在要处理海量的日志,命中词典中userid的日志挑选出来,问题很简单,但是词表很大,可能内存不足以加载,这时候怎么办?我们借助join的思想:将大词典看作是一份特殊的日志,将两份日志join后输出即可满足要求了。[20160519 update.]

5.3 其他操作

  除了上述的count和join两种常用的操作,hadoop还有很多操作,比如简单的字段处理操作。在简单的字段处理操作中,比如加/减某个字段,改写某个字段,抽取某些字段等等,我们只需要mapper就可以了,此时不需要reducer进行任何操作,这时候reducer直接输出mapper的结果就可以了,在streaming中reducer端实际上为一个cat命令。