我已经开始使用以JSON格式到达的大型数据集。不幸的是,提供数据馈送的服务提供了非常重要数量的重复记录。从好的方面来说,每条记录都有一个唯一的Id号,存储为64位正整数(Java long )。
数据每周到达一次,每次传递的记录大约为10M。我需要从当前交货中排除重复项以及之前批次中的记录。
攻击重复数据问题的强力方法是将Id编号推入Java Set 。由于 Set 界面需要唯一性,因此插入期间的失败将指示重复。
问题是:在导入记录时,是否有更好的方法可以查找重复的长?
我正在使用Hadoop挖掘数据,所以如果有一个很好的方法可以使用Hadoop来删除那些可能是奖励的记录。
答案 0 :(得分:5)
您是否可以创建MapReduce任务,其中地图输出具有唯一ID号的密钥?这样,在reduce任务中,您将传递具有该ID号的所有值的迭代器。仅输出第一个值,减少的输出将没有重复。
答案 1 :(得分:1)
让我看看。每个java.lang.Long
占用24个字节。每个HashMap$Entry
也需要24个字节,HashMap
的数组需要4个字节。所以你有52 * 10M = 512M的堆存储空间用于地图。这是一周的10M记录。
如果您使用的是64位系统,则可以将堆大小设置为5 GB,并查看获得的内容。
应该有java.util.Set
的其他实现,每个条目只消耗大约16个字节,因此您可以处理三倍于java.util.HashSet
的数据。我自己写了一篇,但我无法分享。您可以尝试使用GNU Trove。
答案 2 :(得分:0)
您必须在HDFS中保留唯一ID列表,并在每次批量加载后重建它。
由于您案例中的基数非常大(您可以在一年内获得> 1B唯一记录),因此需要将您的唯一ID列表拆分为多个部分,例如N.分区算法是特定于域的。一般方法是将ID转换为长哈希字符串(16个字节就可以)并创建2 ^ k个桶:
对于k = 8,例如:
bucket#1包含哈希值以0开头的所有ID bucket#2包含哈希值以1开头的所有ID ... bucket#256包含哈希值以255开头的所有ID
在每个新批处理中,您首先运行重复数据删除作业:映射读取记录,记录ID,对其进行哈希并输出Key = bucket#(在我们的例子中为0..255)和Value = ID。每个reducer接收给定存储桶的所有IDS。 Reducer将系统中已知的给定存储桶的所有唯一ID加载到内部Set中,并使用此内部Set检查所有传入记录ID。如果记录具有尚未知道的ID,则更新内部设置并输出记录。
在reducer关闭时,您将内部唯一ID集输出回HDFS。
通过将整组ID分成多个桶,您可以创建可以很好地扩展的解决方案。