数据库中许多字符串的相似性

时间:2016-07-06 18:42:29

标签: database string postgresql levenshtein-distance jsonb

检查两个具有多个属性的对象是否相似的最佳方法是什么?

假设我有一个对象 - 地址,它有10个字段,如:location1,location2,location3,location4,...,postalCode,所有者,居住者......

它们都作为jsonb类型存储在postgres数据库中。

当新对象进来时,我需要检查是否有类似的地址。

在这种情况下最常用的技术是什么?

一个想法是连接所有属性并检查levenshtein距离。

我现在不依赖于任何特定的技术,要求这些对象可以很多,并且必须存储在某个地方。

1 个答案:

答案 0 :(得分:0)

JSON和JSONB类型意味着数据标记有不同含义的元素。这通常意味着这些不同的元素不能以同样的方式被有效地处理,这进一步意味着一刀切的方法可能不会得到好的结果。

正如你所提到的,Levenshtein距离是一种可能的方法,但大部分时间它必须以某种方式加权,这种方式是根据您的特定数据定制的,甚至可能对大多数真实数据来说也不够集。

例如,考虑类似基本地​​址的内容。匹配街道号码本身是没有意义的。同样匹配街道名称。实际上所有元素都是依赖的,只有当一个从匹配的国家开始并通过州/省等工作时,“相似性”才具有真正的意义。简单的权重无法捕捉到这种关系。

解决方案是使用存储过程来确定给定表中行之间的相似性。虽然PL / pgSQL可以用于此(并且对于简单的表格非常有用),但是当事情变得复杂时,可能值得挖掘像PL / Python这样的东西。当然,这些存储过程的效率会随着它们的编写方式而有很大差异,但是即使在大型数据库中使用它们时,它们也可以很好地执行。

例如(并且在你的问题中没有足够的信息来制作一些可以直接在这里工作的东西,所以请把它当作比伪代码更好的东西但不是经过彻底测试的PL / Python):

CREATE OR REPLACE FUNCTION compare_json_addresses(addr1 JSON, addr2 JSON)
RETURNS INTEGER AS
$$
BEGIN
  import simplejson as json
  a1, a2 = json.loads(addr1), json.loads(addr2)
  similarity = 0
  for unit in ('country', 'state', 'town', 'street', 'num'):
      if a1[unit] != a2[unit]:
          break
      else:
          similarity += 1
  return similarity
END;
$$
LANGUAGE plpythonu STRICT IMMUTABLE;

显然,您必须对此进行修改,以便考虑您正在使用的各种其他位置字段,并弄清楚您希望它们如何关联。