【问题标题】:Good Hash function? (32-bit too small, 64-bit too large)好的哈希函数? (32 位太小,64 位太大)
【发布时间】:2023-03-22 14:52:01
【问题描述】:

我需要生成一个哈希值,用于 Java 中数十亿条记录的唯一性。麻烦的是,我只有 16 个数字可以玩。在研究这一点时,我发现了 32 位散列算法,它返回 Java 整数。但这太小了,因为它只有 +/ 20 亿的范围,并且会有更多的记录。我无法使用 64 位哈希,因为这会给我返回太大的数值(+/4 quintillion,或 19 位)。麻烦的是,我正在处理一个强制我使用 16 位静态密钥长度的遗留系统。

建议?我知道没有哈希函数可以保证唯一性,但我需要一个适合这些限制的好函数。

谢谢

【问题讨论】:

  • 您打算如何存储数据?所有记录都会存储在内存中(如果您有足够的内存来执行此操作)还是会实现分页到磁盘或类似的东西?如果您确实使用页面/存储桶,则可以为每个存储桶使用不同的 32 位哈希函数。
  • 您能否澄清一下是 16 位数字(如小于 9999999999999999),还是 16 位数字(如 16 个字母数字字符)?您可以将数字另存为数字以外的数字(例如十六进制或基数 36)吗?
  • Goldy locks 说“48 位刚刚好”。我找的不是很多,但是快速的谷歌搜索给出了一些其他的点击,所以可能存在。
  • 而且,不是散列,而是自动增加的主键呢?
  • 您搜索数字的正确单词不是numeric,而是decimal

标签: java hash md5 apache-commons uniqueidentifier


【解决方案1】:

如果您生成的哈希太大,您可以使用您的最大键空间对其进行修改以使其适合。

myhash = hash64bitvalue % 10^16

【讨论】:

  • 你得到哈希冲突的机会很大,正如你所说的,它必须是独一无二的。
  • @Martjin:“你得到哈希碰撞的机会很大” - 我认为不是,这不是哈希的工作方式;键空间中的真正散列与较小键空间中的散列一样好。
  • @Andrew:我不这么认为:极端例子:hash1 = 40000; hash2 = 20000,但我们限制为 2 个字节: hash1_2byte = hash1 % 4; hash2_2byte = hash2 % 4;现在它们是一样的。
  • @Andrew 你能提供一些参考吗?当你向哈希函数添加一个 mod 时,结果实际上不会是一个新的哈希函数吗?我们如何证明这个函数总是和原来的一样“好”?
  • 好的。这个python测试正确吗? pastebin.com/qymjQEV9 它打印“88266 与散列 3775075157 碰撞”(int 到字符串的转换让我感到困惑,但我现在没有足够的时间看)。 Edit2:我刚刚注意到你写了“更多的碰撞”,所以你说碰撞仍然可能吗?因为这就是我一直以来的想法
【解决方案2】:

如果限制为 16 位十进制数字,则密钥空间包含 10^16 个值。 即使您找到了在您的数据集上提供均匀分布的哈希,由于Birthday Paradox,您将有 50% 的机会在 ~10^8 项数据上发生冲突,这比您的数十亿条记录少一个数量级.

这意味着您不能单独使用任何类型的哈希并依赖唯一性。

一个简单的解决方案是改用全局计数器。如果全局计数器不可行,则可以使用具有预分配范围的计数器。例如,6个最高有效数字表示固定数据源索引,10个最低有效数字包含该数据源维护的单调计数器。

【讨论】:

  • 已经考虑过全局计数器,但试图避免它。这将是一个分布式应用程序,除了使用 MySql 序列(我目前正在这样做)或类似的东西之外,我不确定我是否会跟踪序列。
  • @Doug Houck - 不幸的是,没有办法绕过数学......除非您在数据本身中有一些数据源独有的东西,否则如果没有类似的东西,您将无法保证唯一性一个全局计数器。
【解决方案3】:

所以你的限制是 53 位?

据我所知,哈希码中的位序数不会影响其值(位的顺序和值完全相互独立)。因此,您可以获得 64 位哈希函数并仅使用其中的最后 53 位。您必须为此使用二进制运算( hash64 & (1

【讨论】:

    【解决方案4】:

    您不必以人类可读的形式(如您所说的十六进制)存储哈希值。只需将 64 位长数据类型(由 64 位哈希函数生成)存储在您的数据库中,它只有 8 个字节。而不是你被吓跑的 19 个字节。

    如果这不是解决方案,请改进旧系统。


    编辑:等等!

    64 位:264 =

    18446744073709551616
    

    16 个十六进制数字:1616 =

    18446744073709551616
    

    完全合身!因此,对您的 64 位散列进行十六进制表示,就可以了。

    【讨论】:

      【解决方案5】:

      如果您可以保存 16 个字母数字字符,那么您可以使用十六进制表示并将 16^16 位打包成 16 个字符。 16^16 是 2^64。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-13
        • 1970-01-01
        • 2013-12-11
        • 2011-02-05
        • 1970-01-01
        相关资源
        最近更新 更多