1

我有两张大桌子,我需要把它们放在一起。匹配不应该是一个明确的比较。我使用了三元组,Levenshtein 的公式,但我的表现很差。也许有人可以帮助提高性能。表 A 的大小约为 20 万行,表 B 的大小约为 60 万行。

   CREATE TABLE TBL_A(NAME VARCHR,SURNAME VARCHAR, BIRTH_DATE DATE, TABLE_B_ID INT4);
   CREATE TABLE TBL_B(ID INT4, NAME VARCHR, SURNAME VARCHAR, BIRTH_DATE DATE);
--variant 1
SET pg_trgm.similarity_threshold = 0.8; 
UPDATE TBL_A A SET TABLE_B_ID = B.ID
FROM TBL_B B
WHERE A.NAME % B.NAME
AND A.SURNAME % B.SURNAME
AND ABS(A.BIRTH_DATE ::DATE - B.BIRTH_DATE ::DATE)<=1 
--variant 2
UPDATE TBL_A A SET TABLE_B_ID = B.ID
FROM TBL_B B
WHERE A.NAME = B.NAME
AND A.SURNAME = B.SURNAME
AND ABS(A.BIRTH_DATE ::DATE - B.BIRTH_DATE ::DATE)<=1   
--variant 3
UPDATE TBL_A A SET TABLE_B_ID = B.ID
FROM TBL_B B
WHERE levenshtein_less_equal (A.NAME ,B.NAME,2)<=2
AND levenshtein_less_equal (A.SURNAME ,B.SURNAME,2)<=2 
AND ABS(A.BIRTH_DATE ::DATE - B.BIRTH_DATE ::DATE)<=1 

所有这些选项的性能都很差(接近 7 小时)。我尝试创建索引,但没有得到太多加速

CREATE INDEX ind_a_name ON TBL_A USING gist(NAME  trm_gist_ops);
CREATE INDEX ind_a_Surname ON TBL_A USING gist(SURNAME  trm_gist_ops);
4

1 回答 1

0

遗憾的是,无法对 Levenshtein 距离比较进行索引。每个比较都是两个输入字符串的函数。

通常通过使用消除大多数比较的两阶段 where 子句来解决这类问题,然后应用 Levenshtein 的字符串距离函数。

你能设计一个单射函数f(name)来产生某种签名name吗?举个简单的例子,它可以从名称中删除元音。SOUNDEX()就是这样一个函数,但它确实很粗糙,只能在北美名称上正常工作。Metaphone是一个类似的功能。(想出这些功能的人都是会说英语的人。)

如果你这样做,那么你可以用

   name, signature_name

在 上放一个索引(signature_name, name),然后使用这个 WHERE 过滤器。

 WHERE A.signature_name = B.signature_name
   AND levenshtein_less_equal (A.name,B.name,2)<=2

诀窍:使用索引列进行大部分比较工作,并且仅在您已经知道自己有一个紧密匹配时才使用 Levenshtein。

于 2021-08-09T13:21:32.700 回答