繁体   English   中英

Oracle - 查找两个表之间的最佳匹配

[英]Oracle - Find Best Match between Two tables

我和我的团队很想知道我们可以匹配两组不同数据的最佳方式。 没有可以加入的密钥,因为这些数据来自两个彼此不了解的独立来源。 我们将这些数据导入两个oracle表中,一旦完成,我们就可以开始查找匹配项了。

两个表都包含一个完整的属性列表(在房地产中)。 我们需要将Table1中的Properties与Table2中找到的任何可能的匹配属性进行匹配。 对于Table1中的每个记录,搜索Table2中的潜在匹配并确定匹配的概率。 我和我的团队已经决定,最好的方法是比较两个表中每个表的地址字段。

一个问题是Table1以解析格式提供地址,并将地址编号,地址Street和甚至Address_type分配到单独的列中,而Table2仅包含一个用于保存地址的列。 每个表都有City,State和Zip列,可以单独进行比较。

例如 - 见下表1和表2:

请注意,我下面的伪表中的主键是与其所在表匹配的Key1和Key2。

    +---------------+---------------+---------------+---------------+---------------+-------+-------+
    +               +    TABLE1     +               +               +               +       +       +
    +---------------+---------------+---------------+---------------+---------------+-------+-------+
    | Key1          | Addr_Number   | Addr_Street   | Addr_Type     | City          | State | Zip   |
    +---------------+---------------+---------------+---------------+---------------+-------+-------+
    | 1001          | 148           | Panas         | Road          | Robinson      | CA    | 76050 |
    | 1005          | 110           | 48th          | Street        | San Juan      | NJ    | 8691  |
    | 1009          | 8571          | Commerce      | Loop          | Vallejo       | UT    | 83651 |
    | 1059          | 714           | Nettleton     | Avenue        | Vista         | TX    | 29671 |
    | 1185          | 1587          | Orchard       | Drive         | Albuquerque   | PA    | 77338 |
    +---------------+---------------+---------------+---------------+---------------+-------+-------+


    +---------------+----------------------+---------------+---------------+---------------+
    +               +    TABLE2            +               +               +               +
    +---------------+----------------------+---------------+---------------+---------------+
    | Key2          | Address              | City          | State         | Zip           |
    +---------------+----------------------+---------------+---------------+---------------+
    | Ax89f         | 148 Panas Road       | Robinson      | CA            | 76050         |
    | B184a         | 110 48th Street      | San Juan      | NJ            | 08691         |
    | B99ff         | 8571 Commerce Lp     | Vallejo       | UT            | 83651         |
    | D81bc         | 714 Nettleton Ave    | Vista         | TX            | 29671         |
    | F84a2         | 1587 Orachard Dr     | Albuquerqu    | PA            | 77338         |
    +---------------+----------------------+---------------+---------------+---------------+

这里的目标是向用户提供一个输出,它只显示Table1中的所有记录和Table2中找到的最高匹配记录。 当然可以找到许多可能是匹配的记录,但我们希望保持这种一对一的关系,而不是在这个初始输出中产生重复。 输出应该只是表1中的一个记录,与表2中的最佳查找匹配。

请参阅下面我尝试创建的Desired输出的示例:

    +--------+-------+----------------+---------------------------+
    +        +       + Matched_Output +                           +
    +--------+-------+----------------+---------------------------+
    | Key1   | Key2  |  Percent_Match | num_Matched_Records > 90% |
    +--------+-------+----------------+---------------------------+
    | 1001   | Ax89f |  100%          |  5                        |   --All Parsed Values Match
    | 1005   | B184a |  98%           |  4                        |   --Zip Code prefixed with Zero in Table 2
    | 1009   | B99ff |  95%           |  3                        |   --Loop Vs Lp
    | 1059   | D81bc |  95%           |  2                        |   --Avenue Vs Ave
    | 1185   | F84a2 |  97%           |  2                        |   --City Spelled Wrong in Table 2 and Drive vs Dr
    +--------+-------+----------------+---------------------------+

在输出中我想看到Table1中的Key1和它旁边的匹配记录,表明它与Table2中的记录匹配到Key2。 接下来我们需要知道这两个记录的匹配程度。 表2中可能有许多记录显示匹配表1中记录的概率。 实际上,表2中的每个记录都可以从0%到100%匹配一直分配一个百分比。

那么现在主要问题是:如何获得这个百分比?

如何解析Table2中的Address列,以便我可以比较构成Table1中地址的每个列,然后对每个解析的值应用比较算法?

到目前为止,这是我的团队和我自己提出的(头脑风暴,Spitballin,无论你想称之为什么)。

我们已经看了几个内置的Oracle函数来获取我们正在寻找的百分比以及尝试使用正则表达式。 如果我可以点击谷歌并获得他们的一些搜索算法,我会。 显然我没有那么奢侈,必须自己设计。

regexp_count(table2_city,'(^| )'||REPLACE(table1_city,' ','|')||'($| )') city_score,
regexp_count(table2_city,'(^| )') city_max,

to_char((city_score/city_max)*100, '999G999G999G999G990D00')||'%' city_perc,

以上就是我的团队和我用来作为概念证明的东西。 我们只是从两个表中选择了这些值,并对这些列运行'regexp_count'函数。 以下是我们看过的一些其他功能:

SOUNDEX

REGEXP_LIKE

REGEXP_REPLACE

这些函数很棒,但我不确定它们是否可以在两个表之间的单个查询中使用以产生所需的输出。

另一个想法是我们可以创建一个Function(),它将我们想要用来比较的Address字段作为参数。 然后,该函数将在Table2中搜索最高可能的匹配,并将Table2中的Key2值返回给用户。

函数(Addr_Number,Addr_Street,Addr_type,City,State)RETURN table2.key2

例如,可能这样的'可以'工作:

Select tb1.key1, table2Function(tb1.Addr_Number, tb1.Addr_Street, tb1.Addr_type, tb1.City, tb1.State) As Key2
From Table1 tb1;

最后,只知道表1中目前有大约15k记录,表2中有20k记录。 同样......表1中的每条记录都需要根据表2中的每条记录进行检查,以确定是否存在匹配。

我听见了。 并提前感谢您的反馈。

使用UTL_MATCH包:

Oracle安装程序

CREATE TABLE Table1 ( Key1, Addr_Number, Addr_Street, Addr_Type, City, State, Zip ) AS
SELECT 1001, 148,  'Panas',     'Road',   'Robinson',    'CA', 76050 FROM DUAL UNION ALL
SELECT 1005, 110,  '48th',      'Street', 'San Juan',    'NJ',  8691 FROM DUAL UNION ALL
SELECT 1009, 8571, 'Commerce',  'Loop',   'Vallejo',     'UT', 83651 FROM DUAL UNION ALL
SELECT 1059, 714,  'Nettleton', 'Avenue', 'Vista',       'TX', 29671 FROM DUAL UNION ALL
SELECT 1185, 1587, 'Orchard',   'Drive',  'Albuquerque', 'PA', 77338 FROM DUAL;


CREATE TABLE Table2 ( Key2, Address, City, State, Zip ) AS
SELECT 'Ax89f', '148 Panas Road',    'Robinson',   'CA', '76050' FROM DUAL UNION ALL
SELECT 'B184a', '110 48th Street',   'San Juan',   'NJ', '08691' FROM DUAL UNION ALL
SELECT 'B99ff', '8571 Commerce Lp',  'Vallejo',    'UT', '83651' FROM DUAL UNION ALL
SELECT 'D81bc', '714 Nettleton Ave', 'Vista',      'TX', '29671' FROM DUAL UNION ALL
SELECT 'F84a2', '1587 Orachard Dr',  'Albuquerqu', 'PA', '77338' FROM DUAL;

查询

SELECT Key1,
       Key2,
       UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
         A.Addr_Number || ' ' || A.Addr_Street || ' ' || A.Addr_Type
           || ' ' || A.City || ' ' || A.State || ' ' || A.Zip,
         B.Address || ' ' || B.City || ' ' || B.State || ' ' || B.Zip
       ) AS Percent_Match,
       CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
              A.Addr_Number || ' ' || A.Addr_Street || ' ' || A.Addr_Type,
              B.Address
            ) >= 90
            THEN 1
            ELSE 0
            END
       +
       CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY( A.City, B.City ) >= 90
            THEN 1
            ELSE 0
            END
       +
       CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY( A.State, B.State ) >= 90
            THEN 1
            ELSE 0
            END
       +
       CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY( A.Zip, B.Zip ) >= 90
            THEN 1
            ELSE 0
            END AS Num_Matched
FROM   Table1 A
       INNER JOIN
       Table2 B
       ON ( SYS.UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
              A.Addr_Number || ' ' || A.Addr_Street || ' ' || A.Addr_Type
                || ' ' || A.City || ' ' || A.State || ' ' || A.Zip,
              B.Address || ' ' || B.City || ' ' || B.State || ' ' || B.Zip
            ) > 80 );

输出

      KEY1 KEY2  PERCENT_MATCH NUM_MATCHED
---------- ----- ------------- -----------
      1001 Ax89f           100           4 
      1005 B184a            97           3 
      1009 B99ff            95           3 
      1059 D81bc            92           3 
      1185 F84a2            88           3 

一些想法。

首先,您可能需要查看utl_match包: https ://docs.oracle.com/cd/E18283_01/appdev.112/e16760/u_match.htm

然后:你肯定会想要通过邮政编码和州先匹配。 也许在需要的地方添加前导零到邮政编码 - 虽然显然你的一个问题是拼写错误,而不仅仅是输入数据的不同包装。 如果邮政编码中存在拼写错误,你可以或多或少地处理它,但如果状态中的拼写错误真的很糟糕。

您可能希望按城市对相似性进行评分,但这通常无济于事。 例如,出于所有实际目的,纽约布鲁克林应该被视为与纽约纽约市相匹配,但是你无法在你的项目中做到这一点。 因此,我会非常重视城市的匹配。

关于地址类型的类似评论; 也许你可以创建一个具有等价的小表,例如Street,Str,Str。 或Lane,Ln,Ln。 但事实是,当他们给你一个地址时,人们往往不一致; 他们可能会将“幸运街”称为“Clover Street”,将“Clover Avenue”称为另一个来源。 因此,最好只比较街道号码和街道名称。

祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM