5

2 つの異なるソースからのダーティ データがあります。それらを一致させるためのベストプラクティスを探しています。データの例を次に示します。

Source1.Name                   Source2.Name
Adda Clevenger Jr Prep School  Adda Clevenger Junior Preparatory School
Alice Fong Yu Alt School       Alice Fong Yu Alternative School
Convent Of Sacred Heart Es     Convent of Sacred Heart Elementary School
Rosa Parks Elementary School   Rosa Parks Elementary School

人間は、これらの 4 つの例が理想的なあいまい一致と一致するはずであることがわかります。タイプミスやその他の小さなバリエーションを検出する従来のファジー マッチング用の優れたソフトウェアを自由に使用できます。しかし、このデータセットには、「Preparatory」->「Prep」などの略語を管理する約 12 のルールがあります。これらのルールをすべてクエリに取り込みたいと思います。(それから、より伝統的なあいまいさを個別に扱います。)

この要件を処理するためのよく知られた SQL パターンはありますか? 私の検索で例のロックを解除する魔法のキーワードを学ぶのと同じくらい簡単かもしれません. これは一種の「翻訳表」または「略語表」ですが、それらの用語は私が作成したものです。広く受け入れられている用語をまだ見つけていません。

概念的には、私の目標は次の素朴なクエリから始めることです。

/* This succeeds for 1 record and fails for 3 in the sample data set above. */
SELECT * FROM ...
WHERE Source1.Name = Source2.Name

次に、上記の目的の一致をすべて取得するものに変更します。入れ子になった REPLACE 関数をいくつか使って総当たりできると思います。

/* This works for the 4 samples given */
SELECT * FROM ...
WHERE 
  REPLACE( REPLACE( REPLACE( Source1.Name, 'Preparatory', 'Prep' ), 'Alternative', 'Alt' ), 'Elementary School', 'Es' )
  = REPLACE( REPLACE( REPLACE( Source2.Name, 'Preparatory', 'Prep' ), 'Alternative', 'Alt' ), 'Elementary School', 'Es' )

これはエレガントに感じません。一貫性のない略語を説明しているため、見苦しさが増しています (たとえば、'International' は 'Intl' の場合もあれば 'Int''l' の場合もあります)。また、省略形が重複している場合は特にスムーズではありません (たとえば、'Elementary School' -> 'Es' ですが、それ以外の場合は 'School' -> 'Sch')。

他の人はこれをどのように解決しましたか?

注:私はオラクルを使用しています。REPLACE ではなく REGEXP_REPLACE を使用する可能性があります。大文字と小文字の問題を避けるために、私は確かに UPPER (または LOWER) を使用します。しかし、それらの詳細は問題の核心ではありません。

4

1 に答える 1

1

一連の既知の翻訳がある場合は、これらをキャプチャする関数を作成できます。次に、この結果を返す仮想列をテーブルに作成できます。次に、仮想列を比較して、クエリを簡素化できます。

create or replace function abbr_replace ( str varchar2 )  
  return varchar2 deterministic as
begin
  return replace( 
                   replace( 
                         replace( 
                             replace(
                               replace( lower( str ), 'preparatory', 'prep' ), 
                                 'junior', 'jr'),
                             'elementary school', 'es'), 
                         'alternative', 'alt' ), 
                     'elementary school', 'es' 
                 );
end abbr_replace;
/

create table source1 (
  name         varchar2(100),
  replace_name varchar2(100) as ( 
      cast ( abbr_replace ( name ) as varchar2(100) ) 
    )
);

create table source2 (
  name         varchar2(100),
  replace_name varchar2(100) as ( 
      cast ( abbr_replace ( name ) as varchar2(100) ) 
    )
);

insert into source1 (name) values ('Adda Clevenger Jr Prep School');
insert into source1 (name) values ('Alice Fong Yu Alt School');
insert into source1 (name) values ('Convent Of Sacred Heart Es');
insert into source1 (name) values ('Rosa Parks Elementary School');

insert into source2 (name) values ('Adda Clevenger Junior Preparatory School');
insert into source2 (name) values ('Alice Fong Yu Alternative School');
insert into source2 (name) values ('Convent of Sacred Heart Elementary School');
insert into source2 (name) values ('Rosa Parks Elementary School');

commit;

select s1.name, s2.name
from   source1 s1
join   source2 s2
on     s2.replace_name = s1.replace_name;

NAME                                               NAME                                             
-------------------------------------------------- --------------------------------------------------
Adda Clevenger Jr Prep School                      Adda Clevenger Junior Preparatory School          
Alice Fong Yu Alt School                           Alice Fong Yu Alternative School                  
Convent Of Sacred Heart Es                         Convent of Sacred Heart Elementary School         
Rosa Parks Elementary School                       Rosa Parks Elementary School

注意すべき点がいくつかあります。

  • 関数を次のように宣言する必要があります。deterministic
  • これを使用するには、11g 以上である必要があります

より一般的なあいまい一致を探している場合、オラクルはレーベンシュタイン距離およびジャロ・ウィンクラー一致アルゴリズムを実装しています。これらは utl_match にあります:

select s1.name, s2.name, utl_match.jaro_winkler(s1.name, s2.name) jw
from   source1 s1
join   source2 s2
on     utl_match.jaro_winkler(s1.name, s2.name) > .9;

NAME                                               NAME                                               JW
-------------------------------------------------- -------------------------------------------------- --
Adda Clevenger Jr Prep School                      Adda Clevenger Junior Preparatory School           0.904
Alice Fong Yu Alt School                           Alice Fong Yu Alternative School                   0.925
Convent Of Sacred Heart Es                         Convent of Sacred Heart Elementary School          0.902
Rosa Parks Elementary School                       Rosa Parks Elementary School                       1.000

スクリプトはLiveSQLでも利用可能

于 2015-12-22T10:30:45.920 に答える