【问题标题】:construct a unique number for a string in java在java中为字符串构造一个唯一的数字
【发布时间】:2010-06-14 13:11:32
【问题描述】:

我们需要在一个文件中读取/写入超过 1000 万个字符串。此外,我们不希望文件中有重复项。由于字符串会在读取后立即刷新到文件中,因此我们不在内存中维护它。

我们不能使用哈希码,因为哈希码中的冲突可能会导致我们错过一个重复的字符串。 我在谷歌搜索中发现了另外两种方法:

1.使用像 MD5 这样的消息摘要算法 - 但计算和存储的成本可能太高。

2.使用校验和算法。 [我不确定这是否会为字符串生成唯一键-请有人确认]

还有其他方法吗? 谢谢。

【问题讨论】:

  • 创建后可以对文件进行排序和去重吗?
  • MD5 实际上是一个校验和算法。不过,两个不同的字符串可能具有相同的校验和。
  • 您不会与真正的哈希码(如 SHA1 或 SHA 变体)发生冲突。 MD5 IS 是一个哈希码。校验和代码用于确保数据没有损坏,它不会帮助您获得唯一性。

标签: java key checksum hashcode message-digest


【解决方案1】:

如果您可以接受微小的碰撞风险,则可以按照您的建议使用一些哈希函数,例如 MD5,并依赖哈希。

另一种可能具有更大内存占用的替代方法是将已经遇到的字符串存储在trie(一种特殊类型的树)中。


更新:另一种选择是使用Bloom filter。然而,这仍然依赖于散列,但可以调整为具有任意小的冲突概率。

【讨论】:

  • 为每个值添加冲突列表是什么意思?
  • trie 一棵树,一棵前缀树
  • @abhin4v。对不起。愚蠢的想法。 @unbeli。你当然是对的。已更新。
  • +1 表示特里。此外,我不认为碰撞列表是一个坏主意,但他们已经表示他们不想将整个事情保留在内存中。
  • 是的。这就是我意识到的,以及为什么在短时间内删除了这个建议:-),我认为只有发生冲突的字符串必须被存储,但显然所有的字符串都必须被存储。 (-:
【解决方案2】:

在内存中存储 1000 万个字符串确实很多,所以我理解立即将其写入文件而不是存储在例如文件中的原因。首先是TreeSet<String>,但是您想在哪里存储要比较的 1000 万个唯一数字键?当您想保留它 uniquenumerical (其基数/基数比字母小得多)时,您不能使键短于字符串本身,所以你不会保存任何内存。或者可能最高使用 GZIP 等数据压缩,但这只会增加很多开销。 MD5 也不合适,因为两个不同的字符串可以产生相同的哈希值。

我真的认为没有比使用像样的 RDBMS(SQL 数据库)更好的解决方案了,其中您将列设置为 UNIQUE 并相应地处理约束违规。 RDBMS 针对此类任务进行了高度优化。

如果您真的不能考虑数据库,那么您需要在写入/刷新之前重新读取文件以获取任何现有条目。也许不是很快,但肯定是内存效率。

【讨论】:

  • 实际上我们认为我们是否可以生成一个唯一的编号。然后我们可以使用位图向量将字符串存储在内存中以避免重复
  • 这仍然不会比使用TreeSet<String> 提高内存效率。
【解决方案3】:

没有办法创建一个函数来为一个比该字符串短的字符串生成一个唯一键。
有一些数据结构可以解决您的任务。如果您的数据足够大,B-tree 可能适合。根据您输入的性质,可能会有更有效的方法。

【讨论】:

    【解决方案4】:

    可靠地删除重复文件与对文件进行排序一样困难。正如另一个答案所表明的那样,如果不将每个字符串的完整副本保存在内存中,就无法保证精确检测重复项,这似乎正是您要避免的。

    您可以保留哈希码的内存或磁盘索引,并使用它们从文件存储中检索实际字符串以进行比较,但这实际上会复制数据库能够为您做的事情。

    另一种方法是在文件完成后对其进行后处理。 UNIX 排序命令非常适合处理大文件 (How could the UNIX sort command sort a very large file?),所以我希望标准 UNIX 命令行方法能够合理地工作:

        sort my-file-of-strings.txt | uniq > my-filtered-file-of-strings.txt
    

    (请注意,在传递给 uniq 以删除重复文件之前,必须先对文件进行排序)。

    如果您没有这些工具(或等效工具)可用,那么您可以随时尝试自己实现一些外部合并排序的变体。

    【讨论】:

    • 我喜欢后期处理方法。让我看看是否可以找到适用于 windows 框的东西。
    • sort -u 可以自行完成。可能有适用于 Windows 的 GNU 版本的 sort....是的:gnuwin32.sourceforge.net/packages/coreutils.htm
    【解决方案5】:

    如果字符串来自一个固定的可能字符串池 (N),那么您可以使用 minimal perfect hashing 创建一个数组 0...N-1。由完美哈希函数确定的槽中的零表示该字符串到目前为止还没有被看到。

    否则,在大量内存之外唯一有效的正确方法是,目前建议的解决方案是在决定将字符串写入文件之前重新读取文件。

    您可以通过文件的内存映射部分尽可能高效地做到这一点。

    【讨论】:

      【解决方案6】:

      我真的认为最好的解决方案是 - 正如其他人已经建议的那样 - 使用数据库。

      如果由于某种原因您不能使用数据库,您仍然可以使用哈希码。肯定会有碰撞。只需添加一些代码,这样当您检测到重复的哈希码时,您的程序就会检查文件以确定它是真正的重复还是冲突。

      【讨论】:

        猜你喜欢
        • 2011-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-04
        • 2017-04-15
        • 2020-11-22
        相关资源
        最近更新 更多