为与平台无关的字符串生成Hashcode

时间:2012-02-08 17:57:16

标签: c# .net hash hashcode

我们有一个

的应用程序
  • 在字符串
  • 上生成哈希码
  • 将该哈希码与相关数据一起保存到数据库中
  • 稍后,它使用字符串哈希码查询数据库以检索数据

这显然是一个错误,因为string.GetHashCode()返回的值与.NET版本和体系结构(32/64位)不同。更复杂的是,我们太接近于发布以重构我们的应用程序以停止序列化哈希码而只是查询字符串。我们想要做的是现在提出一个快速而肮脏的修复程序,稍后重构代码以正确的方式执行。

快速而肮脏的修复似乎是创建一个跨架构一致的静态GetInvariantHashCode(string s)帮助器方法。

可以建议一种在32位和64位架构上等效的字符串上生成哈希码的算法吗?

还有一些说明:

  • 我知道HashCodes不是唯一的。如果哈希码在两个不同的字符串上返回匹配,我们会发布处理结果以找到完全匹配。它不用作主键。
  • 我相信建筑师的意图是通过查询长而不是NVarChar来加快搜索速度

3 个答案:

答案 0 :(得分:4)

  

我知道HashCodes不是唯一的。如果哈希码在两个不同的字符串上返回匹配,我们会发布处理结果以找到完全匹配。它不用作主键。

     

我相信建筑师的意图是通过查询长而不是NVarChar来加快搜索速度

然后让数据库为你索引字符串!

看,我不知道你的域名有多大,但如果它的大小合适,你很快就会发生碰撞。这是许多人的生日问题,与生日数相关。你将会发生碰撞,并且不会因为首先将字符串编入索引而失去你可能认为正在获得的速度增益。

无论如何,如果您在发布后几天停留,并且您确实需要跨平台的不变哈希码,则不需要我们。你可以使用真正愚蠢,非常快速的哈希代码实现。天啊,你可以在眨眼之间想出一个:

string s = "Hello, world!";
int hash = 17;
foreach(char c in s) {
    unchecked { hash = hash * 23 + c.GetHashCode(); } 
}

或者你可以使用旧的Bernstein哈希。等等。他们会为您提供您正在寻找的性能提升吗?我不知道,它们不应该用于此目的。它们旨在用于平衡哈希表。你没有平衡哈希表。你使用的是错误的概念。

编辑(以下是在使用新的显着信息编辑问题之前编写的)

理论上,如果没有对输入空间的某种限制,你根本无法做到这一点。您的问题比String.GetHashCode从平台到平台的差异要严重得多。

string有很多实例。事实上,实例的情况多于Int32的实例。因此,由于piegonhole原理,你会发生碰撞。你无法避免这种情况:你的string是鸽子,而你的Int32哈希码是凹坑,鸽舍里有太多的鸽子没有鸽子的鸽子。由于碰撞问题,您不能将哈希码用作字符串的唯一键。它不起作用。周期。

您可以将当前提议的设计工作的唯一方法(使用Int32作为string实例的标识符)是将字符串的输入空间限制为大小小于或等于Int32的数量。即使这样,您也很难找到一种算法,以独特的方式将string s的输入空间映射到Int32

即使你试图通过使用SHA-512或其他任何东西来增加鸽笼的数量,你仍然有可能发生碰撞。我怀疑你之前在你的设计中考虑过这种可能性;这个设计路径是DOA。而且这不是SHA-512的用途,它不能用于唯一的消息识别。这只是为了减少消息伪造的可能性。

  

为了使问题复杂化,我们太接近于发布以重构我们的应用程序以停止序列化哈希码并只是查询字符串。

那么,你有很多工作要做。对不起,你在游戏中这么晚就发现了这个。

我注意到String.GetHashCode的文档:

  

GetHashCode的行为取决于其实现,该实现可能会从公共语言运行库的一个版本更改为另一个版本。可能发生这种情况的原因是为了提高GetHashCode的性能。

来自Object.GetHashCode

  

GetHashCode方法适用于散列算法和数据结构,例如散列表。

哈希码用于平衡哈希表。它们不是用于识别物体。如果你已经将这个概念用于它的用途,你本可以更快地抓住它。

答案 1 :(得分:3)

您应该使用SHA512。

请注意,哈希不是(也不可能)唯一的 如果您需要它是唯一的,只需使用身份函数作为哈希。

答案 2 :(得分:2)

您可以使用其中一个托管加密类(例如SHA512Managed)通过ComputeHash计算与平台无关的哈希值。这将需要将字符串转换为字节数组(即:使用Encoding.GetBytes或其他方法),并且速度慢,但要保持一致。

话虽如此,哈希不能保证唯一,并且实际上不是数据库中唯一性的正确机制。使用哈希来存储数据可能会导致数据丢失,因为第一次哈希冲突将覆盖旧数据(或丢弃新数据)。