4

我已经开始处理一个以 JSON 格式到达的大型数据集。不幸的是,提供数据馈送的服务提供了大量的重复记录。从好的方面来说,每条记录都有一个唯一的 ID 号,存储为 64 位正整数(Java long)。

数据每周到达一次,每次交付大约有 1000 万条记录。我需要从当前交付以及以前批次中的记录中排除重复项。

解决重复数据删除问题的蛮力方法是将 Id 编号推入 Java Set中。由于Set接口要求唯一性,因此插入过程中的失败将表明重复。

问题是:只要我导入记录,是否有更好的方法来查找重复项?

我正在使用 Hadoop 来挖掘数据,所以如果有一种使用 Hadoop 对记录进行重复数据删除的好方法,那将是一个额外的好处。

4

3 回答 3

5

您能否创建一个 MapReduce 任务,其中地图输出具有唯一 ID 号的键?这样,在您的 reduce 任务中,您将获得一个包含具有该 ID 号的所有值的迭代器。仅输出第一个值,您减少的输出将没有重复。

于 2011-09-13T00:22:08.733 回答
1

让我看看。每个java.lang.Long占用 24 个字节。每个HashMap$Entry也需要 24 个字节,而数组HashMap需要 4 个字节。所以你有 52 * 10M = 512M 的地图堆存储空间。不过,这是针对一周的 1000 万条记录。

如果您在 64 位系统上,您可以将堆大小设置为 5 GB,然后看看您能走多远。

应该有其他的 a 实现java.util.Set每个条目只消耗大约 16 个字节,因此您可以处理 3 倍于 a 的数据java.util.HashSet。我自己写了一个,但我不能分享它。你可以试试 GNU Trove。

于 2011-09-12T19:58:52.410 回答
0

您必须在 HDFS 中保留唯一 ID 列表,并在每次批量加载后重建它。

由于您的案例中的基数非常大(您可以预期一年内有 > 1B 个唯一记录),您的唯一 ID 列表需要分成多个部分,比如 N。分区算法是特定于域的。一般的做法是将 ID 转换成长哈希字符串(16 字节即可)并创建 2^k 个桶:

对于 k =8,例如:

bucket #1 包含所有哈希值以 0 开头的 ID bucket #2 包含所有哈希值以 1 开头的 ID ... bucket #256 包含所有哈希值以 255 开头的 ID

在您收到的每个新批次上,首先运行重复数据删除作业:Map 读取记录,获取记录 ID,对其进行哈希处理并输出 Key=bucket#(在我们的示例中为 0..255)和 Value = ID。每个 reducer 接收给定存储桶的所有 IDS。Reducer 将系统中已知的给定存储桶的所有唯一 ID 加载到内部 Set 中,并使用此内部 Set 检查所有传入记录 ID。如果记录具有未知的 ID,则更新内部 Set 并输出记录。

在 reducer 关闭时,您将内部唯一 ID 集输出回 HDFS。

通过将整个 ID 集拆分为多个存储桶,您可以创建可扩展的解决方案。

于 2012-12-10T22:10:04.353 回答