【发布时间】:2011-01-20 23:24:20
【问题描述】:
我们有一个大型数据集要使用多个 reduce 函数进行分析。
所有 reduce 算法都适用于由相同 map 函数生成的相同数据集。每次读取大型数据集成本太高,最好只读取一次并将映射数据传递给多个reduce函数。
我可以用 Hadoop 做到这一点吗?我搜索了示例和 intarweb,但找不到任何解决方案。
【问题讨论】:
我们有一个大型数据集要使用多个 reduce 函数进行分析。
所有 reduce 算法都适用于由相同 map 函数生成的相同数据集。每次读取大型数据集成本太高,最好只读取一次并将映射数据传递给多个reduce函数。
我可以用 Hadoop 做到这一点吗?我搜索了示例和 intarweb,但找不到任何解决方案。
【问题讨论】:
也许一个简单的解决方案是编写一个没有 reduce 函数的作业。因此,您可以将所有映射数据直接传递到作业的输出。您只需将作业的减速器数量设置为零即可。
然后,您将为处理该数据的每个不同 reduce 函数编写一个作业。这意味着将所有映射数据存储在 HDFS 上。
另一种选择可能是将所有 reduce 函数组合到一个 Reducer 中,该 Reducer 输出到多个文件,为每个不同的函数使用不同的输出。 this article for hadoop 0.19 中提到了多个输出。我很确定这个功能在 0.20.1 发布的新 mapreduce API 中被破坏了,但你仍然可以在旧的 mapred API 中使用它。
【讨论】:
您是否希望每个 reducer 都处理完全相同的映射数据?但至少“关键”应该不同,因为它决定了使用哪个减速器。
您可以在 mapper 中多次编写输出,并作为键输出(其中 $i 用于第 i 个 reducer,$key 是您的原始键)。并且您需要添加一个“分区器”以确保这 n 条记录基于 $i 分布在减速器中。然后使用“GroupingComparator”按原始 $key 对记录进行分组。
这是可能的,但不是在一个 MR 中以微不足道的方式。
【讨论】:
context.write() 方法向输出添加一个新键,它将从Mapper 对象传输多个数据。它只解决了文件读取问题,不是吗?
您可以使用复合键。假设您需要两种减速器,“R1”和“R2”。将这些的 id 作为前缀添加到映射器中的 o/p 键。因此,在映射器中,键“K”现在变为“R1:K”或“R2:K”。
然后,在 reducer 中,根据前缀将值传递给 R1 或 R2 的实现。
【讨论】:
我猜你想在一个链中运行不同的减速器。在 hadoop 中,“多个减速器”意味着运行同一个减速器的多个实例。我建议您一次运行一个减速器,为除第一个之外的所有减速器提供微不足道的地图功能。为了最大限度地减少数据传输的时间,您可以使用压缩。
【讨论】:
当然你可以定义多个reducer。对于 Job (Hadoop 0.20),只需添加:
job.setNumReduceTasks(<number>);
但是。您的基础架构必须支持多个减速器,这意味着您必须
当然,您的工作必须符合某些规范。在不知道您到底想做什么的情况下,我只能提供广泛的提示:
job.setPartitionerClass(...)
例如使用随机分区器...您将获得多个输出文件,每个减速器一个。如果你想要一个排序的输出,你必须添加另一个读取所有文件的作业(这次是多个 map-tasks ......)并只用一个 reducer 将它们排序......
看看Combiner-Class,它是local Reducer。这意味着您可以对 map 发出的部分数据在内存中进行聚合(减少)。 非常好的例子是 WordCount-Example。 Map 将每个单词作为键发出,其计数为 1:(word, 1)。组合器从地图中获取部分数据,在本地发出 (, )。 Reducer 的作用完全相同,但现在一些(组合)字数已经 >1。节省带宽。
【讨论】:
我还是不明白你的问题,你可以使用以下顺序:
database-->map-->reduce(根据需要使用 cat 或 None) 然后存储您提取的数据表示。 如果您说它足够小以适合内存,那么将其存储在磁盘上应该不是问题。
另外你对给定问题使用 MapReduce 范式是不正确的,使用单个 map 函数和多个“不同”reduce 函数没有意义,这表明你只是使用 map 将数据传递到不同的机器来做不同的事情事物。您不需要 hadoop 或任何其他特殊架构。
【讨论】: