问题
我正在尝试规范化非常大的原始、非规范化csv表中的列。列值是短字符串(10-100字节)。我试图找到一个比我目前的方法更快的解决方案。
示例
输入.csv
john,london
jean,paris
bill,london
转换为以下文件:
输入.normalized.csv
1,1
2,2
3,1
输入.col1.csv
1,john
2,jean
3,bill
输入.col2.csv
1,london
2,paris
我目前有两种方法来规范化这些数据集。
当前方法
内存中的单通道
单通道方法,存储列 values -> normalized_id
关联数组中的值(在我的例子中是java hashmap)。这将在某个时候耗尽内存,但当它可以在内存中存储所有内容时,速度很快。降低内存使用率的一个简单方法是对每列执行一次传递。
多程排序
一种基于排序的多路径方法。列值会附加它们的行号,然后进行排序(以内存高效的合并排序方式)。例如,列值 london,paris,london
附上行号,然后进行排序: london;1,london;3,paris;2
.
我现在可以有一个“unique value counter”,只需将每个值与前一个值进行比较(例如london==london,所以不要递增unique value counter)。最后,我有一对 unique_id,linenum
我可以按行号排序以重建规范化列的对。然后可以在一次传递中合并列。
这种方法可以在非常有限的内存中完成,具体取决于所应用的排序算法的内存使用情况。好消息是,这种方法很容易在hadoop之类的东西中实现,利用它的分布式排序步骤。
我的问题
与单通道方法(或每列单通道方法)相比,多通道方法的速度非常慢。所以我想知道优化这种方法的最佳方法是什么,或者是否有人可以提出替代方法?
我想我正在寻找某种类型的(分布式)键值存储,它具有尽可能低的内存使用率。
在我看来,使用trove将是使用java hashmaps的一个好的、简单的替代方法,但是我希望有一些东西可以为我处理密钥的分发。
redis可能是一个不错的选择,但我对它的每个键值对的内存使用率印象不深。
1条答案
按热度按时间k2fxgqgv1#
你知道输入列的大致数量级吗?如果是这样,您不需要保留原始输入文件顺序吗?然后可以使用足够大的哈希函数来避免输入键的冲突。
如果您坚持使用密集的连续密钥空间,那么您已经介绍了两个主要的选择。你当然可以试试redis,我见过它被用于百万个键值对中的10s,但它可能不会扩展到这个范围之外。你也可以试试memcached。它的内存开销可能比redis略低,但我肯定会尝试两者,因为它们在这个特定的用途上非常相似。实际上,您并不需要redis的高级数据结构。
如果您需要的键值超过了您在一台机器上存储在内存中的数量,您可以使用bdb或kyoto cabinet之类的方法,但最终这一步将成为处理的瓶颈。另一个危险信号是,如果你能在一台机器上在内存中容纳一整列,那么你为什么要使用hadoop呢?
老实说,依赖密集有序主键是nosqldb中首先抛出的事情之一,因为它假设一个协调的主密钥。如果你能允许一些间隙,那么你可以做一些类似于向量时钟的事情。
最后一种选择是使用map reduce作业按键收集所有重复值,然后使用一些外部事务数据库计数器分配唯一值。但是,map reduce作业本质上是一种多过程方法,因此可能更糟。主要的优点是您将获得一些io并行性(尽管id分配仍然是一个串行事务。)