hadoop8天课程——第四天,MapReduce程序开发进阶

六眼飞鱼酱① 提交于 2020-04-06 18:20:52

mapreduce 组件全貌

map组件,reduce组件,partitioner组件,sort组件,inputformat组件,outputformat组件。

inputformat是一个抽象类,实现该接口的类负责实现源数据的读取,outputformat也是一个抽象类,实现改接口的类负责实现处理结果的输出,。用于将数据读取机制与mapreduce逻辑解耦合。默认的实现类是TextInputFormat和TextOutputFormat。也可以自定义实现inputformat和outputformat来满足自己的业务需求。在输入输出部分含有一个RecordReader和RecordWriter,用于从将输入输出数据包装成key-value形式,然后传递给下一个组件。

hadoop中的序列化机制

一次性携带多个数据的解决方法:将多个数据构造为一个java bean类对象 但是因为map和reduce的key-vlaue会在hadoop节点之间进行传输,所以自定义的类做为mr程序的key或者vlaue,则自定义类需要实现hadoop的序列化机制接口:Writable。

序列化:讲一个对象转化成一个二进制流。反序列化:从一个二进制流中构建出一个对象。java自带的序列化机制不但会将对象的各个数据域进行序列化,同时还会把这个对象的继承结构一起序列化到流中。hadoop的序列化机制不会将类的继承信息进行包装序列化,这能够节省网络带宽。反序列化时候会使用反射机制,所以自定义类应该含有一个不带参数的构造方法。

Writable接口需要实现的两个方法:序列化方法write和readFields。需要注意的是,反序列化方法中读字段的顺序一定要和序列化时候写字段的顺序保持一致。

  • write方法接收一个输出流对象out,可以在方法中调用out.writeXXX()方法将对象的各个数据域的输出到流中。
  • readFields方法接受一个输入流对象in,可以在方法中调用in.readXXX()方法从输入流中读出对象各个数据域的值。

流量汇总需求的mr程序开发

mr程序的自定义排序实现

mr程序的自定义分组实现

需求:让相同省份的的手机号的分析结果放在相同文件中,不同省份的手机号的分析结果放在不同的文件中。

要点:mr的分组机制。1.控制reduce任务的个数。2.map传出来的数据需要按着定制化的分组标准来分配到相应的reduce程序上。mr默认分组机制是hash分组:获取map的输出key的hashcode,然后对当前的reduce的任务数进行取余,得到分组号,然后将当前的这组数据<key,value>发送到这个号对应的reduce程序上。

解决方法:1.改造分区逻辑,自定义一个partitioner类。2.自定义reduce task的并发任务数。3.在runner的main方法总设置job的分区类为自定义的这个partitioner类,设置reducer task的任务数(reduce task和分组的数量应该保持一致。如果task数大于分组数,那么多余的task能运行,但是不会去处理任何数据,如果task数小于分组的数量,那么job运行的时候就会把报错。但是特殊情况,如果task数是1,分组数大于1,这样只会认为分组没有意义,数据全都到一个reduce任务上)。

具体的代码如下:

上面看到reduce task的数量可以在程序中直接进行设置,那么map task的数量要如何进行设置呢?与处理的文件数一致?与文件的bolck数一致?

mr框架增加了一个抽象层的逻辑概念称为切片(split),split指的就是文件中数据的偏移量范围,可以根据所处理文件的大小来调整。一个split会产生一个map task。因为split的概念是逻辑抽象的,并不实际存在,所以split的大小可以根据具体情况进行调整。

shuffle机制

  1. map阶段 从一个split中取出一条记录,交给map程序进行处理,那么map程序的输出结果放在那里去了呢?事实上,map的输出数据会先放到内存中的一个大小可设置的缓冲区,默认大小是100M,当缓冲区满了的时候,mr框架会将缓冲区中的数据写入到一个磁盘文件中,在写入的过程中有两点要注意:1写入的时候每个分组的数据会写入到一起,比如说0号分组的数据写在文件的前段,1号分组的数据写入到文件的中段,2号分组的数据写入到文件的末段,不同分组的数据不会交叉。2.组内的数据,在写入的时候也会根据每条数据的key进行排序。可以发现,在向小文件这能够写数据的时候,涉及到相当多的文件随机写(插入)操作,文件越大这种操作越费时,所以这个文件也不能太大,当达到一定大小的时候,会继续写入一个新的文件。当一个split处理完了的时候,那就会有很多小文件,所以框架还要把这些小文件合并起来,合并的过程中仍然是保持同组数据写在一块,不同组的数据不会交叉,并且在合并的时候,多个小文件的相同组的数据还需要进行排序(归并排序),以保证每条数据的全局顺序。合并完成之后,向MRAppMaster汇报处理结果:状态,结果文件所在的位置,分区的信息等。

  2. MRAppMaster启动reduce task进程,并告知该task处理那个分区的数据,以及数据的位置(主机,文件名,偏移量)

  3. reduce阶段 reduce会从每个map task最终产生的数据文件中拉取数据自己的所对应的组的数据(MRappmaster知道每个reduce从每个文件的那个其实位置开始取数据),并将从map task取过来的所有数据再进行排序(归并排序),以保证每条数据的全局顺序。然后将归并后的数据逐条提交给reduce程序去处理。处理完后输出结果到文件(可能是其他的目标)中

调优:增加map的内存缓冲区大小,以及内存缓冲区的益处阈值。

textinputformat类对切片规划的源码分析

切片规划信息会写入到资源路径stagingdir中。主要负责规划切片的方法是WriteSplits()。一个split的大小:在方法computeSplitSize中,首先取blocksize和maxsize得最小值,然后在取改结果与minsize的最大值,其中minsize(默认值1)和maxSize(默认值最大的long数字)都是可以通过配置文件进行配置的。

切片的一些详细信息:?

倒排索引的MR实现

需求:有多个文本文件,现在需要分析每个单词在每个文件中的出现次数。

要点:如何获取一行数据所在的文件名?答:使用map的context参数。

解决方法:分成两个mr程序来实现功能:1.首选还是一个wordcount的功能,但是输出的key不能单单是单词,而需要是单词+文件名作为key,value还是输出个1就行。reduce方法没区别。2.以上一个mr程序的输出内容作为输入数据,主要做的工作将单词相同但是文件名不同的多行数据合并成一行数据。map阶段输出单词为key,文件名+次数为value,reduce阶段就是讲valueList中的各个字符串拼接起来。

具体代码如下:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!