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

Java 确定唯一值的高效内存分布式方法? 问题,java,sorting,hadoop,redis,key-value,Java,Sorting,Hadoop,Redis,Key Value,我正在尝试规范化非常大的原始、非规范化CSV表中的列。列值是短字符串(10-100字节)。我试图找到一个比我目前的方法更快的解决方案 范例 input.csv john,london jean,paris bill,london 1,1 2,2 3,1 1,john 2,jean 3,bill 1,london 2,paris 已转换为以下文件: input.normalized.csv john,london jean,paris bill,london 1,1 2,2 3,1 1

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

范例 input.csv

john,london
jean,paris
bill,london
1,1
2,2
3,1
1,john
2,jean
3,bill
1,london
2,paris
已转换为以下文件:

input.normalized.csv

john,london
jean,paris
bill,london
1,1
2,2
3,1
1,john
2,jean
3,bill
1,london
2,paris
input.col1.csv

john,london
jean,paris
bill,london
1,1
2,2
3,1
1,john
2,jean
3,bill
1,london
2,paris
input.col2.csv

john,london
jean,paris
bill,london
1,1
2,2
3,1
1,john
2,jean
3,bill
1,london
2,paris
我目前有两种方法来规范这些数据集

当前方法 内存中的单次传递 单通道方法,将列
值->标准化的\u id
值存储在关联数组中(在我的例子中是Java HashMap)。这将在某个时候耗尽内存,但当它可以在内存中存储所有内容时,速度会很快。降低内存使用率的一个简单方法是对每列执行一次传递

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

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

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

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

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

在我看来,使用Trove将是使用Java HashMaps的一个好的、简单的替代方法,但我希望能够为我处理密钥的分发


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

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

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

如果您需要的键值超过了在一台机器上存储在内存中的数量,您可以使用BDB或Kyoto cabinet之类的方法,但这一步最终将成为处理的瓶颈。另一个危险信号是,如果您可以在一台机器上安装内存中的整个列,那么为什么要使用Hadoop

老实说,依赖密集有序主键是NoSQL DB中首先被抛弃的事情之一,因为它假定一个协调的主键。如果你能允许一些间隙,那么你可以做一些类似于向量时钟的事情


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

“Redis可能是一个不错的选择,但我对它的每个键值对的内存使用情况印象不深。”->这完全取决于您如何使用Redis,imho。Redis除了普通的键值对之外,还内置了对内存非常友好的功能。你可能想了解(即将被释放)和(在那里呆了很久)。只是想一想,我对其他选项的了解还不够,无法将其作为答案发布。如果我需要估计独特记录的数量,Hyperloglog将非常有用。然而,对于我的用例(确定句子的唯一ID),我会冒冲突的风险,这是不可接受的。但是,如果调整正确,Redis的内存效率似乎是合理的,这一点你是对的——我将不得不进一步研究。谢谢:)是的,hyperloglog对确定性的东西没有用处。关于mem用法:也可以阅读redis.conf。您可以按数据类型配置redis应切换到“更多内存/更少cpu”内存结构的行数。除此之外,由于内存指针的大小,32位redis比64位redis的开销更小。但是,当然也有内存最大化。无论如何,我可以部署redis的机器只有8GB内存,所以32位redis可能是最好的选择。我还必须研究一下使用较小的指针会赢得多少:)-如前所述,我希望避免散列,以尽可能保持文件的密度。我也不能在内存中存储整个列。但是,是的,我同意没有简单的出路,正确的解决方案是抛弃连续的有序ID。尽管如此,这是手头工作的一个要求,因此接受这种方法,并专注于使其更容易的工具(redis等)似乎是正确的选择。