为了节省PostgreSQL中的磁盘空间,我希望将可变长度(6-60个字符长)的字符串散列到32位的PostgreSQL。
我不想加密任何数据,哈希函数需要是可复制的,并且可以从Python调用。问题是,我只能找到生成无符号整数(如CityHash)的算法,从而产生高达2^32的值,而不是2^31。
到目前为止,这就是我所拥有的:
import math
from cityhash import CityHash32
string_ = "ALPDAKQKWTGDR"
hashed_string = CityHash32(string_)
print(hashed_string, len(str(hashed_string)))
max_ = int(math.pow(2, 31) - 1)
print(hashed_string > max_)发布于 2019-03-30 17:15:32
我通常不会使用32位散列,除非基数很低,因为它当然比64位散列更有可能发生碰撞。数据库很容易支持双字节8字节(64位)整数.考虑一些哈希冲突概率的这张桌子。
如果使用Pythons3.6,则绝对不需要为此使用第三方包,也不需要减去偏移量,因为您可以使用shake_128直接生成带符号的64位或 可变位长散列 。
import hashlib
from typing import Dict, List
class Int8Hash:
BYTES = 8
BITS = BYTES * 8
BITS_MINUS1 = BITS - 1
MIN = -(2**BITS_MINUS1)
MAX = 2**BITS_MINUS1 - 1
@classmethod
def as_dict(cls, texts: List[str]) -> Dict[int, str]:
return {cls.as_int(text): text for text in texts} # Intentionally reversed.
@classmethod
def as_int(cls, text: str) -> int:
seed = text.encode()
hash_digest = hashlib.shake_128(seed).digest(cls.BYTES)
hash_int = int.from_bytes(hash_digest, byteorder='big', signed=True)
assert cls.MIN <= hash_int <= cls.MAX
return hash_int
@classmethod
def as_list(cls, texts: List[str]) -> List[int]:
return [cls.as_int(text) for text in texts]用法:
>>> Int8Hash.as_int('abc')
6377388639837011804
>>> Int8Hash.as_int('xyz')
-1670574255735062145
>>> Int8Hash.as_list(['p', 'q'])
[-539261407052670282, -8666947431442270955]
>>> Int8Hash.as_dict(['i', 'j'])
{8695440610821005873: 'i', 6981288559557589494: 'j'}若要生成32位哈希,请将Int8Hash.BYTES设置为4。
免责声明:我没有编写统计单元测试来验证这个实现是否返回均匀分布的整数。
https://stackoverflow.com/questions/45279590
复制相似问题