使用Hadoop映射两个数据集

时间:2012-09-12 23:21:47

标签: hadoop mapreduce

假设我有两个键值数据集 - 数据集A和B,让我们调用它们。我想用Set B中的数据更新Set A中的所有数据,其中两个匹配键。

因为我正在处理如此大量的数据,所以我正在使用Hadoop来实现MapReduce。我担心的是,为了在A和B之间进行这种密钥匹配,我需要将所有Set A(大量数据)加载到每个映射器实例的内存中。这看起来效率很低。

是否有建议的方法来执行此操作,不需要每次都重复在A中加载的工作?

一些伪代码用于澄清我目前正在做的事情:

Load in Data Set A # This seems like the expensive step to always be doing
Foreach key/value in Data Set B:
   If key is in Data Set A:
      Update Data Seta A

3 个答案:

答案 0 :(得分:3)

根据文档,MapReduce框架包括the following steps

  1. 地图
  2. 排序/隔断
  3. 合并(可选)
  4. 减少
  5. 您已经描述了一种执行连接的方法:在每个Mapper中将所有Set A加载到内存中。你说这是低效率的。

    相反,如果两个集合都按键排序和分区,请注意可以将大型连接划分为任意多个较小的连接。 MapReduce在上面的步骤(2)中按键对每个Mapper的输出进行排序。然后按键对排序的映射输出进行分区,以便为每个Reducer创建一个分区。对于每个唯一键,Reducer将接收来自Set A和Set B的所有值。

    要完成连接,Reducer只需输出密钥和Set B中的更新值(如果存在);否则,从Set A输出密钥和原始值。要区分Set A和Set B中的值,请尝试在Mapper的输出值上设置一个标志。

答案 1 :(得分:3)

到目前为止发布的所有答案都是正确的 - 这应该是Reduce-side join ...但是没有必要重新发明轮子!您是否考虑过此PigHiveCascading?它们都内置了连接,并且进行了相当好的优化。

答案 2 :(得分:2)

Cloudera的

This video tutorial描述了如何通过MapReduce进行大规模加入,从12分钟左右开始。
以下是他将文件B中的记录连接到密钥K上的文件A的记录中的基本步骤,使用伪代码。如果这里的任何内容都不清楚,我建议观看视频,因为他的解释能力比我做得好得多。

在你的Mapper中:

K from file A:
  tag K to identify as Primary Key
  emit <K, value of K>

K from file B:
  tag K to identify as Foreign Key
  emit <K, record>

编写一个将忽略PK / FK标记的Sorter和Grouper,这样您的记录就会被发送到同一个Reducer,无论它们是PK记录还是FK记录,并且组合在一起。

写一个比较器,它将比较PK和FK键并首先发送PK。

此步骤的结果将是具有相同键的所有记录将被发送到同一个Reducer并且在同一组值中将被减少。标记为PK的记录将首先出现,然后是来自B的所有需要​​加入的记录。现在,减速器:

value_of_PK = values[0] // First value is the value of your primary key
for value in values[1:]:
  value.replace(FK,value_of_PK) // Replace the foreign key with the key's value
  emit <key, value>

结果将是文件B,其中所有出现的K都替换为文件A中的K值。您还可以扩展它以实现完整的内部联接,或者将这两个文件全部写出来直接数据库存储,但是一旦你开始工作,这些都是非常简单的修改。