Hadoop系列-MapReduce工作原理详解(十二)

21 篇文章 3 订阅
订阅专栏

一、MapReduce Mapper 

hadoop mapper 任务主要负责处理每个输入记录,并生成一个新 键值对,这个 键值对跟输入记录是完成不一样的。mapper 任务的输出数据由这些 键值对组成的集合。在 mapper 任务把数据写到本地磁盘之前,数据会被按 key 进行分区并排序,分区的目的是要把 key 相同的值聚集在一起。

MapReduce 框架为每个 InputSplit(数据分片)生成一个 map 任务,这里的 InputSplit 是由 InputFormat 生成的。

mapper 只会处理键值对形式的数据,所以把数据传给 mapper之前,需要把它转换成 这样的格式。

键值对是怎么生成的

让我们详细的来讨论一下键值对 是怎么生成的。

InputSplit :它是数据的逻辑表示,即数据分片,每个 InputSplit 会被一个 map 任务处理。
RecordReader :它会跟 InputSplit 交互,并把数据转换成适合 mapper 读取的键值对(key-value pair)记录。默认情况下,它用的是 TextInputFormat 类来做转换。RecordReader 与 InputSplit 交互一直到文件读取完成。它会给文件的每一行数据分配一个字节偏移量(byte offset)作为唯一编号。后续这些键值对将被发送给 mapper 做进一步处理。

Hadoop Mapper 是如何工作的

下面让我们来看一下 hadoop 里面 mapper 的工作过程。

InputSplit 会为 mapper 将 HDFS 块转换成逻辑分片。比如,要读取的文件是 200MB,那么就需要 2 个 InputSplit,因为这个有文件有 2 个block(默认块大小为 128MB),MapReduce 会为每个块创建一个 InputSplit,然后为每个 InputSplit 创建一个 RecordReader 和一个 mapper。

InputSplit 的数量并非总是依赖于数据块的数量,我们可以通过设置下面的属性,来为文件指定分片的数量。

mapred.max.split.size

RecordReader 主要负责读取数据,并把数据转换成 的形式。它会为文件的每一行数据分配一个字节偏移量(唯一编号),这些键值对数据会被发送给 mapper,mapper 处理之后把数据落地到本地磁盘,我们把 mapper 输出的数据叫做中间数据,其实就是临时数据。

map 任务的数量

本小节我们来讨论一下在执行 MapReduce 作业的时候,对于给定的数据量,如何计算出 mapper 任务数量?一般情况下,输入文件的数据块总量决定了 mapper 任务的数量。对于 map 阶段,每个节点的最佳并行度在 10 到 100 个 mapper 之间,虽然对于非 CPU 密集型的 map 任务,并行度已经被设置为 300 个 map。由于任务的启动需要消耗一些时间,所以如果 map 的执行超过一分钟的话,任务运行效率会更高。

举个例子,假如 HDFS 的块大小是 128MB,需要处理的数据的大小是 10TB,那么就需要 82000 个 map。这个 map 的数量由 InputFormat 类决定,其计算公式如下:

map 任务数量 = {( 数据总容量 ) / ( 分片大小 )}

如果数据是 1TB,数据分片大小是 100MB 的话,那么 map 任务数 = ( 1000 * 1000 ) / 100 = 10000。即 10000 个 map。


二、MapReduce Reducer

Reducer 获取 Mapper 的输出数据( 键值对 ),并对这些数据逐个处理,最终把最终处理结果存储到 HDFS。通常在 Hadoop 的 Reducer 阶段,我们会做聚合计算、求和计算等操作。

什么是 Hadoop Reducer

Reducer 处理 mapper 的输出数据,在处理这些数据的时候,它会生成一组新的输出数据。最后把数据存储到 HDFS。

Hadoop Reducer 以 mapper 输出的中间结果(键值对)作为输入数据,并对这些数据逐一执行 reducer 函数,比如可以对这些数据做聚合、过滤、合并等操作。Reducer 首先按 key 处理键值对的值,然后生成输出数据(零或多个键值对)。key 相同的键值对数据将会进入同一个 reducer,并且 reducer 是并行执行的,因为 reducer 之间不存在依赖关系。reducer 的数量由用户自己决定,默认值是 1。

MapReduce Reducer 阶段

通过前面章节的介绍我们已经知道,Hadoop MapReduce 的 Reducer 过程包含 3 个阶段。下面对他们进行逐个详细介绍。

Reducer 的 Shuffle 阶段

在本阶段,来自 mapper 的已经排好序的数据将作为 Reducer 的输入数据。在 Shuffle 阶段,MapReduce 通过 HTTP 协议拉取 mapper 输出数据的相应分区数据。

Reducer 的排序阶段

在该阶段,来自不同 mapper 的输入数据将会按 key 重新做排序。shuffle 和排序阶段是同时进行的。

Reduce 阶段

在 shuffle 和排序完成之后,reduce 任务对键值对数据做聚合操作。之后,OutputCollector.collect() 方法把 reduce 任务的输出结果写到 HDFS。Reducer 的输出不做排序。

Reducer 任务的数量

一个作业的 Reduce 任务数量是怎么确定的呢?以及如何修改 Reduce 数量?下面我们带着问题来详细了解一下。

我们可以通过 Job.setNumreduceTasks(int) 方法设置 reduce 的数量。一般合适的 reduce 任务数量可以通过下面公式计算:

(0.95 或者 1.75) * ( 节点数 * 每个节点最大的容器数量)

使用 0.95 的时候,当 map 任务完成后,reducer 会立即执行并开始传输 map 的输出数据。使用 1.75 的时候,第一批 reducer 任务将在运行速度更快的节点上执行完成,而第二批 reducer 任务的执行在负载平衡方面做得更好。


三、MapReduce 键值对

Apache Hadoop 主要用于数据分析,我们利用数据分析里面的统计和逻辑技术来描述,说明和评估数据。Hadoop 可以用来处理机构化,非结构化和半结构化数据。在使用 Hadoop 的时候,当模式是静态的时候,我们可以直接使用模式的列,如果模式是非静态的,就不能用列的,因为没有列的概念了,只能使用键和值来处理数据。键和值并非是数据的固有属性,它只是在对数据做分析时人为选择的一种策略。

MapReduce 是 Hadoop 的核心组件,主要用于数据处理。Hadoop MapReduce 是一种软件框架,利用这个框架很容易就能开发出处理存储在 HDFS 的大数据量的应用程序。MapReduce 把处理过程分成两个阶段:Map 阶段和 Reduce 阶段。每个阶段的输入数据和输出数据都是以键值对的形式出现。

MapReduce 键值对的生成

让我们来了解一下 MapReduce 框架是怎么生成键值对的。MapReduce 过程中,在数据传输给 mapper 之前,数据首先被转换成键值对,因为 mapper 只能处理键值对形式的数据。

Hadoop MapReduce 生成键值对的过程如下:

InputSplit:这个是数据的逻辑表示形式。单个独立的 Mapper 处理的数据就是由 InputSplit 提供的。
RecordReader:它和 InputSplit 交互,并且把数据分片转换成适合 Mapper 读取的记录,这里的记录其实就是数据的键值对形式。默认情况下,RecordReader 使用 TextInputFormat 把数据转换成键值对。RecordReader 和 InputSplit 的交互直到文件读取完成才停止。

在 MapReduce 框架里面,map 函数处理某个键值对并发出一定数量的键值对,Reduce 函数处理按相同键分组的值,并发出另一组键值对作为输出。map 的输出类型应该和 reduce 的输入类型一致。比如:

  • Map: (K1, V1) -> list (K2, V2)
  • Reduce: {(K2, list (V2 }) -> list (K3, V3)

K2,V2 数据类型是要保持一致的。

Hadoop 中生成键值对需要依赖什么?

Hadoop 中键值对的生成取决于数据集和所需的输出。通常,键值对在4个位置指定:Map 输入、Map 输出、Reduce 输入和 Reduce 输出。

Map 输入

map 输入默认把数据文件的行数作为键(key),数据行对应的内容作为值。可以对 InputFormat 进行定制化开发,可以修改这个默认设置。

Map 输出

Map 主要负责过滤数据,并为数据基于键分组提供基础。

Key:它可能是字段、文本、对象,Reducer 端会根据 Key 对数据做分组和聚合。
Value:它可能是字段、文本、对象。它会被单独的 reduce 函数处理。

Reduce 输入

Map 的输出作为 Reduce的输入,也就是说,Reduce 的输入数据和 Map 输出数据是一样的。

Reduce 输出

这个取决于所需要的输出是怎么样的。

MapReduce 键值对举例

假如有个存储在 HDFS 的文件的内容如下:

John is Mark Joey is John

利用 InputFormat,我们就可以知道这个文件是怎么被分片和读取的。默认情况下,RecordReader 使用 TextInputFormat 把这个文件转换成键值对数据。

Key:这个是键值对的键,它是数据行的偏移量。
Value:值就是数据行具体内容,不包含行终止符。

根据上文件的内容,具体的 Key 和 Value 的内容如下:

Key 是 24
Value 是 John is Mark Joey is John

四、MapReduce InputFormat

Hadoop InputFormat 会检查作业的数据输入规范,它把输入文件分割成 InputSplit 分片,并发送给 Mapper。

Hadoop InputFormat

输入文件的分片和读取是由 InputFormat 定义的。InputFormat 主要负责创建数据分片,并把它转换成记录(即键值对),如果你还不熟悉 MapReduce 作业的工作原理,请参考  MapReduce 工作原理。

MapReduce 任务处理的数据是存储在输入文件的,而输入文件一般保存在 HDFS。虽然这些文件的格式可以是任意的,如基于行的日志文件和二进制格式都有可能被使用。利用 InputFormat 我们可以分割和读取这些文件。InputFormat 类是 MapReduce 框架最基础的类之一,它提供如下功能:

  • 数据切分,按照某个策略将输入数据且分成若干个 split,以便确定 Map Task 的个数即 Mapper 的个数,在 MapReduce 框架中,一个 split 就意味着需要一个 Map Task。
  • 为 Mapper 提供输入数据,即给定一个 split,使用其中的 RecordReader 对象将之解析为一个个的key/value 键值对。

如何把数据发送给 Mapper

MapReduce 框架有 2 种方法可以把数据发送给 mapper:getsplits() 和 createRecordReader() 。

public abstract class InputFormat<K, V>
{
public abstract List<InputSplit> getSplits(JobContext context)
throws IOException, InterruptedException;

public abstract RecordReader<K, V> createRecordReader(InputSplit split,
TaskAttemptContext context) throws IOException,
InterruptedException;

MapReduce InputFormat 的几种类型

让我们来看一下 Hadoop 里面的几种 InputFormat。

FileInputFormat

它是所有基于文件的 InputFormat 的基类。Hadoop FileInputFormat 指定数据文件所在的输入目录。当我们启动一个 Hadoop 作业的时候,FileInputFormat 提供了一个包含要读取的文件的路径,它会读取路径下的所有文件,并把这些文件分割成一个或多个 InputSplit 。

TextInputFormat

这个是 MapReduce 默认使用的 InputFormat。TextInputFormat 会把输入文件的每一个数据行当成一个记录,这对于无格式数据或者基于行数据文件(如日志文件)非常有用。

KeyValueTextInputFormat

KeyValueTextInputFormat 和 TextInputFormat 类似,它也会把输入文件的每一个数据行当成一个记录。TextInputFormat 是把数据行的内容作为键值对的 Key 部分,而 KeyValueTextInputFormat 分割 Key 和 value 是用 tab 键(‘\t’)来区分的。在一行数据里面,tab 键前面的内容作为 Key,tab 键后面的内容作为 Value。

SequenceFileInputFormat

Hadoop SequenceFileInputFormat 用来读取顺序文件(sequence file)的。sequence 文件是一种存储二进制键值对序列的二进制文件。sequence 文件是块压缩的,并且提供了几种数据类型(不仅仅是文本类型)直接的序列化和反序列化操作。sequence 文件可以作为 MapReduce 任务的输出数据,并且用它做一个 MapReduce 作业到另一个作业的中间数据是很高效的。

SequenceFileAsTextInputFormat

Hadoop SequenceFileAsTextInputFormat 是 SequenceFileInputFormat 的另一种形式,它把 sequence 文件的 key / value 转换成文本对象。通过调用 “toString()” 方法,就可以把 key / value 转换成文本对象(Text Object)。这种 InputFormat 使得 sequence 文件适合作为流输入。

SequenceFileAsBinaryInputFormat

跟 SequenceFileAsTextInputFormat 类似,只是它从 sequence 文件读取 Key / Value 的时候是以二进制的形式读取的。

NLineInputFormat

Hadoop NLineInputFormat 是 TextInputFormat 的另一种形式,key 是数据行的字节偏移量,value 是数据行具体内容。如果InputFormat 是 TextInputFormat 和 KeyValueTextInputFormat,那么每个 mapper 接收的输入行数是可变的,并且 mapper 的数量取决于分片的数量和数据行的长度。如果我们想要让 mapper 接收固定数量的输入行的话,我们可以使用 NLineInputFormat 。NLineInputFormat 前面的 N 表示每个Mapper收到输入的行数。默认 情况下(N=1),每个 mapper 刚好接收一行,如果 N = 2,那么每个分片是 2 行,一个 mapper 将接收两个键值对。

DBInputFormat

Hadoop DBInputFormat 是一种使用 JDBC 从关系数据库读取数据的 InputFormat。使用 DBInputFormat 读取数据的时候, Key 是 LongWritables 类型,而 Value 是 DBWritables 类型。


五、MapReduce InputSplit

Hadoop InputSplit

InputSplit 是数据的一种逻辑表示,即我们所说的文件的数据分片。每个分片由一个 mapper 处理,当然,mapper 并非直接对数据分片进行处理,在 mapper 处理数据分片之前,数据分片会被转换成记录,即键值对。mapper 直接操作键值对。

MapReduce InputSplit 的长度是以字节来度量的,每个 InputSplit 都有相应的存储位置(主机名称)。MapReduce 利用分片存储位置,把 map 任务调度到距离数据尽可能近的地方执行。Map 任务的执行优先级取决于分片的大小,分片大的最先执行,主要为了最小化作业的运行时间。需要注意的是,InputSplit,即数据分片并不真正存储输入数据,它只是数据的一种引用,即一种数据的逻辑表示

我们并不需要直接处理 InputSplit,因为他们是由 InputFormat 创建的( InputFormat 创建 InputSplit 并把它转换成键值对)。默认情况下,FileInputFormat 把文件分割成若干个块,每个块大小 128MB(和 HDFS 的块大小一样),这个默认值可以在配置文件 mapred-site.xml 修改,参数为 mapred.min.split.size。也可以在提交作业的时候修改该值。另外,可以定制化开发 InputFormat,来决定分割文件的方式。

Hadoop 如何修改数据分片大小

我们可以在 MapReduce 程序根据数据的大小来调整分片大小。修改 mapred.min.split.size 这个参数即可。

客户端(运行 Job 的节点)调用 getSplit() 方法为一个作业计算分片大小,然后发送到 application master,它根据数据分片的存储位置对处理该数据分片的 map 任务进行调度。接下来 map 任务把分片传递给 InputFormat 的 createRecordReader() 方法以便获取分片的 RecordReader 对象,而 RecordReader 对象将生成记录,也就是键值对,然后传递给 map 函数。


六、MapReduce RecordReader

为了理解 MapReduce 框架的 RecordReader 原理,首先得搞清楚 Hadoop 的数据流程。下面我来了解一下 Hadoop 里面的数据流程是怎样的。

Hadoop RecordReader 简介

MapReduce 有一个简单数据处理模型,map 和 reduce 函数的输入数据和输出数据都必须是键值对(key-value pairs)。Hadoop MapReduce 的 map 和 Reduce 函数具有以下通用的形式:

  • map:(K1, V1) —> list(K2, V2)
  • reduce:(K2, list(V2)) —> list(K3, V3)

在 MapReduce 运行之前,它必须要知道到底需要处理什么数据,这个过程由 InputFormat 类来完成,InputFormat 类主要负责从 HDFS 读取 map 函数需要处理的文件,并且它还会创建 InputSplit 并把 InputSplit 转换成记录。在 HDFS 数据会被分割成若干个块,块大小默认为 128 MB。默认每个分片对应一个块,由一个 map 任务处理。

InputFormat 类调用 getSplits() 函数计算每个文件的分片,然后把分片发送给 JobTracker,它利用分片的存储位置信息,把执行该分片的 map 任务调度到 TaskTracker。然后,Map 任务把分片传递给 TaskTracker 里面的 InputFormat类的 createRecordReader() 方法,以便获取分片的 RecordReader 对象。RecordReader 读取分片数据并把它转换成适合 mapper 读取的键值对形式。

Hadoop RecordReader 读取由 InputSplit 创建的数据并创建相应的键值对。“start” 是 RecordReader 开始生成键值对的起始字节位置,也就是一条记录的起始位置,“end” 是停止读取记录的标志,一条记录的结束位置。这里的 “start” 和 “end” 是由 InputSplit 确定的,“start” 通过 InputSplit.getStart() 获取,“end” 通过 InputSplit.getStart + InputSplit.length 获取。

RecordReader 工作原理

RecordReader 不仅仅是记录的迭代器。map 任务利用一个记录生成一个键值对,我们可以通过 mapper 的 run 函数验证这一点:

public void run(Context context) throws IOException, InterruptedException{
setup(context);
while(context.nextKeyValue())
{
map(context.getCurrentKey(),context.getCurrentValue(),context)
}
cleanup(context);
}

在执行 setup() 之后, nextKeyValue() 将重复从 context 获取下个记录来填充 mapper 的 key 和 value 对象。而 key 和 value 是通过 context 读取的。map 函数的输入数据是键值对形式的 (K, V),当读取记录结束时,nextKeyValue 方法将返回 false。

RecordReader 根据 InputSplit 对数据划分好的数据边界进行读取,并生成键值对,但这个并非强制的,你可以通过自定义 RecordReader 来读取更多 InputSplit 之外的数据,但并不鼓励这么做。

RecordReader 分类

RecordReader 实例是被 InputFormat 定义的,默认情况下,它使用 TextInputFormat 把数据转换成键值对。TextInputFormat 提供 2 种 RecordReader,分别是 LineRecordReader 和 SequenceFileRecordReader。

LineRecordReader

LineRecordReader 是 TextInputFormat 默认的 RecordReader。它把输入文件的每一行内容作为 value,字节偏移量作为 key。

SequenceFileRecordReader

这个是 SequenceFileInputFormat 对应的 RecordReader。用于把二进制数据转换成记录形式。

单个记录的最大值

一个被处理的记录的大小是有限制的,默认的最大值为 Integer.MAX_VALUE。可以通过下面参数设置这个最大值:

conf.setInt("mapred.linerecordreader.maxlength", Integer.MAX_VALUE);

如果一行数据的大小超过这个最大值,那么该记录会被忽略掉。


七、MapReduce Combiner

当我们用 MapReduce 作业处理大数据集的时候,Mapper 生成的中间结果数据就会比较大,而且这些中间结果数据后续会被传输到 Reducer 继续处理,这会导致非常大的网络开销,甚至网络堵塞。MapReduce 框架提供了一个函数——Hadoop Combiner 函数,它在减少网络阻塞方面扮演着一个关键的角色。

我们在之前已经学习了 Hadoop MapReduce 框架的 mapper 和 reducer。现在我们来学习 Hadoop MapReduce 框架的 Combiner。

MapReduce combiner 也被称为 “微型 reducer ”。combiner 的主要工作就是在 Mapper 的输出数据被传输到 Reducer 之前对这些数据进行处理。它在 mapper 之后 reducer 之前执行,也就是在 mapper 和 reducer 两个阶段的中间执行。并且 combiner 的执行是可选的,即可用可不用。

MapReduce combiner 工作原理

让我们来理解一下 Hadoop combiner 的工作原理,以及比较一下使用了 combiner 和未使用两者的区别。

未使用 combiner 的 MapReduce 程序

在上图中,MapReduce 程序没有使用 combiner。输入数据被分到两个 mapper 里面,并且生成了 9 个 key。现在 mapper 的中间结果已经产生了,即上图所示的 9 个键值对。后续 mapper 将会把这些数据直接发送到 reducer。在数据发送给 reducer 期间,这些数据的传输会消耗一些网络带宽(带宽,即在两台机器间传输数据的时间消耗)。如果数据容量很大,那么数据传输到 reducer 的耗时就更长。

如果我们在 mapper 和 reducer 中间使用了 combiner,那么,数据在从 mapper 传输到 reducer 之前,combiner 会对数据按 key 做聚合,那么输出的数据就是 4 个键值对。

使用 combiner 的 MapReduce 程序

在使用了 combiner 之后,Reducer 只需要处理由 2 个 combiner 生成的 4 个键值对数据。因此,reducer 生成最终结果只需要执行 4 次即可。作业的整体性能得到显著提升。

MapReduce combiner 优点

我们已经详细讨论了什么是 Hadoop MapReduce combiner,现在我们讨论一下使用 MapReduce combiner 的优势。

  • Hadoop combiner 减少了数据从 mapper 到 reducer 之间的传输时间。
  • 减少 reducer 处理的数据量,但最终计算结果不变。
  • 提升 reducer 的整体性能。

MapReduce combiner 缺点

  • MapReduce job 不能依赖于 Hadoop combiner 的执行,因为 combiner 的执行没有保证。
  • 在本地文件系统中,键值对是存储在 Hadoop 中的,运行 combiner 会导致昂贵的磁盘IO 开销。

八、MapReduce Partitioner

MapReduce Partitioner 是用来对 mapper 输出的数据进行分区的。partitioner 通过哈希函数对 Key 或者 Key 的子集求哈希值,哈希值相同的键值对将在同一个分区里面。分区的数量取决于 reduce 任务的数量。下面对 MapReduce Partitioner 详细介绍。

MapReduce Partitioner

在开始学习 MapReduce Partitioner 之前,你需要先理解一下 mapper、reducer 以及 combiner 的概念。

map 输出的键值对的分区逻辑由 Partitioner 决定的。通过哈希函数,对 key 进行哈希并生成哈希值。每个 mapper 的输出都会被分区,key 相同记录将被分在同一个分区里。每个分区会被发送给一个 reducer。(key, value) 键值对将会被分到哪一个分区是由 Partition 类决定的。分区阶段发生在 map 阶段之后 reduce 阶段之前。MapReduce 为什么要设计分区这个阶段呢?下面会给出答案。

Hadoop MapReduce Partitioner 的必要性

现在让我们来讨论一下 Hadoop MapReduce Partitioner 的必要性。

MapReduce 作业接收一个输入数据集并生成键值对列表,这里的键值对列表是 map 阶段的输出结果数据,在这个阶段里面,输入数据会被切分成分片,每个 map 任务处理一个数据分片,并生成键值对列表。接着,map 的输出数据被发送到 reduce 任务,它会执行用户自定义的 reduce 函数,该函数会对 map 的输出数据进行计算。但在 reduce 阶段之前,map 的输出数据会被基于 Key 分区并排序。

分区的目的是把具有相同 key 的值集合在一起,确保 key 相同的值都会在同一个 reducer 里面。这样才能保证 map 的输出数据被均匀的分发到 reducer 。

默认的 MapReduce Partitioner

Hadoop MapReduce 默认的 Hadoop Partitioner 是哈希 Partitioner(Hash Partitioner),它会对 key 计算哈希值,并基于该哈希值对键值对数据进行分区。

一个 MapReduce job 会有多少个 Partitioner

Partitioner 的数量等于 reducer 的数量,Partitioner 会根据 reducer 的数量来划分数据,reducer 数量可以通过下面的方法进行设置:

JobConf.setNumReduceTasks()

因此,来自同一个分区的数据会被一个 reducer 任务处理。需要注意的是,只有作业具有多个reducer 任务时,分区才会被创建。也就是说,如果作业只有 1 个 reducer 任务,分区阶段是不会发生的。

低效的分区

如果在输入数据集里面,有一个 key 的数量比其他 key 的数量要大得多,这种情况,有两种机制可以对数据进行分区。

  • 数量比其他 key 大得多的数据分到一个分区
  • 其他 key 根据他们的 hashCode() 的值进行分区

但如果 hashCode() 方法不能均匀的把其他 key 的数据分发到分区,那么数据将会被均匀的发送到 reducer 任务。低效的分区意味着,某些 reducer 将比其他 reducer 任务处理更多的数据。那么,整个作业的运行时间将取决于这些需要处理更多数据的 reducer,也就是说,作业的运行时间会更长。

如何克服低效分区

为了克服低效分区的问题,我们可以自定义分区器(partitioner),这样我们就可以根据具体业务修改分区逻辑,把数据均分的分发到不同的 reducer 任务里。 


九、MapReduce Shuffle 和排序

mapper 的输出结果被传输到 reducer 的过程被称为 shuffle,并且在传输到 reducer 之前,数据会被按 key 排序。下面会详细介绍这两个过程。

Hadoop MapReduce Shuffle 和排序

在学习 shuffle 和排序之前,可以先复习一下 MapReduce 的其他阶段,比如  Mapper, Reducer, Combiner, partitioner 以及  InputFormat。

MapReduce 框架的 Shuffle 阶段指的是把 map 的输出结果从 Mapper 传输到 Reducer 的过程。MapReduce 的排序阶段包括对 map 输出的合并和排序两个步骤。mapper 的输出数据会被按 key 分组和排序。每一个 reducer 获取所有具有相同 key 的值。MapReduce 框架的 shuffle 和排序阶段是同时发生的。

Shuffle

我们都知道,数据从 mapper 传输到 reducer 的过程被称为 shuffle。所以,MapReduce Shuffle 阶段对于 reducer 来说是有必要的,否则,reducer 就没任务输入数据。由于 shuffle 可以在 map 阶段完成之前就启动,所以这回节省一些运行时间,以更少的时间完成任务。

排序

由 mapper 生成的 key 会被 MapReduce 框架自动排序,比如,在 reducer 启动之前,所有由 mapper 生成的中间结果键值对会按 key 进行排序而不是按 value 排序。传输给 reducer 的 value 并没有排序,它们的顺序是任意的。

Hadoop 中的排序帮助 reducer 轻松区分何时应该启动新的 reduce 任务。这会为 reducer 节省一些时间。在已排序的输入数据中,当下一个 key 和 前一个 key 不一样的时候,reducer 就会启动一个新的 reduce 任务。每个 reduce 任务以键值对作为输入并输出键值对数据。

需要注意的是,如果你通过下面的代码把 reducer 任务的个数设置为0,那么作业就不会有 shuffle 和排序阶段了。

setNumReduceTasks(0)

这时,MapReduce 作业在 map 阶段完成后就结束的,而且,map 阶段不包括任何类型的排序操作,所以这样的 map 阶段执行速度会更快。

MapReduce 二次排序

如果你想对 reducer 的键值对的 value 进行排序,那么,就需要用到二次排序技术了,二次排序技术可以让我们对传输到每个 reducer 的键值对的 value 以降序或者升序排序。


十、MapReduce OutputFormat

Hadoop OutputFormat 负责检验 job 的输出规范,RecordWriter 把输出数据写到输出文件的具体实现就是由 OutputFormat 决定的。

Hadoop Outputformat

在开始学习 MapReduce 框架的 OutputFormat 之前,让我们先来看一下 RecordWriter ,以及它在 MapReduce 框架起到什么样的作用。

Hadoop RecordWriter

我们知道,Reducer 以 mapper 输出的键值对结果为输入数据,并对这些数据执行 reducer 函数,它最终输出的结果依然是键值对数据。RecordWriter 负责把 Reducer 输出的键值对数据写到输出文件。

Hadoop Outputformat

在前面我们已经了解到,Hadoop RecordWriter 获取 Reducer 输出的数据,并把这些数据写到输出文件。而 RecordWriter 用怎样的格式把数据写到文件,这些行为是由 OutputFormat 决定的。OutputFormat 和 InputFormat 函数两者之间有许多共同之处。OutputFormat 函数负责把文件写到 HDFS 或者本地磁盘,它描述了 MapReduce job 输出数据的规范:

  • MapReduce job 检查输出目录是否已经存在
  • OutputFormat 提供的 RecordWriter 把结果数据写到输出文件,该输出文件会被存储在文件系统。

FileOutputformat.setOutputPath() 方法用来设置输出目录。每个 Reducer 会把数据写到公共目录下的一个独立文件中,每个 reducer 对应一个文件。

Hadoop OutputFormat 的分类

和 InputFormat 一样,Hadoop OutputFormat 也分好几种不同分类。

TextOutputFormat

Reducer 默认的输出格式是 TextOutputFormat,它是以每一行一个键值对的形式写入数据的,key 和 value 可能是任意数据类型的,但最终 TextOutputFormat 会调用 toString() 方法把他们转换成字符串类型。键值对之间以 tab 键作为分割符,你可以通过修改下面的属性修改这个默认的设置:

MapReduce.output.textoutputformat.separator

与 TextOutputFormat 对应的输入格式是 KeyValueTextInputFormat,它通过可配置的分隔符将键值对文本行分割。

SequenceFileOutputFormat

SequenceFileOutputformat 将它的输出写为一个顺序文件。如果输出需要作为后续 MapReduce 任务的输入,这是一种比较好的输出格式,因为它的格式紧凑,很容易被压缩。压缩由 SequenceFileOutputformat 的静态方法 putCompressionType() 来实现。

SequenceFileAsBinaryOutputFormat

SequenceFileAsBinaryOutputFormat 与 SequenceFileAsBinaryInputFormat 相对应,它以原始的二进制格式把键值对写到一个顺序文件中。

MapFileOutputFormat

MapFileOutputformat 以 map 文件作为输出。MapFile 中的键必须顺序添加,所以必须确保 reducer 输出的键是已经拍好序的。

MultipleOutput

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

LazyOutputFormat

FileOutputformat 的子类会产生输出文件( part-r-nnnnn ),即使文件是空的。有些应用倾向于不创建空文件,此时 LazyOutputFormat 就有用武之地了。它是一个封装输出格式,可以保证指定分区第一条记录输出时才真正创建文件。要使用它,用 JobConf 和相关的输出格式作为参数来调用 setOutputFormatClass() 方法即可。

DBOutputFormat

它适用于将作业输出数据转储到关系数据库和 HBase。


附1: MapReduce InputSplit 与 HDFS 块区别

InputSplit 即数据分片,HDFS 块(block)即分布式存储系统的数据块概念。下面详细介绍这两个概念的区别和联系。

HDFS 块与 InputSplit

HDFS 块

块是硬盘上存储数据的一个连续位置。通常,文件系统将数据存储成块的集合。同样的方式,HDFS 以块的方式存储文件。Hadoop 应用程序负责在多个节点分配数据块。

InputSplit

InputSplit 即我们所说的数据分片,一个单独的 mapper 处理的数据由 InputSplit 提供,即一个数据分片对应被一个 mapper 处理,数据分片会转换成记录,每个记录(即键值对)会被 map 处理。map 任务的个数等于数据分片的数量。

一开始 MapReduce 任务处理的数据是存储在输入文件的,而输入文件一般在 HDFS 。输入文件如何被读取和切分由 InputFormat 类来决定,另外它还负责创建 InputSplit。

InputSplit 和 块的比较

让我们来讨论 MapReduce InputSplit 和块之间的特性比较。

InputSplit 与块的大小比较

:HDFS 块的默认大小是 128MB,我们可以按实际需求对该值进行配置。除了最后一个数据块,文件的其他所有块大小都是一样的,最后一个数据块大小一般小于等于 128MB。文件被切分成若干个大小为 128MB 的数据块,并存储到 Hadoop 文件系统。

InputSplit:默认情况下,InputSplit 的大小近似等于块大小。InputSplit 是由用户自己定义的,并且基于数据的容量可以在 MapReduce 程序调整 InputSplit 的值。

InputSplit 和 块的数据表示

:块是数据的物理表示,它包含可读或者可写的最小数据量。
InputSplit:它是块中数据的逻辑表示。它是在 MapReduce 程序处理数据的时候被使用的。InputSplit 本身并不存储物理数据,它只是数据的一种引用。

InputSplit 和 块示例

假如我们需要把文件存储到 HDFS。HDFS 以块的形式存储文件,块是数据读取和存储的最小单位,并且块的默认大小是 128MB 。HDFS 把文件切分成块,并把块存储在集群的不同机器节点上,假如我们有一个 130MB 的文件,那么 HDFS 会把这个文件切割成 2 个块,如上第一个图所示。

现在,如果我们想对这些块执行 MapReduce 程序,那么它是不会被处理的,因为第二个块并不是完整的块。但是这个问题 InputSplit 可以解决。InputSplit 可以把一组 block 作为一个单独的块,因为 InputSplit 里面包含下一个块的位置以及完整的块所需的数据的字节偏移量。


附2:MapReduce 只有 Map 阶段的 job

在 Hadoop,只有 Map 任务的作业就是 mapper 处理了所有的数据处理任务,作业的整个过程没有 reducer 参与,而 mapper 的输出结果就是作业的最终输出结果。

仅 Map 阶段的 MapReduce 作业

MapReduce 是一种软件框架,利用该框架可以快速开发出处理大数据量的应用程序。MapReduce 框架的两个重要任务是:Map 任务和 Reduce 任务。Map 阶段接收一批数据,并把这些数据转换键值对。Reduce 阶段以 map 阶段的输出结果为输入数据,并且对这些数据基于 key 做聚合。

从上图我们可以知道,在一个 MapReduce job 里面有两组并行进程,即 map 和 reduce;在 map 进程,首先输入数据会被分发到多个 map 节点 ,然后每个单词被标记并生成键值对 。

第一个 mapper 节点接收到 3 个单词分别是 lion,tiger 和 river,因此节点的输出将会是 3 个键值对,其中 key 是单词本身,value 设置为 1。其他节点的处理过程跟第一个 mapper 一致。这些键值对之后会被传递给 reducer 节点,这样就会发生 shuffle 操作,也就是说,所有具有相同 key 的键值对会被分发到相同的节点。因此,在 reduce 进程中,就是对具有相同 key 的 value 进行运算操作。

现在让我们来考虑这样一个场景,如果我们只需要执行分发的操作,而不需要聚合的操作,那么这种情况下,我们就会更倾向于使用只有 map 阶段的作业。 在仅发生 Map 阶段的 Hadoop 作业中,map 阶段利用 InputSplit 就完成了所有的任务,并不需要 reducer 的参与。这里 map 的输出数据就是作业的最终输出结果了。

如何避免 Reduce 阶段的产生

为了避免触发 Reduce 任务,你可以在驱动程序(driver program)通过调用下面的方法来把 reduce 任务数设置为 0。

job.setNumreduceTasks(0)

设置完之后,Hadoop 作业在执行的时候就只有 map 阶段,而不会发生 reduce 了。

优点

在 map 和 reduce 两个阶段之间,包含排序和 shuffle 阶段。排序和 shuffle 负责对 key 升序排序和基于相同 key 对 value 进行分组。这个阶段的开销是非常大的。如果 reduce 阶段不是必要的,那么我们可以通过把 reduce 任务数设置为 0 来避免 reduce 阶段的发生,而且排序和 shuffle 阶段也不会发生。同时还可以避免数据传输的网络开销。

在一般的 MapReduce 作业中,mapper 的输出在被发送给 reducer 之前会先把输出数据写到本地磁盘,但在只有 map 的作业里,map 的输出会被直接写到 HDFS,这将节省了作业运行时间和 reduce 的开销。另外 partitioner 和 combiner 这两步在只有 map 的作业里是不需要的,所以这也会让作业运行的更快。


 参考: MapReduce Mapper | MapReduce 教程 ...

MapReduce InputSplit 与 HDFS 块 | MapReduce 教程

14-如何合-Partitioner&Combiner&Shuffle&OutputFormat解析
软通大学企业博客
12-30 474
Hadoop Partitioner&Combiner&Shuffle&OutputFormat解析 1 概述 我们在本节的目标是关注数据的归并过程,包括Partitioner、Combiner、Shuffle&Sort以及OutputFormat等组件合过程。 对于Partioner,我们将讨论什么是Hadoop Partitioner。MapReduce中的Pa...
Hadoop MapReduce执行过程详解(带hadoop例子)
weixin_33937778的博客
06-06 554
为什么80%的码农都做不了架构师?>>> ...
分布式计算框架Hadoop原理及架构全解
02-25
本文来自于csdn,这篇文章讲解了分布式计算框架的核心内容、架构图详解,运用流程等Hadoop是Apache软件基金会所开发的并行计算框架与分布式文件系统。最核心的模块包括HadoopCommon、HDFS与MapReduce。HDFSHDFS是Hadoop分布式文件系统(HadoopDistributedFileSystem)的缩写,为分布式计算存储提供了底层支持。采用Java语言开发,可以部署在多种普通的廉价机器上,以集群处理数量积达到大型主机处理性能。HDFS架构原理HDFS采用master/slave架构。一个HDFS集群包含一个单独的NameNode和多个DataNode。NameN
Hadoop从入门到上手企业开发
07-15
近百节课视频详细讲解,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 课程目录 000 上课方式和课程大纲介绍 001 Linux系统基本知识说明和启动Linux虚拟机 002 配置虚拟机IP地址和如何使用远程工具SecureCRT 003 Linux 环境下基本命令使用及Linux系统中文件的类型和权限 004 Linux 环境下基本命令讲解二 005 Linux 系统远程FTP工具与桌面工具XManager使用和培养三大能力 006 Linux 系统基本命令和基本配置的复习讲解 007 What is Apache Hadoop讲解 008 Hadoop 的发展史和版本发展与区别 009 Hadoop 生态系统介绍讲解 010 Hadoop 生态系统介绍讲解 011 Hadoop 服务讲解 012 HDFS 架构的讲解 013 MapReduce 架构讲解和MapReduce思想原理讲解 014 Apache Hadoop 三种安装部署模式讲解 015 Apache Hadoop 单机(本地)模式安装部署与测试 016 Hadoop 伪分布式安装部署 017 查看Hadoop 日志以及日志的格式和命名组成 018 Hadoop 守护进程服务三种启动停止方式 019 测试环境(HDFS Shell基本命令和运行WordCount程序) 020 结合WordCount实例讲解Hadoop的数据存储和数据计算 021 Hadoop 五大服务与配置文件中的对应关系 022 分析Hadoop 三种启动停止方式的Shell 脚本 023 去除警告【Warning$HADOOP HOME is deprecated。】 024 Hadoop相关命令中的【–config configdir】作用 025 Hadoop 目录结构 026 Eclipse导入Hadoop源码项目 027 HDFS 设计目标 028 HDFS 文件系统架构概述 029 HDFS架构之NameNode和DataNode 030 HDFS 架构讲解总结 031 回顾NameNode和DataNode 032 HDFS架构之Client和SNN功能 033 HDFS Shell 命令命令讲解和演示 034 讲解HDFS 文件读写流程 035 详解HDFS API之FileSystem方式基本操作一 036 HDFS Java API 两种方式介绍及使用URL API详解一 037 使用URL API详解二 038 使用HDFS FileSystem API 详解 039 HDFS文件系统读写流程及HDFS API两种方式读取文件 040 详解HDFS API之FileSystem方式基本操作二 041 讲解分析Configuration和FileSystem类源代码 042 引出HDFS实际应用场景之合并文件和使用getmerge命令并查看实现源码 043 分析getmerge功能实现思路和代码实现 044 演示讲解【百度网盘】功能与HDFS API对应说明 045 HDFS 专题结束和布置HDFS 作业 046 MapReduce架构原理介绍讲解 047 WordCount运行和MapReduce运行基本流程 048 MapReduce执行流程详解 049 MapReduce编程模型讲解及运行PI程序和JobWebUI监控Job运行 050 如何按照【八股文】方式编写MapReduce 051 复习MapReduce编写模型和【八股文】方式编写MapReduce 052 完成MyWordCount程序编写 053 打包运行MyWordCount程序并监控Job运行 054 优化MyWordCount程序和讲解GenericOptionsParser 055 安装Hadoop Eclipse插件并使用Eclipse查看文件系统 056 使用Eclipse运行MyWordCount程序并解决PriviledgedActionException问题 057 MyWordCount 处理过程详解 058 MapReduce提交作业源码跟踪讲解 059 MR作业运行流程整体分析 060 MapReduce执行流程之Shuffle和排序流程以及Map端分析 061 MapReduce执行流程之Reduce端分析 062 MapReduce Shuffle过程讲解和Map Shuffle Phase讲解 063 Reduce Shuffle Phase讲解 064 源代码跟踪查看Map Task和Reduce Task数目的个数 065 回顾MapReduce执行过程以及MapReduce核心 066 Hadoop MapReduce框架数据类型讲解 067
MapReduce
wsfengye的博客
04-03 254
一、例子 如果想统计下过去10年计算机论文出现最多的几个单词,看看大家都在研究些什么,那收集好论文后,该怎么办呢?方法一:我可以写一个小程序,把所有论文按顺序遍历一遍,统计每一个遇到的单词的出现次数,最后就可以知道哪几个单词最热门了。这种方法在数据集比较小时,是非常有效的,而且实现最简单,用来解决这个问题很合适。方法二:写一个多线程程序,并发遍历论文。这个问题理论上是可以高度并发的,因为统计一...
mapper排序_MapReduce之Shuffle,自定义对象,排序已经Combiner
weixin_36263001的博客
12-11 424
1. Shuffle:MapReduce的计算模型主要分为三个阶段,Map, shuffle, Reduce。 Map负责数据的过滤,将文件中的数据转化为键值对,Reduce负责合并将具有相同的键的值进行处理合并然后输出到HDFS。 为了让Reduce可以并行处理map的结果,必须对Map的输出进行一定的排序和分割,然后交个Reduce,这个过程就是Shuffle。官方给的图如下:上图Map和Re...
Hadood之MapReduce的介绍及简单例子
最新发布
m0_71417856的博客
06-08 365
1. 到底什么是Mapper与Reducer2. 为什么要用MapReduce而不是普通的代码3. 常见的MapReduce任务示例3.1 简单的单词计数任务3.1.1 自动排序功能~~~~~~~首先给出定义:Mapper与Reducer是MapReduce编程模型的两个核心组件,用于处理大规模数据集的并行计算。Mapper(映射器):Mapper的主要任务是将输入数据分割成较小的数据块,并为每个数据块生成键值对
mapperducer基本案例实操(简单易懂)
weixin_52733693的博客
09-27 867
MapperReduce学习基本案例,小白入门必备
MapReduce基础原理及应用
妖精小狗的博客
04-07 5974
MapReduce基础原理: MapReduce(起源于Google): MapReduce是一种计算模型,它将大型数据操作作业分解为可以跨服务器集群并行执行的单个任务。用于管理DataNode 用于大规模数据处理:每个节点处理存储在该节点上的数据 每个MapReduce工作由两个阶段组成:Map;Reduce 自动MapReduce计算: MapReduce计算是并行和自动分布的 ...
大数据之Hadoop_MapReduce自定义输出和输入类型
WuBoooo的博客
08-21 558
自定义输出和输入类型介绍 我们在使用MapReduce处理需要两次聚合的数据时,我们会进行两次输出,第二次输出的结果是读取第一次输出的结果进程聚合处理的,但我们只需要看到第二次的聚合的结果就可以了,第一次聚合的结果我们是否能看懂都无所谓, 此时我们在进行第一次输出时,我们可以将输出类型由原来(当我们未自定义时默认的输入和输出类型都是TextInputFormat和TextOutputFormat)改为SequenceFileOutputFormat,Sequence相对于Text类型处理速度较快,且更节约内
MapReduce 工作原理
m0_72168501的博客
12-13 2789
MapReduce工作原理
Hadoop mapper类和reducer类的阅读 Hadoop(1)
jbt2008bg的专栏
10-22 397
Hadoop的mapper类中,有4个主要的函数,分别是:setup,clearup,map,run。 protected void setup(Context context) throws IOException, InterruptedException { // NOTHING } protected void map(KEYIN key, VALUEIN value,
高性能集合流式操作,MapReduce初体验
weixin_34343308的博客
10-19 144
高性能集合流式操作,MapReduce初体验 1、MapReduce简介源自于google的MapReduce论文,发表于2004年12月,HadoopMapReduce是google MapReduce 克隆版。MapReduce是一种计算模型,用以进行大数据量的计算。其中Map对数据集上的独立元素进行指定的操作,生成键-值对形式中间结果。Reduce则对中间结果中相同“键”的所有“值”进行规约...
Mapper类——hadoop
热门推荐
孤竹的博客
05-25 1万+
1、Map是一些单个任务。Mapper类就是实现Map任务的类。haddop提供了一个抽象的Mapper基类,程序员需要继承这个基类,并实现其中相关的接口函数 一个示例Mapper类的定义如下: public static class MyMapper extend Mapper ①Mapper类是Hadoop提供的一个抽象类,程序员可以继承这个基类并实现其中的相关接口函数。它位于 o
Spark入门-聚合算子详解
汪巡的博客
09-10 1924
Overview Spark中常用的算子加起来有几十个,其中针对key的聚合算子有五个,分别是groupBy、groupByKey、reduceByKey、aggregateByKey和flodByKey,有几个底层其实调用的都是一个方法,只不过传入的参数不一样产生了这几个算子,但我仍打算分开来详解每个算子的计算过程,加深理解。 这几个聚合算子要解决的问题都是将所需操作的RDD中的key值相同的value值聚合在一起然后两两做计算也就是聚合最终得出一个结果,这里有三个点需要注意,一是两两聚合的初始值,是
Hadoop MapReduce概述讲解
codeSmart的博客
06-12 282
Hadoop MapReduce概述讲解MapReduce定义MapReduce优点易于编程良好的扩展性 MapReduce定义 MapReduce是一个分布式运算程序的编程框架,是基于Hadoop的数据分析计算的核心框架。 MapReduce处理过程分为两个阶段:Map阶段和Reduce阶段 Map负责把一个任务分解成多个任务 Reduce负责把分解后多任务处理的结果汇总 MapReduce优点 易于编程 简单实现一些接口,
MapReduce之自定义Key和Value
tangshiweibbs的专栏
05-07 1805
package com.uplooking.bigdata.mr.writablez; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.T
hadoop mapper从源码开始 详解
bitcarmanlee的博客
05-15 7898
hadoopmapreduce计算框架中,最重要的两个部分自然就是mapper跟reducer了。写了这么久的MR,一直没有机会研究源码,也挺遗憾的。趁着这波有一些要深入了解的需求,加上周末的一些时间,仔细阅读了一下mapper相关源码,有了自己的一些小小心得,权当笔记。写得不好或者有不对的地方,请童鞋们指出1.mapper源码/** * Licensed to the Apache Softw
MapReduce shuffle过程详解
weixin_42265234的博客
10-25 1560
一、MapReduce计算模型 我们知道MapReduce计算模型主要由三个阶段构成:Map、shuffle、Reduce。 Map是映射,负责数据的过滤分法,将原始数据转化为键值对;Reduce是合并,将具有相同key值的value进行处理后再输出新的键值对作为最终结果。为了让Reduce可以并行处理Map的结果,必须对Map的输出进行一定的排序与分割,然后再交给对应的Reduce,而这个将Map输出进行进一...
hadoop-mapreduce-app
05-16
Hadoop-MapReduce作为分布式计算框架的代表,已经成为了处理大数据的首选方案。Hadoop-MapReduce主要由两个部分组成,一个是Hadoop分布式存储系统,它是一个可扩展的、高可靠的存储系统,另一个是MapReduce计算框架...

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 用最小二乘法OLS做回归,并解读结果 38409
  • SVM(核函数、高斯核函数RBF) 17363
  • Chrome配置Proxy代理 15208
  • python中的类class: 继承、覆盖、重写、重载、扩展、多态、封装 12088
  • 【转】什么是预研?产品预研与技术预研 10967

分类专栏

  • 神经网络和深度学习 17篇
  • Embedding 2篇
  • 读书分享 1篇
  • 认知方法 40篇
  • 人生经历思考反思 22篇
  • 推荐系统 38篇
  • 工具安装和使用 14篇
  • NLP自然语言处理 4篇
  • Spark权威指南 33篇
  • Scala开发日志 28篇
  • 一个小目标 3篇
  • 因果模型 3篇
  • 面试刷题 6篇
  • 特征工程 22篇
  • 语音识别
  • 学习资料汇总 8篇
  • 最优化算法 4篇
  • Linux 1篇
  • 广告和影响力传播 3篇
  • AB测试 2篇
  • Hive & Hadoop 21篇
  • python 39篇
  • spark 74篇
  • Tensorflow&Keras 17篇
  • 算法模型分析方法 21篇
  • 机器学习 81篇

最新评论

  • 学习TensorFlow的过程和经验总结

    weixin_38790181: [恰好我想起了2020年年初的时候我让同学给我推荐过一本他学习深度学习用过的比较好的书。] 请问是哪本书?谢谢!

  • lateral view json_tuple函数解析非结构化的json数据类型

    bigdata_han: 使用lateral view json_tuple时传入不存在的key,也不会报错吧

  • 在使用nohup命令后台训练pytorch模型时,关闭ssh窗口导致的训练任务失败解决方法

    kill all bad moods: 大佬,我在Windows下用的xshell连接服务器,应该如何修改呢

  • pyspark使用XGboost训练模型实例

    John Dang: 多谢朋友指点!GitHub那篇文章解决了我的大问题

  • 【转】基于知识图谱的推荐系统(KGRS)综述

    mlm5678: 话说大佬啥方向的表情包

大家在看

  • JSON及Python操作JSON相关 596
  • java常用对象的判空写法 204
  • 【docker】centos7配置docker镜像阿里云加速 84
  • 深度学习各算法的优缺点和适用场景!!纯干货,建议收藏。(上篇)
  • 121文章解读与程序——EI\CSCD\北大核心《计及动态电价的电动汽车充放电优化调度》已提供下载资源 310

最新文章

  • sklearn.preprocess.LabelEncoder出现从未见过值的处理方法
  • 3-pytorch数据迁移代码实例:特征提取和微调(基于卷积神经网络retnet18)
  • 2-Embedding例子:简单NN网络、迁移学习例子(glove语料预训练)
2024年9篇
2023年21篇
2022年45篇
2021年117篇
2020年104篇
2019年19篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

深圳SEO优化公司烟台外贸网站制作莆田关键词按天扣费推荐潍坊网页设计报价长葛百搜标王价格巢湖百度爱采购公司坪地关键词按天收费公司迪庆网站优化按天收费推荐昆明SEO按天计费推荐来宾seo价格绍兴设计网站哪家好九江网络营销报价茂名网络营销价格钦州建站多少钱松岗如何制作网站推荐金华品牌网站设计报价大浪关键词按天计费哪家好同乐模板网站建设公司西乡关键词按天收费宝鸡模板制作东营网页制作哪家好景德镇关键词排名报价石家庄高端网站设计哪家好武威百搜标王公司威海网站推广方案哪家好长沙推广网站推荐天门百搜标王报价莆田SEO按天扣费公司哈密网站关键词优化多少钱营口网络营销多少钱焦作网站搭建报价歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化