【问题标题】:How to hash a URL quickly如何快速散列 URL
【发布时间】:2011-12-10 05:21:15
【问题描述】:

我有一个独特的情况,我需要即时生成哈希。这是我的情况。这个问题与here 有关。我需要在需要索引的数据库中存储许多 url。 URL 的长度可以超过 2000 个字符。数据库抱怨无法索引超过 900 字节的字符串。我的解决方案是使用 MD5 或 SHA256 对 URL 进行哈希处理。我不确定要使用哪种散列算法。这是我的要求

  • 字符长度最短,冲突最小
  • 需要非常快速。我将在每个页面请求上对引荐网址进行哈希处理
  • 冲突需要最小化,因为我的数据库中可能有数百万个网址

我不担心安全问题。我担心字符长度、速度和碰撞。有人知道这方面的好算法吗?

【问题讨论】:

  • 你对这些 URL 做了什么?
  • Git 使用 SHA1,它比简单的 url 散列更多的数据。我会选择 SHA1,你真的不需要 SHA2。
  • url 将存储在数据库中,没有索引。我将使用 has 值来搜索给定的 url。但该网址将用于在给定网页上生成链接。
  • “最短的字符长度,最小的冲突”——作为一个要求,这并没有什么意义。假设一个“完美”的散列函数,碰撞的概率将与散列长度成反比。您需要将哈希长度和您期望在数据库中拥有多少个 URL 插入生日悖论公式,以获得碰撞概率并判断这是否“足够低”。
  • 您说您需要快速,但听起来您正在获取网页。任何网络往返都将比散列短字符串慢几个数量级。

标签: c# algorithm c#-4.0 hash


【解决方案1】:

在您的情况下,我不会使用任何加密哈希函数(即 MD5、SHA),因为它们在设计时考虑到了安全性:他们主要希望尽可能难以找到两个不同的字符串相同的哈希。我认为在你的情况下这不会是一个问题。 (当然,随机冲突的可能性是散列所固有的)

强烈不建议使用String.GetHashCode(),因为它的实现是未知的,而且 MSDN 说它可能在不同版本的框架之间有所不同。甚至 x86 和 x64 版本之间的结果也可能不同。因此,当您尝试使用更新(或不同)版本的 .NET 框架访问同一数据库时,您会遇到麻烦。

我在 Wikipedia (here) 上找到了 hashCode 的 Java 实现算法,它似乎很容易实现。即使是简单的实现也会比 MD5 或 SHA imo 的实现更快。您还可以使用long 值来降低冲突的可能性。

还有一个对.NET GetHashCode 实现here 的简短分析(不是算法本身,而是一些实现细节),我猜你也可以使用这个。 (或者尝试以类似的方式实现Java版本...)

【讨论】:

    【解决方案2】:

    一个快速的:

    URLString.GetHashCode().ToString("x")
    

    【讨论】:

      【解决方案3】:

      虽然 MD5 和 SHA1 都已被证明在碰撞预防必不可少的情况下无效,但我怀疑对于您的应用程序来说,两者都足够了。我不确定,但我怀疑 MD5 会是这两种算法中更简单、更快的算法。

      【讨论】:

      • 惊喜!在实际测试中,MD5 和 SHA-1 在 .NET 框架中的速度相同。
      • SHA1 有已知的弱点,但没有被破坏。但是,当需要安全性时,将其视为已损坏是明智的。
      【解决方案4】:

      我建议使用System.Security.Cryptography.SHA1Cng 类。它有 160 位或 20 字节长,所以绝对应该足够小。如果你需要它是一个字符串,它只需要 40 个字符,所以这应该很适合你的需要。它也应该足够快,据我所知,还没有发现碰撞。

      【讨论】:

      • 在 base64 编码中,160 位肯定是 28 个字符吗?即使使用十六进制,它仍然只有 40 个字符(每个字符 4 位)。
      • @Chris 试试看Convert.ToBase64String(new byte[20]).Length
      • @Chris:我的数学有点不对劲 :) 而且我实际上在考虑十六进制,因为我对该网站了解不多。它们可能需要对 URL 友好。但同样,这只是在它需要是一个字符串的情况下。 BINARY() 会更好。
      • @L.B.:我是对的。我的第一个问题是修辞性的,而不是真正的信息请求。用这种方式表达事情对我来说似乎不那么具有对抗性,而不是“你错了。它将是 28/40 字节”。这是一个很好的例子,说明检查这些东西是多么容易。特别是如果你有像 LinqPad 这样的东西,它可以执行这样的单行代码,而无需将它放入任何类型的框架中。 :)
      • 如果您想知道,SHA1Cng 实现通常是最快的。 SHA1Managed 是最慢的,SHA1CryptoServiceProviderSHA1Cng 几乎相同(尽管我在 SHA1Cng 上获得了大约 1% 的性能提升)。在 Core i5 处理器上使用 1KB 明文对此进行了测试。
      【解决方案5】:

      我个人会使用String.GetHashCode()。这是基本的哈希函数。老实说,我不知道它与其他实现相比表现如何,但应该没问题。

      您命名的两个散列函数中的任何一个都应该足够快,以至于您不会注意到它们之间的太大差异。除非这个网站需要超高性能,否则我不会太担心它们。我个人可能会选择MD5。这可以格式化为 64 个字符的十六进制字符串或 44 个字符的基本 64 字符串。

      我选择 MD5 的原因是因为您不太可能遇到冲突,即使发生冲突,您也可以使用“where urlhash = @hash and url = @url”来构建查询。数据库引擎应该计算出一个被索引而另一个没有被索引,并使用该信息进行明智的搜索。

      如果存在 colisions,则 urlhash 上的索引扫描将返回一些结果,这些结果将很容易进行文本比较以获得正确的结果。不过,这不太可能经常相关。以这种方式发生碰撞的可能性非常低。

      【讨论】:

      • 这可能不应该被使用,因为这个函数的实现可能会在不同版本的 .Net Framework 之间发生变化(如文档中特别指出的那样)。
      【解决方案6】:

      .net 4.0中GetHashCode函数的反映源码

      public override unsafe int GetHashCode()
      {
          fixed (char* str = ((char*) this))
          {
              char* chPtr = str;
              int num = 0x15051505;
              int num2 = num;
              int* numPtr = (int*) chPtr;
              for (int i = this.Length; i > 0; i -= 4)
              {
                  num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
                  if (i <= 2)
                  {
                      break;
                  }
                  num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
                  numPtr += 2;
              }
              return (num + (num2 * 0x5d588b65));
          }
      }
      

      有 O(n) 个简单的操作(+、

      我已经在 300 万个数据库上测试了这个函数,其中包含长度不超过 256 个字符的字符串,并且大约 97% 的字符串没有冲突。 (最多 5 个字符串具有相同的哈希)

      【讨论】:

        【解决方案7】:

        您可能想查看以下项目:

        CMPH - C Minimal Perfect Hashing Library

        并查看以下热门话题列表以获得完美的哈希值:

        Hottest 'perfect-hash' Answers - Stack Overflow

        您也可以考虑在 SQL 中使用全文索引而不是散列:

        CREATE FULLTEXT INDEX (Transact-SQL)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-07
          • 1970-01-01
          • 1970-01-01
          • 2014-03-30
          • 1970-01-01
          • 2011-02-25
          • 2020-12-30
          相关资源
          最近更新 更多