Hadoop第七章

1.map和reduce函数的输入和输出是键值对。遵循如下常规格式:

一般来说map函数的输入键值对类型不同于输出类型,虽然reduce函数的输入类型必须与map函数的输出类型相同,但是reduce函数的输出K3和V3类型可以不同于输入类型。

2.Mapper和Reducer是单独的类,Mapper的KEYIN的实际参数类型参数和Reducer中同名的KEYIN类型参数可能不一致。类似的即使map输出类型与reduce的输入类型必须匹配,但java编译器并不是强制要求的。类型参数命名可以不同于抽象类型的定义,但是它们的格式是相同的。

3.combine函数与reduce函数的形式相同,它是Reducer的一个实现,不同之处是它的输出类型是中间键值对类型K2和V2,这些中间值可以输出reduce函数:

combine函数与reduce函数通常是一样的,所以K3与K2类型相同,V3和V2类型相同。

Partition函数对中间结果的键值对k2和v2进行处理,并且返回一个分区索引,实际上分区由键单独决定,值被忽略。

4.输入数据的类型由输入格式进行设置,如键值对类型分别为LongWritable和Text,如果没有明显设置,中间的类型默认也是如此,因此如果k2与k3是相同的类型,就不需要调用setMapOutputKeyClass(),只调用setOutputKeyClass()设置。同样v2与v3相同,只需要使用setOutputValueClass(),如下是与MapReduce类型兼容的设置。

5.中间和最终输出类型的设置虽然奇怪,但是因为Java范型机制有很多限制:类型擦除导致运行过程中类型信息并非一直可见。所以Hadoop不得不进行明确设定,这意味着可能在MapReduce配置的作用中遇到不兼容的类型,因为这些配置在编译时无法检查,明智的做法是先用少量的数据跑一次测试数据,发现并修正任何类型不兼容的问题。

6.默认的partitioner是HashPatitioner,它对每条记录的键进行哈希操作决定该记录应该属于哪个分区,每个分区对应一个reducer任务,所以分区数等于作业的reducer个数。键的哈希码被转换成一个非负整数,他由哈希值与最大的整形值做一次按位与操,然后用分区数进行取模操作,来决定该记录属于哪个分区索引。

7.默认情况下只有一个reducer,也就是只有一个分区,这时候由于所有数据都放入一个分区,所以partitioner操作无关紧要,然而对于又很多reducer,那么记录将被均匀分到若干个reduce任务中,这样具有相同键的记录将由同一个reduce任务进行处理。

8.mao任务的数量等于输入文件被划分的分块数,这取决于输入文件的大小以及文件块的大小。

9.事实上,对于MapReduce程序来说,所有键都时Longwritable类型,所有的值都时Text类型,因为它们是输入键/值,并且map函数和reduce函数是恒等函数,然而大多数MapReduce程序不同一直用相同的键值类型,所以就必须设置作业来声明使用的类型。

                  记录在发送给reducer之前,会被MapReduce系统进行排序,比如天气温度例子中键是按照数值的大小进行排序的,因此来自输入文件中的行会被交叉放入一个合并后的输出文件。

默认的输入格式是TextInputFormat,产生的键类型是LongWritable(文件中每行中开始的偏移量值),值类型是Text(文本行)。

默认的输出格式是TextptpitFormat,它将键值对转换成字符串并用制表符分隔开,然后一条记录一行地进行输出,这就是为什么输出文件是用制表符分隔的,这是TextOutputFormat的特点。

10.在Streaming方式下,默认的作业与java方式相似但是也有差别,必须提供一个mapper,因为默认的mapper不能工作,因为默认输入格式TextInputFormat产生是LongWritable类型的键和Text类型的值,而Streaming的输出键和值(包括map的键/值)都是Text类型。Indentity mapper无法将LongWritable类型的键转换为Text类型的键,因而导致无法使用。简单形式如下:

11.如果用非java的mapper,输入格式是TextInputFormat,Streaming并不会把键传递给mapper,而是只传递值,对于其他输入类型将stram.map.input.ignoreKey设置为true,也可以达到相同的效果。因为键值时行偏移量,值才是真正关心的数据。

12.Streaming应用可以决定分隔符的使用,该分隔符用于通过标准输入把键值对转换成一串比特值发送到map或者reduce函数。默认情况下是制表符,但是如果键/值中本身含有Tab 分隔符,能将分隔符修改成其他符号是很有用的。类似的当map和reduce输出结果键值对时,也需要一个可配置的分隔符来进行分隔。Mapper和reducer的分隔符是单独配置的,如下:

这些属性和输入和输出的格式无关,如stram.reduce.output.field.separator被设置为冒号,rduce Srteaming过程就把a:b行写入标准输出,Streaming的reducer就会知道a作为键b作为值,如果使用标准的TextOutputFormat,那么这条记录就用Tab将和值分隔开并写道输出文件,可以设置mapred.textoutputformat.Separator来修改TextOUtputFormat的分隔符。

13.一个输入分片就是一个由单个map操作来处理的输入块。每个map操作只处理一个输入分片,每个分片被划分为若干个记录,每条记录就是一个键值对,map一个接一个地处理记录。输入分片和记录都是逻辑概念,不必实际对应。

14.如图所示,Input包含一个以字节为单位的长度和一组存储位置,即一组主机名,注意分片并不包含数据本身,而是指向数据的引用。存储位置公MapReuce系统使用以便将map任务尽量放在分片数据附近,而分片大小用来排序分片,以便优先处理最大的分片,从而最小化作业时间。

15.MapReduce应用开发用InputFormat直接处理InputSplit,InputFormat负责产生输入分片并将它们分割成记录,如图所示,运行作业的客户端通过调用getSplits()计算分片,然后将他们发送到jobtracker,jobtracker使用其存储位置信息来调度map任务从而在tasktracker上处理这些分片数据。在tasktracker上,map任务把输入分片传给InputFormat的getRecordReader()方法来获得这个分片的RecordReader来生成记录的键值对,然后再传递给map函数。

查看mapper的run()可以看到这些情况:

16.Mapper的run()方法可以由用户定制。MultithreadedMapRunner可以使用可配置的个数的线程来并发运行多个mapper(mapreduce.mapper.multithreadmapper.thread设置)。一般来说默认的执行机制没有优势,对于因为需要连接外部服务器而造成单个记录处理时间比较长的mapper来说,允许多个mapper在同一个JVM下以避免竞争的方式运行。

17.FileInputFormat是所有使用文件作为其数据源的InputFormat实现的基类,主要有两个功能:一个用于指出作业的输入文件位置;一个是输入文件生成分片的实现代码段,把分片分割成记录的作业由其子类完成。

18.一条路径可以表示一个文件、一个目录或者一个glob,即一个文件和目录的集合。路径时目录的话,表示要包含这个目录下的所有的文件,这些文件都作为作业的输入,但是不会递归处理。如果包含子目录,也会被解释为文件从而产生错误。解决办法是:使用一个文件glob或者一个过滤器根据命名模式限定选择目录中的文件。另一种方法是将mapred.input.dir.recursive设置为true从而强制对输入目录进行递归读取。

19.路径和过滤器也可以通过配置属性来设置,这对Streaming和Pipes应用很方便。如图。

20.FileInputFormat只分割大文件,这里的大文件指的是超过HDFS块的大小,分片通常与HDFS块大小一样,然而这个值也可以设置,如图

21.应用程序可以强制设置一个最小的输入分片大小:通过设置一个比HDFS块更大一些的值,强制分片比文件块大,如果数据存储在HDFS上,则没有好处,因为这样做会对map任务来说不是本地文件的文件块数。最大的分片大小默认是由long类型表示的最大值,只有把它的值被设置成小于块大小才有效果,这将强制分片比块小。

22.分片大小由一下公式计算:

默认情况下:

所以分片的大小就是blockksize,分片大小参数如图

23.相对于大批量的小文件,Hadoop更适合处理少量的大文件,一个原因就是FIleInputFormat生成的分块是一个文件或着该文件的一部分,如果文件小到比HDFS的块还要小很多,并且文件数量很多,每次map任务只处理很少的输入数据,一个文件就会有很多ma任务,每次map操作都造成额外的开销。

CombineFileInputFormat就是针对大批量小文件而设计的。当然在处理大文件的时候也有好处,这个类的本质就是使map操作中处理的数据量与HDFS中文件的块大小之间的耦合度降低了。如果每个mapper可以在几秒之内处理每个数据块,就可以把mapre.max.split.size的最大分片大小设置为块数的较小的整数倍。让每个map可以处理多个块,这样处理时间减少了,因为相对来说,少量的mpper的运行,减少了运行大量短时mapper所涉及的任务管理和启动开销。

24.可以的话尽量避免许多小文件的情况,因为MapReduce的最佳处理数据速度与数据在集群中的传输速度相同,处理小文件将增加作业必需的寻址次数,同时在HDFS中存储大量的小文件浪费namenode的内存。

25.一个可以减少大量小文件的方法是使用SequenceFile将这些小文件合并成一个或者多个大文件,可以将文件名或者NullWritable等常量作为键,文件的内容作为值。但是如果有大批量小文件可以试试CombineFileInputFormat。

26.有些用硬不希望文件被切分,用一个mapper完整处理每个输入文件,有两个办法保证输入文件不被切分,第一种就是增加最小分片大小,将它设置成大于要处理的最大文件大小,将它设置成大于要处理的最大文件大小。把它设置为最大值long.MAX_VALUE即可,第二种方法就是使用FileInputFormat具体子类,冲在isSplitable(),把返回值设置为false。

27.处理文件输入分片的mapper可以从作业配置对象的某些特定属性中读取输入分片的有关信息,这可以通过调用载Mapper的Context对象上的getInputSplit()方法来实现。当输入的格式源自于FileInputFormat时,该方式返回的InputSplit可以被强制转换为一个FileSplit,以此返回如图信息。

老版本的MapReduceAPI、Streaming和Pipes中,可以通过configure()方法来获取配置信息。

28.有时,mapper需要访问一个文件中的全部内容,即使不分割文件,仍然需要一个RecordReader来读取文件内容作为record的值。而将如果干小文件打包成顺序文件,至少有一种方法可以改进我们的程序,一个mapper处理一个文件的方法时低效的,较好的方式是继承combineFileInputFormat。

29.Hadoop擅长处理非结构化文本数据。TextInputFormat是默认的InputFormat,每条记录时一行输入。

30. 常见的处理文本的InputFormat类型有TextInputFormat、KeyVlaueTextInputFormat和NLineInputFormat。如包含以下文本的分片:

则TextInputFormat输出是:

KeyVlaueTextInputFormat可以改变分隔符:

NLineInputFormat可以设置每个mapper的收到的输入行数,如果N是2:

另一个mapper则收到:

31.

32.通常来说少量输入行之行map任务是低效的,但是有些饮用对少量数据做一些扩展的计算任务产生输出,比如仿真实验,通过生成一个指定输入参数的

输入文件,每行一个参数,便可以执行一个参数扫描分析;另一个例子是Hadoop引导从多个数据源加载数据,创建一个种子输入文件,记录所有的数据源,一行一个数据源,然后每个mapper分到一个数据源,并从这些数据源中加载数据到HDFS中,这个作业不需要reduce阶段,所以设置为0.

33.Hadoop提供了StreamXmlRecordReader类,通过把输入格式设置为StreamInputFormat,把stream.recordreader.class设置为org.apache.Hadoop.Streaming.StreamXmlRecordReader来使用StreamXmlRecordReader类。例如维基百科用XML格式提供大量数据内容,非常适合用MapReduce来并行处理。

34.Hadoop不仅可以处理文本数据,还可以处理二进制格式的数据。常见的类由SequenceFileInputFormat,SequenceFileAsTextInputFormat和SequenceFIleAsBinaryInputFormat。

Hadoop的顺序文件格式存储二进制的键值对的序列,由于是可分割的,所以它们很符合MapReduce数据的格式要求,并且支持压缩,可以使用一些序列化技术来存储任意类型。

                  如果要用顺序文件数据作为MapReduce的输入,应该用sequenceFileInputFormat。键/值由顺序文件决定,值需要保证map输入的类型匹配即可。

                  sequenceFileAsTextInputFormat是sequenceFileInputFormat的变体,它将顺序文件的键值转换为Text对象,这个转换通过在键值上调用toString()实现,这个格式使顺序文件作为Streaming的合适输入类型。

                  SequenceFIleAsBinaryInputFormat是sequenceFileInputFormat的一种变体,他获取顺序文件的键值作为二进制对象,它们被封装为BytesWritable对象。

35.一个MapReduce作业的输入可能包含多个输入文件,但是所有的文件都由同一个InputFormat和Mapper来解释,但是随时间演变会存在数据格式问题,MultipleInputs可以处理这些问题,它允许每条输入路径指定InputFormat和Mapper。如下图使用不同的mapper处理不同的数据文本一起来分析最高温度。

两个mapper抽取的年份和气温,而且输出类型一样,但是reducer看到的是聚集后的map输出,并不知道输入由不同的mapper产生。

36.DBInputFormat这种输入格式用于使用JDBC从关系数据库中读取数据,数据库中运行太多的mapper度数据可能会使数据库受不了,正是由于这个原因,DBInputFormat最好用于加载小量的数据集。如果需要与来自HDFS的大数据集链接,要使用MultipleInputs,与之对应的输出格式是DBOutputFormat,它适用于将作业输出数据转储到数据库。在关系数据库和HDFS之间移动数据的另一个方法是使用sqoop。

                  HBase的TableInputFormat的设计初衷是让MapReduce程序操作存放在HBase表中的数据,而TableOutputFormat则是把MapReduce的输出写到HBase。

36.Hadoop有相应的输出格式,如下有OutputFormat类的层次结构。

37.文本输出的默认格式是TextOutputFormat,他把每条记录写为文本行。它的键值对可以是任意类型,因为TextOutputFormat调用toString()方法把它们转换成字符串,默认是制表符进行分割,可以设置。可以使用NullWritable来省略输出的键/值,或者都省略。这会导致无分隔符输出,以使输出适合用TextInputFormat读取。

38.二进制输出常见的类有SequenceFileOutFormat将它的输出写为一个顺序文件,SequenceFileAsBinaryOutputFormat把键值对作为二进制格式写到一个SequenceFIle容器中。MapFileOutputFormat把MapFIle作为输出,MapFile中的键必需顺序添加,所以必须确保reducer输出的键已经排好序。

39.FileOutputFormat及其子类产生的文件放在输出目录下。每个reducer一个文件并且文件由分区号命名:part-r-00000,part-r-00001等等。有时可能需要对输出的文件名进行控制或者让每个reducer输出多个文件。MapReduce提供了MultipleOutputFormat类。

40.一般来说,让应用程序来严格限定分区数并不好,因为可能导致分区数少或者分区不均,让很多reducer做少量工作不是一个高校的作业组织方法,比较好的办法是使用更少reducer做更多的事情,因为运行任务的额外开销减少了。而且作业的运行时间可能由数据量最大的reducer运行时间决定。

                  最好让集群为作业决定分区数:集群的reducer任务槽越多,作业完成就快,这是默认的HashPartitioner表现如此出色的原因,因为它处理的分区数不限,并且保证每个分区有一个很好的键组合使分区更均匀。如果要用每个reducer写多个文件就要用MultipleOuput。

41.MultipleOutputFormat类可以讲数据写到多个文件,这些文件的名称源于输出的键值或者任意字符串。这允许每个reducer(或只有map作业的mapper)创建多个文件。采用name-m-nnnnn形式的文件名用于map输出,name-r-nnnnn形式的文件名用于reduce输出,其中name是程序设定的任意名字,nnnnn是一个指明块号的整数,从0开始。块号保证从不同块(mapper/reducer)写到输出在相同名字情况下不会冲突。

42.FIleOutputFormat的子类会产生输出文件,即使是空的,如果倾向不创建空文件,可以用LazyOutputFormat,它封装了输出格式,指定分第一条记录输出时才真正创建文件。用JobConf调用setOutputFormat()方法即可。

                  Streaming和Pipes支持-LazyOutput启动LazyOutputFormat功能。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王大丫丫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值