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

Similarity on many strings in database

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

假设我有一个对象 - 地址,它有 10 个字段,例如:location1、location2、location3、location4、...、postalCode、owner、habitants..

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

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

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

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

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

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

正如您提到的,Levenshtein 距离是一种可能的方法,但大多数时候它必须以某种方式进行加权,以针对您的特定数据进行定制,即使这样对于大多数人来说可能还不够真实数据集。

例如,考虑基本地址之类的东西。单独匹配街道号码是没有意义的。同上匹配街道名称。实际上所有的元素都是依赖的,只有从匹配的国家开始并通过 state/province 等向下计算,"similarity" 才有真正的意义。简单的权重将无法捕获这种类型的关系。

解决方案是使用存储过程来确定给定 table 中行之间的相似性。虽然 PL/pgSQL 可用于此(并且对于简单的 tables 非常有效),但当事情变得复杂时,可能值得深入研究 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;

显然,您必须修改它以同时考虑您正在使用的各种附加位置字段,并弄清楚您希望它们如何关联。