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

Algorithm 从名称和地址数据创建id。散列/摘要,algorithm,hash,digest,Algorithm,Hash,Digest,我的问题是: 我正在寻找一种方法来表示一个人的姓名和地址作为一个编码的id。该id应该只包含字母数字字符,是防冲突的,并以尽可能少的字符数表示。我的第一个想法是简单地使用加密散列函数,如MD5或SHA1,但这似乎有点过头了(安全性并不重要,不需要是单向的),我更喜欢找到可以生成更短id的东西。有人知道适合这个问题的现有算法吗 换句话说,实现以下函数的最佳方法是什么,以使相同输入的返回值一致,不可能发生冲突,并且ID少于20个字符 >>> make_fake_id(fname =

我的问题是:

我正在寻找一种方法来表示一个人的姓名和地址作为一个编码的id。该id应该只包含字母数字字符,是防冲突的,并以尽可能少的字符数表示。我的第一个想法是简单地使用加密散列函数,如MD5或SHA1,但这似乎有点过头了(安全性并不重要,不需要是单向的),我更喜欢找到可以生成更短id的东西。有人知道适合这个问题的现有算法吗

换句话说,实现以下函数的最佳方法是什么,以使相同输入的返回值一致,不可能发生冲突,并且ID少于20个字符

>>> make_fake_id(fname = 'Oscar', lname = 'Grouch', stnum = '1', stname = 'Sesame', zip = '12345')
N1743123734
应用程序上下文(对于感兴趣的人):


这将用于一个新的应用程序。给定一个输入名称和地址,我们在一个非常大的数据库中搜索最佳匹配项,并返回数据库id和其他数据(在这里我们如何做并不重要)。如果没有匹配项,我需要从搜索输入(实体的名称和地址数据)生成此psuedo/generated/derived id。每个搜索记录都应生成一个输出记录,其中包含实数(匹配/链接产生的实际数据库id)或此生成的psuedo/生成/派生id。psuedo id将以字符(例如N)作为前缀,以将其与实数id区分开来。

我知道您对MD5和SHA1说了不,但我认为你还是应该考虑他们。除了经过充分研究的散列算法外,长度为您提供了更多的保护,以防止可能发生的冲突。没有散列是防冲突的,但加密散列通常比你自己能想到的更不容易发生冲突。

好吧,如果同一地址有多个人同名,你就到此为止(没有添加代码来检测这种情况并添加某种鉴别器)

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

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

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和全名,或者使用相同的哈希值,尽管哈希值方法生成重复项的可能性很小

我想知道您是否打算将这些ID“分配”给用户?如果是这样,我希望你的用户会讨厌你提出的任何建议;谁想要“aaaa01”的用户id

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

如果这些IDS是试图检测一次注册多于一次的用户,那么我同意您应该考虑加密散列,然后再完整地比较注册数据(名称、地址等)。但是,为了便于使用,您需要在计算哈希或进行比较之前将数据转换为规范格式(标准化的字母大小写、空格、规范的街道地址等)。否则,您将基于微小的差异而不匹配

编辑:基于您的编辑,现在我更好地理解了问题空间,我认为您的算法(到目前为止)不太可能捕捉到大多数匹配。除了我提出的规范输入的建议外,我建议你考虑一种方法,在一个排名列表中列出一些可能的匹配(如果可能的话,由人类来解决),而不是在一个匹配中进行完全或无尝试。换句话说,我建议使用搜索方法而不是查找方法


这在您的情况下可行吗?

好的解决方案在某种程度上取决于您的应用程序。您知道有多少用户,以及所有用户的集合是什么吗?如果你提供更多的细节,你会得到更好的帮助。

我同意另一张建议序列号的海报。OTOH,如果你真的真的真的想做其他事情:

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

然后,当您获得数据时,计算散列,在表中查找,得到序列号,这就是您的id。如果它不在表中,请插入它。

  • 对其属性使用加密哈希,而不是其他属性
  • 从散列中使用任意多的字节(截断)
  • 转换为字母数字字符
  • 您还可以截断字母数字字符串而不是散列
一个简单的方法是:散列数据,用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亿)之间的冲突。

您能否将您的问题扩展到包括您的目标环境?这是SQL DB ID还是内存中受约束的设备数据结构?它是否总是必须为相同的输入生成相同的键?我希望有一个函数,它接受以下参数并将“id”作为字符串返回:*名*姓*USPS邮政编码*街道编号*街道预定向*街道名称*街道邮政定向