Map Reduce编程中reducer中的shuffle和sorting阶段的目的是啥?

Posted

技术标签:

【中文标题】Map Reduce编程中reducer中的shuffle和sorting阶段的目的是啥?【英文标题】:What is the purpose of shuffling and sorting phase in the reducer in Map Reduce Programming?Map Reduce编程中reducer中的shuffle和sorting阶段的目的是什么? 【发布时间】:2014-04-04 04:45:26 【问题描述】:

在 Map Reduce 编程中,reduce 阶段包含 shuffle、sorting 和 reduce 作为其子部分。排序是一件昂贵的事情。

Map Reduce编程中reducer中shuffle和sort阶段的目的是什么?

【问题讨论】:

我一直认为这是必要的,因为 mapper 的输出是 reducer 的输入,所以它根据 keyspace 进行排序,然后为每个 reducer 输入拆分成桶。 【参考方案1】:

首先shuffling是将数据从mapper传输到reducer的过程,所以我认为reducer显然是有必要的,否则他们将无法有任何输入(或来自每个映射器的输入)。洗牌甚至可以在地图阶段完成之前开始,以节省一些时间。这就是为什么当地图状态还不是 100% 时,您会看到大于 0%(但小于 33%)的 reduce 状态。

Sorting 为 reducer 节省了时间,帮助它轻松区分何时应该开始新的 reduce 任务。它只是启动一个新的 reduce 任务,当排序后的输入数据中的下一个 key 与上一个不同时,简单地说。每个reduce任务都接受一个键值对列表,但它必须调用reduce()方法,该方法接受一个键列表(值)输入,因此它必须按键对值进行分组。如果输入数据在 map 阶段(本地)预先排序并在 reduce 阶段简单地合并排序(因为 reducer 从许多 mapper 获取数据),那么这样做很容易。

您在其中一个答案中提到的Partitioning 是一个不同的过程。它确定将在哪个reducer 中发送(key, value) 对,即map 阶段的输出。默认的 Partitioner 对键使用散列来将它们分配给 reduce 任务,但您可以覆盖它并使用您自己的自定义 Partitioner。

Yahoo tutorial (archived) 是这些步骤的重要信息来源。

一个很好的图形表示如下(在该图中,随机播放称为“复制”):

请注意,如果您指定零减速器 (setNumReduceTasks(0)),则根本不会执行 shufflingsorting。然后,MapReduce 作业在 map 阶段停止,并且 map 阶段不包括任何类型的排序(因此即使是 map 阶段也更快)。

更新:由于您正在寻找更官方的东西,您还可以阅读 Tom White 的书“Hadoop:权威指南”。 Here 是您问题的有趣部分。 Tom White 自 2007 年 2 月以来一直是 Apache Hadoop 提交者,并且是 Apache 软件基金会的成员,所以我想这是相当可信和官方的......

【讨论】:

"排序为reducer节省了时间,帮助它轻松区分什么时候应该开始一个新的reduce任务。它只是启动一个新的reduce任务,当排序后的输入数据中的下一个key与前一个不同时, 简而言之。”我不明白这部分。 Mapper 使用分区器将溢出划分为本地分区,然后将每个分区发送到 reduce。排序在这里有什么帮助? @MaxNevermind 如果您有 x 个 reduce 任务(分区),这并不意味着您最终会调用 x 次 reduce() 方法。它将为每个不同的键调用一次。所以一个reduce任务可以多次调用reduce()方法。 "它将为每个不同的键调用一次" 为什么? Mapper 以任何它想要的方式形成分区(不必为每个不同的 key 一个分区),然后每个分区都进入 reducer,是不是错了? @MaxNevermind Mapper 输出键和值,它不形成分区。分区由用户定义的 reduce 任务的数量和 Partitioner 实现定义。所有具有相同键的 Mapper 的输出都将转到相同的 reduce() 方法。这是无法改变的。但是可以改变的是其他键(如果有的话)将被放置在同一分区中,因此将由同一任务处理。 reduce 任务可以多次调用 reduce() 函数,但每个键只能调用一次。 好的,我想我明白了。我的问题是我忘记了 reduce 将值列表作为参数,而不仅仅是一个键值对。我认为你应该在你的回答中详细说明:“每个reduce任务都需要一个键值对列表,但它必须调用reduce方法,它需要一个key-List,所以它必须按键对值进行分组,这很容易如果输入数据在映射器阶段预先排序"【参考方案2】:

让我们回顾一下 Mapreduce 程序的关键阶段。

映射阶段由映射器完成。 Mappers 在未排序的输入键/值对上运行。每个映射器为每个输入键/值对发出零个、一个或多个输出键/值对。

组合阶段由组合器完成。 combiner 应该将键/值对与相同的键组合起来。每个组合器可以运行零次、一次或多次。

洗牌和排序阶段由框架完成。来自所有映射器的数据按 key 分组,在 reducer 之间拆分并按 key 排序。每个 reducer 获取与同一个键关联的所有值。程序员可以提供用于排序的自定义比较函数和用于数据拆分的 partitioner

partitioner 决定哪个reducer 将获得特定的键值对。

reducer 获得排序后的 key/[values list] 对,按 key 排序。值列表包含映射器生成的具有相同键的所有值。每个reducer 为每个输入键/值对发出零个、一个或多个输出键/值对

看看这个 javacodegeeks article by Maria Jurcovicova 和 mssqltips Datta 的文章以获得更好的理解

下图来自safaribooksonline文章

【讨论】:

我认为图像中有错字(我意识到只是在这里复制)。我相信 Reducers 和 Output 下的 ie 字符串实际上应该是 is 你能告诉我为什么映射器需要偏移量,因为该偏移量的值将在“值”部分可用吗?【参考方案3】:

我想只是在上面的答案中添加一些缺失的点。这张来自here 的图表清楚地说明了实际情况。

如果我再说一遍真正的目的

拆分:通过将处理负载分布到不同节点(映射器)来改进并行处理,这将节省整体处理时间。

组合:缩小每个映射器的输出。这将节省将数据从一个节点移动到另一个节点所花费的时间。

排序(Shuffle & Sort) 使运行时可以轻松地安排(生成/启动)新的 reducer,在遍历排序的项目列表时,只要当前key 和之前的不一样,它可以产生一个新的 reducer。

【讨论】:

分区步骤会出现在该图中的什么位置?地图之后和合并之前? @Joel 我希望您指的是“拆分”步骤? 不,我的意思是分区步骤,它决定将数据发送到哪个reducer,默认情况下使用简单的哈希模数,经过更多研究,我相信它在组合步骤之后,在随机排序和排序之前. @Joel 我不太清楚你打算描述什么。简而言之,确切的步骤顺序几乎是针对特定问题的。我可以说,在某些情况下,甚至不需要排序。回到您的输入,如果我专门讨论上述简单的字数示例,我真的认为不需要这样的分区来决定减速器。在这里,每个键的产生减少非常简单。但我可以猜到你的观点在某些情况下是有效的。坦率地说,我对此并没有一个明确的概念。 @rahulsharma 整个 map-reduce 系统遵循主从协调。因此,每个节点间的操作都基于此。【参考方案4】:

某些数据处理要求根本不需要排序。 Syncsort 使 Hadoop 中的排序成为可插拔的。 Here 是他们关于排序的一个不错的博客。将数据从 mapper 移动到 reducer 的过程称为 shuffle,查看this 文章了解更多信息。

【讨论】:

【参考方案5】:

我一直认为这是必要的,因为 mapper 的输出是 reducer 的输入,因此它根据 keyspace 进行排序,然后为每个 reducer 输入拆分成桶。您希望确保 Key 的所有相同值最终都在同一个桶中进入减速器,以便它们一起减少。将 K1,V2 和 K1,V4 发送到不同的减速器是没有意义的,因为它们需要放在一起才能被减速。

试图尽可能简单地解释它

【讨论】:

如果我们想将 k1,v1 和 k1,v4 发送到同一个 reducer,我们可以做 shuffle。那么排序的目的是什么? 它进行排序有多种原因,一个原因是,当 MapReduce 作业将所有 KV 对发送到减速器时,如果输入未排序,则必须扫描所有 Mapper 输出以拾取 K1,VX 的每个实例。而如果 Mapper 输出在 K2,VX 被拾取后立即排序,则您知道所有 K1,VX 都已被拾取并且该集合可以发送到减速器进行处理,这样做的好处是您不需要必须等待每个 reducer 准备好才能让每个 reducer 开始 reduce。 同样,当涉及到聚合时,如果你指定你想要聚合所有的 K1,V1,如果减速器的输入在减速器接收到 K2,V2 时立即排序,它知道没有存在更多 K1,V1 实例,因此它可以完成聚合,而如果减速器输入未排序,则必须扫描整个输入以查找 K1,V1 我认为原因是这样的:你将键映射到给定的减速器。因此,一次扫描整个键空间就足以将每个 (k,v) 映射到减速器,这样相同的键就会进入相同的分区。完成排序以获得 (k,v1,v2,v3,v4,...) 将在其上运行 reducer 逻辑。这是hadoop的groupby方式【参考方案6】:

混洗是将来自映射器的中间数据传输到 0,1 或更多减速器的过程。每个 reducer 接收 1 个或多个键及其关联值,具体取决于 reducer 的数量(用于平衡负载)。此外,与每个键关联的值在本地排序。

【讨论】:

【参考方案7】:

由于其大小,分布式数据集通常存储在分区中,每个分区包含一组行。这也提高了地图或过滤器等操作的并行性。 shuffle 是对数据集的任何操作,需要在其分区之间重新分配数据。示例包括按键排序和分组。

对大型数据集进行混洗的常用方法是将执行拆分为 map 和 reduce 阶段。然后数据在 map 和 reduce 任务之间进行混洗。例如,假设我们要对一个有 4 个分区的数据集进行排序,其中每个分区是一组 4 个块。目标是生成另一个有 4 个分区的数据集,但这次是按 key 排序的。

例如,在排序操作中,每个正方形都是一个排序后的子分区,其键位于不同的范围内。然后每个 reduce 任务对相同阴影的子分区进行合并排序。 上图显示了这个过程。最初,未排序的数据集按颜色(蓝色、紫色、绿色、橙色)分组。洗牌的目标是按阴影(从浅到深)重新组合块。这种重组需要全对多的通信:每个映射任务(一个彩色圆圈)为每个阴影生成一个中间输出(一个正方形),这些中间输出被打乱到它们各自的归约任务(一个灰色圆圈)。

文字和图片主要取自here。

【讨论】:

【参考方案8】:

MapReduce 原生只做两件事:排序和(通过排序实现)可扩展的 GroupBy。

MapReduce 上的大多数应用程序和设计模式都是基于这两个操作构建的,它们由 shuffle 和 sort 提供。

【讨论】:

【参考方案9】:

This 是一本好书。希望能帮助到你。就您所关心的排序而言,我认为这是 Map 最后一步中的合并操作。当map操作完成后,需要将结果写入本地磁盘时,会对buffer产生的splits进行multi-merge操作。对于合并操作,提前对每个分区进行排序很有帮助。

【讨论】:

【参考方案10】:

嗯, 在 Mapreduce 中有两个重要的短语,分别叫做 Mapperreducer 都太重要了,但是 Reducer 是必须的。在某些程序中,reducers 是可选的。现在来回答你的问题。 洗牌和排序是 Mapreduce 中的两个重要操作。第一个 Hadoop 框架采用结构化/非结构化数据并将数据分离为 Key、Value。

现在 Mapper 程序将数据分离并排列成要处理的键和值。生成键 2 和值 2 值。该值应按正确顺序处理和重新排列以获得所需的解决方案。现在这个洗牌和排序在您的本地系统中完成(框架负责它)并在流程框架清理本地系统中的数据后在本地系统中处理。 好的

这里我们也使用 combinerpartition 来优化这个 shuffle 和 sort 过程。经过适当的安排,这些键值传递给 Reducer 以获得所需的 Client 输出。最后 Reducer 得到想要的输出。

K1, V1 -> K2, V2(我们会写程序Mapper),-> K2, V'(这里是shuffle and soft data) -> K3, V3 生成输出。 K4,V4。

请注意所有这些步骤只是逻辑操作,不会改变原始数据。

您的问题:在 Map Reduce 编程中,reducer 中的 shuffle 和 sort 阶段的目的是什么?

简答:处理数据以获得所需的输出。 shuffle 是聚合数据,reduce 是得到预期的输出。

【讨论】:

以上是关于Map Reduce编程中reducer中的shuffle和sorting阶段的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章

js高阶函数filter reduce map

js高阶函数filter reduce map

python进阶一(函数式编程)2-3 python中的reduce函数

函数式编程 & Python中的高阶函数map reduce filter 和sorted

Python 函数式编程(map reduce filter sorted)

Python函数式编程——map()reduce()