内存高效的分布式方法来确定唯一值?

时间:2014-04-11 08:59:28

标签: java sorting hadoop redis key-value

问题

我正在尝试在非常大的原始非规范化CSV表中规范化列。列值是短字符串(10-100字节)。我试图找到一种比我目前的方法更快的解决方案。

实施例

input.csv

john,london
jean,paris
bill,london

转换为以下文件:

input.normalized.csv

1,1
2,2
3,1

input.col1.csv

1,john
2,jean
3,bill

input.col2.csv

1,london
2,paris

我目前有两种方法来规范化这些数据集。

当前方法

单次传入内存

单通道方法,将列values -> normalized_id值存储在关联数组中(在我的例子中为Java HashMap)。这会在某些时候耗尽内存,但是当它可以将所有内容存储在内存中时它会很快。降低内存使用量的一种简单方法是每列执行一次传递。

多通道排序

基于排序的多遍方法。列值附加其行号,然后进行排序(以内存高效的合并排序方式)。例如,列值london,paris,london附加了行号,然后进行排序:london;1,london;3,paris;2

我现在可以拥有一个“唯一值计数器”,只需将每个值与之前的值进行比较(例如伦敦==伦敦,所以不要增加唯一值计数器)。最后,我有一对unique_id,linenum对,我可以按行号排序以重建规范化列。然后可以在一次通过中合并列。

这种方法可以在非常有限的内存中完成,具体取决于所应用的排序算法的内存使用情况。好消息是,这种方法很容易在像hadoop这样的方法中实现,利用它的分布式排序步骤。

我的问题

与单通道方法(或单通道每列方法)相比,多通道方法非常缓慢。所以我想知道优化这种方法的最佳方法是什么,或者是否有人可以建议其他方法?

我估计我正在寻找某种类型的(分布式)键值存储,它具有尽可能低的内存使用率。

在我看来,使用Trove将是使用Java HashMaps的一个好的,简单的替代方案,但我想要能够为我处理密钥分发的东西。

Redis可能是一个不错的选择,但我对每个键值对的内存使用量印象不深。

1 个答案:

答案 0 :(得分:1)

您知道输入列的粗略数量级吗?如果是这样,您不需要保留原始输入文件顺序?然后,您可以使用足够大的哈希函数来避免输入键的冲突。

如果您坚持拥有密集的连续密钥空间,那么您已经涵盖了两个主要选择。你当然可以尝试redis,我已经看到它用于数百万的键值对,但它可能不会扩展到那个以上。你也可以试试memcached。它的内存开销可能略低于redis,但我肯定会尝试两者,因为它们对于这种特殊用法非常相似。您实际上并不需要Redis的高级数据结构。

如果你需要更多的键值而不是你可以在一台机器上存储在内存中,那么你可能会回到像BDB或Kyoto橱柜那样的东西,但最终这一步将成为你处理的瓶颈。另一个红色标志是如果你可以在一台机器上将整个列放在内存中,那你为什么要使用Hadoop?

老实说,依赖密集排序的主键是NoSQL DB中首先抛出的东西之一,因为它假设一个单独的协调主。如果你甚至可以允许一些间隙,那么你可以做一些类似于矢量时钟的东西。

最后一种选择是使用map-reduce作业按键收集所有重复值,然后使用某个外部事务DB计数器分配唯一值。但是,map-reduce工作本质上是一种多遍方法,因此可能更糟。主要优点是你将获得一些IO并行性。 (虽然id赋值仍然是一个串行事务。)