两个mapreduce 做topn_hadoop分布式计算MapReduce详细总结

《大数据和人工智能交流》头条号向广大初学者新增C 、Java 、Python 、Scala、javascript 等目前流行的计算机、大数据编程语言,希望大家以后关注本头条号更多的内容。

1、MapReduce概述

MapReduce用于大规模数据集(大于1TB)的并行运算。概念"Map(映射)"和"Reduce(归约)",是它们的主要思想,它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组。

MapReduce的目的就是在开发人员不熟悉分布式并行计算编程的情况下提供一个计算框架,使开发人员能够将自己的程序运行在分布式系统上。

MapReduce采用的是"分而治之"的思想,即将大数据切割成一块一块的小数据分发给各个集群结点同时进行计算,然后再把计算后的结果汇总。

2、MapReduce的特点

(1)易于使用

MapReduce只需要简单的实现一些接口,就可以完成一个分布式的程序,这些分布式程序可以分不到大量的廉价PC机上运行,Google就是运行大量廉价PC机的能手

(2)可扩展性强

当计算资源不足的时候,可以通过简单的增加机器来扩展它的计算能力

(3)集群高可靠性

(4)可以对PB量级以上的海量数据进行离线处理

MapReduce不擅长的计算:

(1)实时计算

(2)流式计算

(3)DAG(有向图)计算

3、MapReduce编程概述

MapReduce由两个阶段组成:Map和Reduce,用户只需要重map()和reduce()两个方法即可实现分布式计算程序。

Map()函数是以key/value键值对作为输入,产生另外一系列的key/value键值对作为中间结果输出到本地磁盘。MapReduce框架底层一些算法会自动将这些中间数据按照Key值进行聚集,默认采用的是哈希算法将key值相同的数据统一交给reduce()函数处理。

reduce()函数以key及对应的value列表作为输入,经合并key相同的value值后产生另外一系列key/value对作为最终输出写入HDFS。

一个完整的mapreduce程序有三类实例进程:

MRAppMaster:负责整个程序的协调过程

MapTask:负责map阶段的数据处理

ReduceTask:负责reduce阶段的数据处理

(1)Map阶段由一定数量的Map Task组成

格式解析:InputFormat(把输入文件分片)

据处理:继承Mapper类

组:继承Partitioner类

(2)Reduce阶段由一定数量的Reduce Task组成

从Map Task的输出拷贝数据, 按照key排序和分组(key相同的都放在一起,按照key进行分组操作,每一组交由Reducer进行处理),它继承Reducer类,可以通过OutputFormat类设置。

mapreduce详细流程图文详解:

310d4c2d410a76d93273c8fc6fed0305.png

切片:

(1)在FileInputFormat中,计算切片大小的逻辑:Math.max(minSize, Math.min(maxSize, blockSize))。

(2)minSize的默认值是1,而maxSize的默认值是long类型的最大值,即可得切片的默认大小是blockSize(128M)。

(3)maxSize参数如果调得比blocksize小,则会让切片变小,而且就等于配置的这个参数的值。

(4)minSize参数调的比blockSize大,则可以让切片变得比blocksize还大。

(5)hadoop为每个分片构建一个map任务,可以并行处理多个分片上的数据,整个数据的处理过程将得到很好的负载均衡,因为一台性能较强的计算机能处理更多的数据分片。

(6)分片也不能切得太小,否则多个map和reduce间数据的传输时间,管理分片,构建多个map任务的时间将决定整个作业的执行时间。

如果文件大小小于128M,则该文件不会被切片,不管文件多小都会是一个单独的切片,交给一个maptask处理.如果有大量的小文件,将导致产生大量的maptask,大大降低集群性能。

大量小文件的优化策略:

(1)在数据处理的前端就将小文件整合成大文件,再上传到hdfs上,即避免了hdfs不适合存储小文件的缺点,又避免了后期使用mapreduce处理大量小文件的问题。(最提倡的做法)

(2)小文件已经存在hdfs上了,可以使用另一种inputformat来做切片(CombineFileInputFormat),它的切片逻辑和FileInputFormat(默认)不同,它可以将多个小文件在逻辑上规划到一个切片上,交给一个maptask处理。

环形缓存区:

(1)经过map函数的逻辑处理后的数据输出之后,会通过OutPutCollector收集器将数据收集到环形缓存区保存。

(2)环形缓存区的大小默认为100M,当保存的数据达到80%时,就将缓存区的数据溢出到磁盘上保存。

溢出:

(1)环形缓存区的数据达到其容量的80%时就会溢出到磁盘上进行保存,在此过程中,程序会对数据进行分区(默认HashPartition)和排序(默认根据key进行快排)

(2)缓存区不断溢出的数据形成多个小文件

合并:

(1)溢出的多个小文件各个区合并在一起(1区和1区合并成一个1区),形成大文件。

(2)通过归并排序保证区内的数据有序。

Shuffle:

从过程2到过程7之间,即map任务和reduce任务之间的数据流称为shuffle(洗牌),而过程5最能体现出洗牌这一概念。一般情况下一个reduce任务的输入数据来自与多个map任务,多个reduce任务的情况下就会出现如过程5所示的,每个reduce任务从map的输出数据中获取属于自己的那个分区的数据。

运行reducetask的节点通过过程5,将来自多个map任务的属于自己的分区数据下载到本地磁盘工作目录。这多个分区文件通过归并排序合并成大文件,并根据key值分好组(key值相同的,value值会以迭代器的形式组在一起)。

ReduceTask:

ReduceTask从本地工作目录获取已经分好组并且排好序的数据,将数据进行reduce函数中的逻辑处理。

示例:单词计数WordCount

在假设有个文本文件hello,里面的内容如下:

hello you

hello me

每一行单词之间使用跳格键Tab分开,假设诸如这个文件格式的数据是T级别的海量数据,请使用MapReduce的计算框架统计每个单词出现个数

上述是个每个教材都的MapReduce使用的经典案例,程序代码不多而且很多都是可重用的代码,但是需要我们知道的流程、原理、设计思想却不少,其实很多框架比如Spring、Spark都是这样,能写出个"Hello World"需要你知道很多东西的,不过大家在学习过程中一定先摸清楚了使用路子再回过头看实现原理这样更简单些,作者通过大量的实训证明先实践-再理论-再实践-在理论…效果很明显

MapReduce计算原理如下:

读HDFS数据map处理reduce处理写回HDFS

我们自己的业务逻辑需要覆盖框架的map函数和reduce函数

第一步:map处理过程

107ec7014cb79342b88089bf8e3316dd.png

map读取上述文本数据的时候会"一行一行的读取",注意这点非常的重要,那么上述文件hello一共分2行读取,即hello you、hello me,注意每读取一行调用一次map函数,那么上述调用2次map函数。框架的map函数定义如下:

protected void map(LongWritable k1, Text v1, Mapper.Context context) throws java.io.IOException ,InterruptedException {

}

map再读取数据的时候,框架先按照行将数据转化为键值对。其中k1为该行的起始位置,v1为该行的内容。上述hello文本的键值对如下:

第1行的键值中起始位置按照字节数计算为0,内容为"hello you";第2行的键值中起始位置为10(别忘记了制表符和换行符),内容为"hello me"。数据整理如下:

<0 , "Hello you" >

<10 , "Hello me" >

那么map调用2次map函数,传递的数据分别为k1=0,v1= "Hello you" 、k2=10,v1= "Hello me" ,再这个过程中可以对k1和v1按照我们自己的业务逻辑进行处理。处理完成之后,我们还要将转成新的键值对然后使用上下文对象context的write方法写出去

上述hello统计单词的例子的伪代码(只是代表思路)如下:

Text k2=new Text();

LongWritable v2=new LongWritable();

protected void map(LongWritable k1, Text v1, Context context) {

String line = v1.toString();

String[] split = line.split("");

for(String word:split){

k2.set(word);

v2.set(1);

context.write(k2, v2);

}

}

过上述思路处理之后,新的的键值对为:。

第二步:reduce处理过程

9796400dec59b2b7b280e1a2f160b349.png

框架的reduce部分会将上述map处理后的进行排序、分组。排序是按照键k2对数据进行排序;分组是指把相同的k2的v2分到一个组中,例如hello文件

1、由map处理后的数据为

2、按照k2排序升序

3、按相同的k2分组

每一个分组调用一次reduce函数,其函数声明如下:

reduce的函数如下:

public class WordCountReducer extends Reducer{

LongWritable v3=new LongWritable();

protected void reduce(Text k2, java.lang.Iterable v2s, Reducer.Context context) throws java.io.IOException ,InterruptedException {

};

}

k2,v2s代表分组后的数据,那么传入的参数分别是:

k2=hello v2s = (1,1) ;k2 = you v2s =( 1) ; k2 = me v2s = (1)

那么单词计数的伪代码如下:

protected void reduce(k2 , v2 ,context){

long sum=0L;

for(LongWritable v2:v2s){

sum+=v2.get();

}

v3.set(sum);

context.write(k2, v3); //将写出,k3和k2相同

};

WordCount单词计数的完整源代码如下:

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Mapper;

public class WordCountMapper extends Mapper{

Text k2=new Text();

LongWritable v2=new LongWritable();

protected void map(LongWritable k1, Text v1, Mapper

LongWritable>.Context context) throws java.io.IOException ,InterruptedException {

String line = v1.toString();

String[] split = line.split("");

for(String word:split){

k2.set(word);

v2.set(1);

context.write(k2, v2);

}

};

}

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Reducer;

public class WordCountReducer extends Reducer{

LongWritable v3=new LongWritable();

protected void reduce(Text k2, java.lang.Iterable v2s, Reducer

LongWritable,Text,LongWritable>.Context context) throws java.io.IOException ,InterruptedException {

long sum=0L;

for(LongWritable v2:v2s){

sum+=v2.get();

}

v3.set(sum);

context.write(k2, v3);

};

}

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCount {

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

Configuration conf = new Configuration();

String jobName=WordCount.class.getSimpleName();

Job job=Job.getInstance(conf, jobName);

job.setJarByClass(WordCount.class);

//指定文件的输入路径

String inputPath=args[0];

FileInputFormat.setInputPaths(job, inputPath);

//指定具体FileInputFormat的子类

job.setInputFormatClass(TextInputFormat.class);

//指定自定义的Mapper类

job.setMapperClass(WordCountMapper.class);

job.setMapOutputKeyClass(Text.class);

job.setOutputValueClass(LongWritable.class);

//指定自定义Reducer类

job.setReducerClass(WordCountReducer.class);

job.setOutputKeyClass(Text.class);

job.setOutputValueClass(LongWritable.class);

//指定输出路径

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

FileOutputFormat.setOutputPath(job, ouputPath);

//指定具体的FileOutputFormat子类

job.setOutputFormatClass(TextOutputFormat.class);

//提交yarn运行

job.waitForCompletion(true);

}

}

4、总结educe工作原理

b590c0e6d78081fc2cc5004b73024722.png

上述结果可以省略reduce过程,直接将数据写入HDFS系统硬盘,假设我们2过程都有,其MapReduce框架数据处理过程如下:

(1)第1步:将数据按行解析成键值对

HDFS以块block为单位默认每个HDFS的block对应一个split(可以理解为把一个大块分成1个或若干个小块)块,框架一行一行的读取每个split小块中的数据解析成一个一个的键值对

(2)第2步:调用map函数

上述已经将每一行解析成一个个键值对,每个键值对调用一次map函数,输入的参数是一个个,输出是键值对。一个split块对应一个map 任务,我们可以按照自己的业务逻辑对每个进行运算处理,覆盖map函数即可实现自己的业务逻辑

(3)第3步:对处理后的键值对进行分区、排序、分组

框架对map输出的进行分区(可以把分区理解把你手里扑克牌分红桃、黑桃、方片、草花过程),不同的分区中的由不同的reduce任务处理,默认只有1个分区;排序默认正序;分组是值把相同的key的value放在一起,例如

(4)第4步:将处理结果写入HDFS系统磁盘中

(5)第5步:

对多个map任务的输出,按照不同的分区,通过网络传输到不同的reduce节点,这个过程称作shuffle(可以理解为每个map任务各自挑自己手里的红桃、黑桃、方片、草花,挑完之后按红桃、黑桃、方片、草花送到下家)

(6)调用reduce函数计算

调用reduce方法对分组后的数据即一个个的的数据进行处理,传入的参数是一个个的,输出是。每个分组调用一次reduce函数。我们可以覆盖reduce函数实现自己的业务逻辑。最后将数据写入HDFS系统磁盘。map任务和reduce的数量:可以通过修改在mapred-site.xml配置设置map任务和reduce的数量:

mapred.map.tasks

10

As a rule of thumb, use 10x the number of slaves(i.e., number of tasktrackers)

mapred.reduce.tasks

2

As a rule of thumb, use 2x the number of slaveprocessors (i.e., number of tasktrackers)

map的数量通常是由hadoop集群的DFS块大小确定的,也就是输入文件的总块数,正常的map数量的并行规模大致是每一个Node是10~100个

reduce任务的个数(分区的个数),建议设置为2*从节点个数

partition(分区)

数据从环形缓存区溢出到文件的过程中会根据用户自定义的partition函数进行分区,如果用户没有自定义该函数,程序会用默认的partitioner通过哈希函数来分区,hash partition 的好处是比较弹性,跟数据类型无关,实现简单,只需要设置reducetask的个数。分区的目的是将整个大数据块分成多个数据块,通过多个reducetask处理后,输出多个文件。通常在输出数据需要有所区分的情况下使用自定义分区,如在上述的流量统计的案例里,如果需要最后的输出数据再根据手机号码的省份分成几个文件来存储,则需要自定义partition函数,并在驱动程序里设置reduce任务数等于分区数(job.setNumReduceTasks(5);)和指明自己定义的partition(job.setPartitionerClass(ProvincePartitioner.class))。在需要获取统一的输出结果的情况下,不需要自定义partition也不用设置reducetask的数量(默认1个)。

自定义的分区函数有时会导致数据倾斜的问题,即有的分区数据量极大,各个分区数据量不均匀,这会导致整个作业时间取决于处理时间最长的那个reduce,应尽量避免这种情况发生。

combiner(map端的reduce)

集群的带宽限制了mapreduce作业的数量,因此应该尽量避免map和reduce任务之间的数据传输。hadoop允许用户对map的输出数据进行处理,用户可自定义combiner函数(如同map函数和reduce函数一般),其逻辑一般和reduce函数一样,combiner的输入是map的输出,combiner的输出作为reduce的输入,很多情况下可以直接将reduce函数作为conbiner函数来使用(job.setCombinerClass(FlowCountReducer.class);)。combiner属于优化方案,所以无法确定combiner函数会调用多少次,可以在环形缓存区溢出文件时调用combiner函数,也可以在溢出的小文件合并成大文件时调用combiner。但要保证不管调用几次combiner函数都不会影响最终的结果,所以不是所有处理逻辑都可以使用combiner组件,有些逻辑如果在使用了combiner函数后会改变最后rerduce的输出结果(如求几个数的平均值,就不能先用combiner求一次各个map输出结果的平均值,再求这些平均值的平均值,这将导致结果错误)。

combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量。(原先传给reduce的数据是(a,(1,1,1,1,1,1...)),使用combiner后传给reduce的数据变为(a,(4,2,3,5...)))

分组

分组和上面提到的partition(分区)不同,分组发生在reduce端,reduce的输入数据,会根据key是否相等而分为一组,如果key相等的,则这些key所对应的value值会作为一个迭代器对象传给reduce函数。以单词统计为例,reduce输入的数据就如:第一组:(a,(1,3,5,3,1))第二组:(b,(6,2,3,1,5))。上述例子也可以看出在map端是执行过combiner函数的,否则reduce获得的输入数据是:第一组:(a,(1,1,1,1,1,...))第二组:(b,(1,1,1,1,1...))。对每一组数据调用一次reduce函数。

值得一提的是如果key是用户自定义的bean对象,那么就算两个对象的内容都相同,这两个bean对象也不相等,也会被分为两组。如上述流量统计案例里自定义的flowbean对象,就算是上行流量下行流量相等的两个flowbean对象也不会被分为一组。这种bean作为key的情况下,如果处理逻辑需要将两个bean归为一个组,则需要另外的方法

排序

在整个mapreduce过程中涉及到多处对数据的排序,环形缓存区溢出的文件,溢出的小文件合并成大文件,reduce端多个分区数据合并成一个大的分区数据等都需要排序,而这排序规则是根据key的compareTo方法来的。

map端输出的数据的顺序不一定是reduce端输入数据的顺序,因为在这两者之间数据经过了排序,但reduce端输出到文件上显示的顺序就是reduce函数的写出顺序。在没有reduce函数的情况下,显示地在驱动函数里将reduce的数量设置为0(设置为0后表示没有reduce阶段,也就没有shuffle阶段,也就不会对数据进行各种排序分组),否则虽然没有reduce逻辑,但是还是会有shuffle阶段,map端处理完数据后将数据保存在文件上的顺序也不是map函数的写出顺序,而是经过shuffle分组排序过后的顺序

MapTask和ReduceTask的并行度

有几个maptask是由程序决定的,默认情况下使用FileInputFormat读入数据,maptask数量的依据有一下几点:

a.文件大小小于128M(默认)的情况下,有几个文件就有几个maptask

b.大于128M的文件,根据切片规则,有几个分片就有几个maptask

c.并不是maptask数量越多越好,太多maptask可能会占用大量数据传输等时间,降低集群计算时间,降低性能。大文件可适当增加blocksize的大小,如将128M的块大小改为256M或512M,这样切片的大小也会增大,切片数量也就减少了,相应地减少maptask的数量。如果小文件太多,可用上述提到过的小文件优化策略减少maptask的数量。

有几个reducetask是用户决定的,用户可以根据需求,自定义相应的partition函数,将数据分成几个区,相应地将reducetask的数量设置成分区数量。(设置5个reducetask,job.setNumReduceTasks(5))

YARN

1、用户提交的程序的运行逻辑对yarn是透明的,yarn并不需要知道。

2、yarn只提供运算资源的调度(用户程序向yarn申请资源,yarn就负责分配资源)。

3、yarn中的老大叫ResourceManager(知道所有小弟的资源情况,以做出资源分配),yarn中具体提供运算资源的角色叫NodeManager(小弟)。

4、yarn与运行的用户程序完全解耦,就意味着yarn上可以运行各种类型的分布式运算程序(mapreduce只是其中的一种),比如mapreduce、storm程序,spark程序...只要他们各自的框架中有符合yarn规范的资源请求机制即可。

6、Yarn是一个通用的资源调度平台,企业中存在的各种运算集群都可以整合在一个物理集群上,提高资源利用率,方便数据共享。

7、Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而mapreduce等运算程序则相当于运行于操作系统之上的应用程序。

5、MapReduce在Yarn上的运行过程

2c541b91bc6c035dd72268a79232a01a.png

客户端的配置信息mapreduce.framework.name为yarn时,客户端会启动YarnRunner(yarn的客户端程序),并将mapreduce作业提交给yarn平台处理。

(1)向ResourceManager请求运行一个mapreduce程序。

(2)ResourceManager返回hdfs地址,告诉客户端将作业运行相关的资源文件上传到hdfs。

(3)客户端提交mr程序运行所需的文件(包括作业的jar包,作业的配置文件,分片信息

等)到hdfs上。

(4)作业相关信息提交完成后,客户端用过调用ResourcrManager的submitApplication()

方法提交作业。

(5)ResourceManager将作业传递给调度器,调度器的默认调度策略是先进先出。

(6)调度器寻找一台空闲的节点,并在该节点隔离出一个容器(container),容器中分配

了cpu,内存等资源,并启动MRAppmaster进程。

(7)MRAppmaster根据需要运行多少个map任务,多少个reduce任务向ResourceManager

请求资源。

(8)ResourceManager分配相应数量的容器,并告知MRAppmaster容器在哪。

(9)MRAppmaster启动maptask。

(10)maptask从HDFS获取分片数据执行map逻辑。

(11)map逻辑执行结束后,MRAppmaster启动reducetask。

(12)reducetask从maptask获取属于自己的分区数据执行reduce逻辑。

(13)reduce逻辑结束后将结果数据保存到HDFS上。

(14)mapreduce作业结束后,MRAppmaster通知ResourceManager结束自己,让ResourceManager回收所有资源。

6、MapReduce其它话题

数据本地化优化

MRAppmaster向ResourceManager请求容器用于运行maptask时,在请求信息中有map所需要处理的分片数据所在的主机和相应的机架信息(即告诉MRAppmaster需要处理的数据在哪里),调度器根据这些信息做出调度决策。

(1)最理想的情况是将任务分配到数据本地化的节点上,这样一来map的输入数据不需要从其他节点通过网络传输过来,大大提高了性能。

(2)如果存储所需处理的三个HDFS数据块备份的三个节点都在运行其他map任务,处于忙碌状态,资源不足以再开辟一个容器来运行maptask。此时调度器会选择一个与数据所在节点同机架的节点来开辟容器,运行maptask。

(3)如果在同一机架上的节点都处于忙碌状态,调度器才会选择跨机架的节点,这会导致机架与机架之间的数据传输,是三种方式中性能最低的。

map和reduce的输出结果存放位置

map任务将其输出写到本地硬盘而不是HDFS,因为map任务的输出结果是中间结果,并不是最终结果,在mr程序结束后,map的输出结果就可以被删除,将其存在可靠的HDFS上一来是没必要浪费HDFS集群的空间,二来是没有存在本地硬盘的速度快。

reduce任务的输出是最终的输出结果,将其存在HDFS上可保证数据的安全。

map,reduce任务分配

默认情况下小于10个mapper且只有1个reducer且所需处理的数据总大小小于1个HDFS块的作业是小作业(可通过mapreduce.job.ubertask.maxmaps,mapreduce.job.ubertask.maxreduces,mapreduce.job.ubertask.maxbytes改变一个作业的默认配置),对于小作业,MRAppmaster会选择在与它同一个容器里运行任务(顺序运行),而不会去向ResourceManager请求资源。(mapreduce.job.ubertask.enable设为false将关闭小作业这一性质)。

作业不是小作业的情况下,MRAppmaster会向ResourceManager请求资源,ResourceManager根据数据本地化优化原则分配相应的容器。在默认情况下map任务和reduce任务都分配到1024MB的内存(可通过mapreduce.map.memory.mb和mapreduce.map.memory.mb来设置map任务和reduce任务的使用内存空间)。

调度器在分配容器时有两个参数,yarn.schedule.capacity.minimum-allocation-mb和yarn.schedule.capacity.minimum-allocation-mb,分别表示容器的最小可分配内存和最大可分配内存,默认值分别是1024MB和10240MB,手动给map,reduce任务分配内存空间时,应设置为容器最小可分配内存的整数倍且不大于最大可分配内存。在不设置map和reduce任务的使用内存情况下,调度器会自己根据任务的需要分配最接近的倍数的内存给容器。

map,reduce任务的并行

小作业的情况下,所有的map任务会在一个容器里顺序执行,所有map任务处理完后再执行1个reduce任务。是大作业的话,所有map任务会分别发送到不同容器里并行运行。而在一个节点上可以并行运行几个map,reduce任务,取决于节点的资源和每个任务所需的资源(如节点资源为8核8G可用内存,每个任务需要1个核1G内存,则该节点理论上可以开辟8个容器,并行执行8个任务)。在多个节点上的任务并行更是理所当然的,值得一提的是属于同一个作业的map任务和reduce任务不能并行,reduce任务一定是在接收到来自所有map任务的分区数据后再执行。

mapreduce输出数据压缩

map或reduce函数的输出可以压缩,减少网络io时间和存储空间,但相应地增加了cpu负担。

计算密集型的任务,少用压缩,将更多的cpu性能用在计算上

io密集型的任务,使用压缩提高mr速度

相应配置:

#map输出压缩

mapreduce.map.output.compress=true

mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.DefaultCodec

#也可在驱动类中写相应的代码

conf.setBoolean(Job.MAP_OUTPUT_COMPRESS, true);

conf.setClass(Job.MAP_OUTPUT_COMPRESS_CODEC, GzipCodec.class, CompressionCodec.class);

#reduce输出压缩

mapreduce.output.fileoutputformat.compress=true

mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.DefaultCodec

mapreduce.output.fileoutputformat.compress.type=RECORD

#也可在驱动类中写相应代码

Job job = Job.getInstance(conf);

FileOutputFormat.setCompressOutput(job, true);

FileOutputFormat.setOutputCompressorClass(job, (Class extends CompressionCodec>) Class.forName(""));

db2613f170a07113b386aed136d4fa2e.png

《大数据和人工智能交流》的宗旨

1、将大数据和人工智能的专业数学:概率数理统计、线性代数、决策论、优化论、博弈论等数学模型变得通俗易懂。

2、将大数据和人工智能的专业涉及到的数据结构和算法:分类、聚类 、回归算法、概率等算法变得通俗易懂。

3、最新的高科技动态:数据采集方面的智能传感器技术;医疗大数据智能决策分析;物联网智慧城市等等。

根据初学者需要会有C语言、Java语言、Python语言、Scala函数式等目前主流计算机语言。

根据读者的需要有和人工智能相关的计算机科学与技术、电子技术、芯片技术等基础学科通俗易懂的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值