4

假设我有两个键值数据集——数据集 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
4

3 回答 3

3

根据文档,MapReduce 框架包括以下步骤

  1. 地图
  2. 排序/分区
  3. 结合(可选)
  4. 减少

您已经描述了一种执行连接的方法:将所有 Set A 加载到每个 Mapper 的内存中。你是对的,这是低效的。

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

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

于 2012-09-13T00:34:38.670 回答
3

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

于 2012-09-13T18:30:44.513 回答
2

Cloudera 的这个视频教程很好地描述了如何通过 MapReduce 进行大规模连接,从大约 12 分钟开始。
以下是他列出的基本步骤,用于使用伪代码将文件 B 中的记录连接到密钥 K 上的文件 A 中的记录。如果这里有任何不清楚的地方,我建议您观看视频,因为他的解释比我做得更好。

在您的映射器中:

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 值。您还可以扩展它以实现完全内部连接,或者将两个文件全部写出以直接进行数据库存储,但是一旦你得到这个工作,这些都是非常微不足道的修改。

于 2012-09-13T17:50:51.707 回答