我有一个table1,其中所有商店名称如下:
表1
id|name
1 |wairau road
在第二个表2中,我具有以下值:
表2
id|name |customer_name
1|wairau rd |shelly
2|wairau road |andy
3|wairauroad |ally
当我做select * from table 2
时,
我的预期输出如下:
id |名称| customer_name 1 | Wairau道路| Shelly 2 | Wairau Road |安迪 威乐路3号|盟友
注意到该名称现在要与table1中的名称同步。有没有办法在postgres / redshift SQL中做到这一点?
答案 0 :(得分:2)
如您所知,脏数据的解决方案是清理它。如果您要像显示的那样处理地址数据,那么地址标准化本身就是一个不错的选择。这是一个普遍的问题,有很多解决方案和服务。最佳方法可能在很大程度上取决于您需要支持的国家和预算。
您已经很好地建议使用soundex来解决此问题。 soundex的作用是将字符串转换为代码,以便将听起来相似的字符串转换为相同的代码。可以预先准备好此翻译,并将其存储在索引中,这可以使音效比较非常快。不好的一面是,soundex的历史可追溯到一百年前,它是用来给姓氏打分的,并且是为美国英语版本而设置的。因此,并不是每个问题都适合。您会在同一扩展名中找到Meataphone,它可能会更好一些,但或多或少都具有相同的优缺点。该扩展名也具有Levenshtein距离,也称为“编辑距离”。它计算将一个字符串转换为另一字符串必须进行的更改。长字符串比短字符串更好。这很棒!但这也不是您可以预先计算的,因为您不知道要与之比较。但是,一旦通过其他方法找到了一些可能的匹配项,它便是对相似字符串进行排名的好工具。
说到其他方式,Postgres中还有另一个出色的工具可以签出:
https://www.postgresql.org/docs/current/pgtrgm.html
这是标准软件包的一部分,因此您将按照与模糊字符串匹配相同的说明安装它。 Trigram是一个超越上面列出的简单模糊字符串匹配的世界。他们背后进行了大量研究,可以在不同的语言和数据集之间很好地工作。上周,我终于花了一些时间看一下Postgres的实现,它很棒
select 'wairau rd' as address, show_trgm('wairau rd') union all
select 'wairau rd' as address, show_trgm('wairau road') union all
select 'wairau rd' as address, show_trgm('wairauroad')
那会吐出这样的东西:
address,show_trgm
wairau rd,"{"" r"","" w"","" rd"","" wa"",air,""au "",ira,rau,""rd "",wai}"
wairau rd,"{"" r"","" w"","" ro"","" wa"",""ad "",air,""au "",ira,oad,rau,roa,wai}"
wairau rd,"{"" w"","" wa"",""ad "",air,aur,ira,oad,rau,roa,uro,wai}"
魔术部分是Postgres然后可以使用这些块对索引进行一些非常好的比较和猜测。由于索引位于覆盖整个字符串的这些微小块上,因此您摆脱了标准B树的左锚限制。这提供了很大的灵活性和功能,而不会降低查询速度。
有两种设置索引的方法,具体取决于您感兴趣的比较类型。在时间和空间上也需要权衡取舍,但是一旦确定此工具已完成,就需要检查一下甚至对您来说都是一个不错的选择。这是两个索引:
CREATE INDEX table_1_names_gin
ON table1
USING gin (address gin_trgm_ops);
CREATE INDEX table_1_names_gist
ON table1
USING gist (address gist_trgm_ops);
我在这里称您的字段为“地址”,因为我不会称呼字段名称。一旦有了此类索引,便可以进行快速的LIKE或ILIKE搜索,以及模式匹配搜索,而无需复杂的正则表达式语法。像这样(未经测试)的搜索开始搜索
:select *
from table2
where address ILIKE 'wairu%'
甚至对于包含搜索:
select *
from table2
where address ILIKE 'wairu%'
或者通过以下类似搜索: 来自analytic_scan
select *
from table2
where address %> 'wairu'
还有更多,但我会停下来。老实说,无论如何,地址标准化应该是您的第一步。但是模糊匹配可以提供帮助。
提示:过去,我发现人们经常输入错误的地址或不一致的地址是出于(可用性/ UX)原因。如果您的数据库是公司应用程序的一部分,一种选择是每晚运行报告,以查找和标记不标准的地址或名称。模糊匹配在这里非常有用。然后,有人可以帮助训练犯错误的人做得更好。也许您发现的是,系统的UI使得输入错误数据比输入好数据容易。在这种情况下,您可以对应用程序进行改进以使其更好,并测量几乎重复的变化来衡量您的表现。
答案 1 :(得分:1)
您可以使用soundex(扩展名为Fuzzystrmatch)。在the SQL Fiddle
中测试CREATE EXTENSION if not exists fuzzystrmatch;
CREATE TABLE t1 (id int, name text);
CREATE TABLE t2 (id int, name text, customer_name text);
INSERT INTO t1 VALUES (1, 'wairau road');
INSERT INTO t1 VALUES (2, 'joe road');
INSERT INTO t1 VALUES (3, 'jerry road');
INSERT INTO t2 VALUES (1, 'wairau rd', 'shelly');
INSERT INTO t2 VALUES (2, 'wairau road', 'andy');
INSERT INTO t2 VALUES (3, 'wairauroad', 'ally');
INSERT INTO t2 VALUES (4, 'joe row', 'john');
INSERT INTO t2 VALUES (5, 'joe.rd', 'jack');
SELECT DISTINCT ON (t2.id) t2.id, t1.name, t2.customer_name,
t2.name AS data_entry_name
FROM t2
CROSS JOIN t1
ORDER BY t2.id, t1.name = t2.name DESC, difference(t1.name, t2.name) DESC, t1.name
如果有很多数据,查询可能会非常慢。在这种情况下,它将通过ORDER BY选择最可能的匹配项:
您可以添加更多规则,例如如果没有空格的小写版本匹配。
此查询的问题是它将显示最可能的匹配,如果没有可能的匹配,则可能完全错误。另外,这是一个最佳猜测,因此查询可能会做出错误的选择。