我有一个可与 MySQL 数据库配合使用的 Java 应用程序。
我希望能够存储长文本并检查表是否包含它们。为此,我想使用索引,并通过减少全文的“哈希”进行搜索。
MY_TABLE [
full_text: TEXT
text_hash: varchar(255) - indexed
]
问题是,我不能将 String.hashCode() 用作:
我想找到一个快速哈希函数,它将读取长文本值并为其生成一个长哈希值,例如 64 个符号长。
这种可靠的哈希方法并不快。不过,它们可能足够快。您正在寻找一种加密消息摘要方法(例如用于识别 P2P 网络中的文件或 Git 中的提交的方法)。查找 MessageDigest 类,然后选择您的算法(SHA1、MD5、SHA256 等)。
这样的哈希函数将采用字节作为参数,并生成字节作为结果,因此请确保使用常量编码(例如 UTF8)转换字符串,并转换生成的字节数组(通常为 16 或 20 字节) ) 到使用十六进制或 Base64 编码的可读字符串。
我建议您重新访问
String.hashCode()
。
首先,它不会因实现而异。指定了确切的哈希值;请参阅 String.hashCode javadoc 规范。
其次,虽然字符串哈希算法并不是最好的(而且它肯定会比加密哈希有更多的冲突),但它确实在将哈希值分布在 32 位结果空间上方面做得相当好。例如,我快速检查了我机器上的一个文本文件 (
/usr/share/dict/web2a
),其中包含 235,880 个单词,并且存在 6 冲突。
第三和第四:
String.hashCode()
应该比加密哈希要快得多,并且哈希值所需的存储应该要小得多。
如果您将字符串存储在数据库表中,并且它们的哈希值已建立索引,那么出现一些冲突应该不重要。查找字符串应该很快就能找到正确的数据库行,而且与数据库 I/O 相比,(也许)检查几个实际字符串应该非常快。
我建议使用 mzHash64,一个非常简单、快速的函数,其碰撞次数非常接近理想的通用哈希函数
public static long mzHash64(byte[] data, int start, int length, long seed) {
long hash = 0xD45E69F901E72147L ^ seed;
for(int i = 0; i < length; i++)
hash = 0x3631754B22FF2D5CL * (i + data[start + i]) ^ (hash << 2) ^ (hash >>> 2);
return hash;
}
public static long mzHash64(String str) {
byte[] data = str.getBytes();
return mzHash64(data, 0, data.length, 0);
}