从名称和地址数据创建id。散列/摘要

时间:2008-12-01 18:13:20

标签: algorithm hash digest

我的问题:

我正在寻找一种方法来将一个人的姓名和地址表示为编码ID。 id应仅包含字母数字字符,防碰撞,并以尽可能少的字符表示。我的第一个想法是简单地使用加密哈希函数,如MD5或SHA1,但这似乎有点过分(安全性并不重要 - 不需要单向),我更愿意找到能产生更短的身份。有没有人知道适合这个问题的现有算法?

换句话说,实现以下函数的最佳方法是什么,以便相同输入的返回值一致,碰撞不太可能,并且id少于20个字符?

>>> make_fake_id(fname = 'Oscar', lname = 'Grouch', stnum = '1', stname = 'Sesame', zip = '12345')
N1743123734

应用程序上下文(对于那些感兴趣的人):

这将用于record linkage app。给定一个输入名称和地址,我们搜索一个非常大的数据库以获得最佳匹配,并返回数据库ID和其他数据(我们如何做到这一点并不重要)。如果没有匹配,我需要从搜索输入(实体的名称和地址数据)生成此伪造/生成/派生的id。每个搜索记录都应该生成一个输出记录,其中包含一个实数(由匹配/链接产生的实际数据库ID)或者生成的伪造/生成/派生ID。 psuedo id将以字符(例如N)为前缀,以区别于真实id。

6 个答案:

答案 0 :(得分:4)

我知道你对MD5和SHA1说不,但我认为无论如何你应该考虑它们。除了经过充分研究的散列算法之外,长度还可以为您提供更多保护,防止可能发生的冲突。没有散​​列是防碰撞的,但是加密的散列通常不像你想要的那样容易碰撞。

答案 1 :(得分:3)

  • 为其collision resistance使用加密哈希,而不是其他品质
  • 根据需要使用哈希中的字节数(截断)
  • 转换为字母数字字符
  • 您还可以截断字母数字字符串而不是哈希

一种简单的方法:哈希数据,在base64中编码,删除所有非字母数字字符,截断。

N_HASH_CHARS = 11
import hashlib, re
def digest(name, address):
  hash = hashlib.md5(name + "|" + address).digest().encode("base64")
  alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", hash)
  return alnum_hash[:N_HASH_CHARS]

您应该保留多少字母数字字符?每个字符为您提供大约5.95位的熵(log(62,2))。 11个字符为您提供65.5位熵,这应足以避免前2 ** 32.7用户(约70亿)的冲突。

答案 2 :(得分:0)

我想知道您是否打算将这些ID“分配”给用户?如果是这样,我希望您的用户讨厌您提议的任何内容;谁想要用户ID为“AAAAA01”?

因此,如果用户可以看到这些ID,那么您应该让他们选择他们喜欢的内容并检查它们的唯一性(简单)。如果用户看不到它们(例如,内部主键),那么只需使用适当的技术(如Oracle序列或SQL Server自动编号)(也很简单)顺序生成它们。

如果这些ID是尝试检测多次注册的用户,那么我同意您应该考虑加密哈希,然后对注册数据(名称,地址等)进行全面比较。但是,为了可以使用,您需要在计算哈希值或进行比较之前将数据转换为规范形式(标准化字母大小写,空格,规范街道地址等)。否则,您将根据微不足道的差异而不匹配。

编辑:现在我根据您的编辑更好地理解了问题空间,我认为您的算法(到目前为止)不太可能捕获大多数匹配。除了我对输入进行规范化的建议之外,我建议您考虑一种方法,该方法会产生少数可能匹配的排序列表(如果可能,由人类解决),而不是单个匹配的全有或全无尝试。换句话说,我建议使用搜索方法而不是查找方法。

在你的情况下这是否可行?

答案 3 :(得分:0)

一个好的解决方案在某种程度上取决于您的应用。你知道有多少用户和所有用户是什么?如果您提供更多详细信息,您将获得更好的帮助。

答案 4 :(得分:0)

我同意另一张提示序列号的海报。 OTOH,如果你真的,真的真的想做别的事情:

从数据创建SHA1哈希,并将其存储在带有序列号字段的表中。

然后,当你得到数据时,计算哈希值,在桌面上查找,得到序列号,那就是你的id。如果它不在桌子上,请插入它。

答案 5 :(得分:-1)

好吧,如果同一个地址的同一个地址不止一个人,你就会在这里干杯,(不添加代码来检测这个并添加某种鉴别器)。

但假设问题不是,那么完整地址的街道地址和邮政编码部分足以保证其中的唯一性,因此从名称中添加足够的数据应该可以解决问题......

您是否可以访问数据库或其他持久性机制,您可以在其中为每个地址生成和维护键值?然后将地址和单个实体保存在两个键控字典结构中,其中为每个新的不同地址,遇到的人自动生成密钥...然后使用自动生成的字母数字键...

You could use AAAAA01  for first person at first address,
              AAAAA02 for second person at first address,
              AAAAB07 for the seventh resident at the second adresss, etc.

如果你没有办法生成和维护这些实体键映射,那么你需要使用完整的街道地址/ Zip和fullNAme,或者哈希值相同的哈希值,尽管哈希值方法有一个很大的机会生成重复...