【问题标题】:Stable hash function to partition a set of number into m buckets to make the m bucket size balanced as possible稳定的散列函数,将一组数字划分为 m 个桶,使 m 个桶的大小尽可能平衡
【发布时间】:2021-09-30 08:06:44
【问题描述】:

当前算法是:

            d = {}
            for doc_id in request:
                    md5 = hashlib.md5()
                    md5.update(str(doc_id) + "_" +  request_id)
                    digest = md5.hexdigest()
                    k = int(digest, 16)
                    a = (k%720)/(720/16)
                    if a not in d:
                            d[a]=1
                    else:
                            d[a]=d[a]+1

请求大小在 (800, 1000) 范围内

我计算了1000次算法,

max(d[i])-min(d[j]) 是 20+ 的平均值

有没有办法让16个桶的大小尽可能平衡

【问题讨论】:

  • a = (k%720)/(720/16) 背后的想法是什么?为什么不简单地a = k % number_of_buckets?如果2**128(一个MD5哈希的最大值,加1)不能被number_of_buckets整除,就会产生一些偏差,但是2**128很大,所以偏差很小。
  • @Thomas a = k % number_of_buckets。没有区别,
  • 我知道,但这不是我的问题。 :)

标签: algorithm hash partition data-partitioning


【解决方案1】:

我不认为通过改变哈希函数可以做得更好只是。 MD5 不再是最先进的,但对于这样的事情来说,它仍然足够随机。

让我们看看一些概率论,看看如果我们使用一个完全统一的哈希函数,它会变得多么好。如果您将 1000 个元素完全随机放入 16 个桶中,则您预计每个桶平均有 1000 / 16 = 62.5 个元素。但是这个数字的差异是什么?

要计算这一点,请考虑单个存储桶和完全随机的存储桶分配。将特定元素分配给这个桶的概率是 1/16,我们有 1000 个元素。所以我们的分布相当于一个binomial distribution,n = 1000,p = 1/16。

该分布的方差由 n * p * (1 - p) ≈ 59 给出。标准偏差为 sqrt(variance) ≈ 8,这使您可以了解与平均值的预期偏差的数量级.二项分布不是正态分布,但对于这种大小的数字,它非常接近,所以we would expect 大约 68% 的桶大小在平均值的 8 以内。根据我值得信赖的 TI-83 计算器,预计在 0.6% 的情况下会出现与平均值偏差超过 20 的值,因此通过 1000 次试验,您很可能会看到其中的一些。


如果不平衡确实导致问题,您可以更改分区代码以使用某种类型的open addressing。一种简单的方法是使用目标存储桶加一(模存储桶计数),直到找到一个不够满的存储桶。

请注意,之后您将很难再次找到该元素,除非您限制此桶跳跃,例如最多执行 3 次。这使得查找更加昂贵,因为您需要在 4 个存储桶中查找元素,而不仅仅是 1 个。

如果您以后不需要查找元素,则可以简单地将它们分配给最不满的桶;那么根本不需要散列。

【讨论】:

  • 目前我需要找到一个稳定的算法来将相同的doc_id放入同一个bucket中。
【解决方案2】:

正如 Thomas 所解释的,即使是加密强度哈希函数——有效地产生伪随机值(但对于每个密钥都是稳定的)——也会表现出相当大的差异。如果你想改进它,你有几个选择:

  • #elements-per-bucket 方差存在一些差异,因此您可以执行一些操作,例如将 i 从 1 循环到 1000;将"_" + i 附加到您的键,并查看哪个循环迭代产生了最小的max(d[i])- min(d[j]) 值;只需记住在查找时添加相同的_i

    • 我的公司在早上打包密钥以供全天使用时会做类似的事情,以最大限度地减少最坏情况下的冲突链长度,从而最大限度地减少我们静态分配的二维数组的内存使用;基本上[#buckets][max-collisions];我们更改散列函数使用的随机数数据而不是键,但两者皆有可能
  • 利用一些关于密钥的知识(如果它们可以接受的话) - 这是一种魔法,但是例如 - 往往会增加但可能偶尔会出现间隙的数字通常会更好地映射到具有身份哈希的存储桶上(即 h(k) == k)而不是加密强度哈希;当您有两个部分密钥 - doc_idrequest_id - 您需要了解两者的典型值/模式,以便有机会使用比加密分布更均匀的哈希函数并尝试组合它们变得同样密集但均匀包装

【讨论】:

    【解决方案3】:

    正如其他答案所指出的那样,您看到的行为是随机将球放入垃圾箱并查看装载最多和装载最少的桶的行为的结果。即使是纯随机分布,您也希望在这些桶之间看到一个不错的分布。

    另一种方法是使用不同的策略将项目分配到存储桶中。想象一下,您有 两个 散列函数,而不仅仅是一个。如果您对每个项目进行哈希处理并将其放入它所哈希到的两个存储桶中负载较小的一个,那么与仅对每个项目进行一次哈希处理相比,所得分布明显更接近于均匀分布。 (这有时被称为“两种选择的力量”)。在此之外添加更多哈希函数确实会进一步降低传播,但程度不如从一个哈希函数到两个哈希函数。

    【讨论】:

      猜你喜欢
      • 2018-12-28
      • 1970-01-01
      • 2015-01-21
      • 1970-01-01
      • 2015-12-09
      • 2020-04-04
      • 2016-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多