0

最初のテーブルの文字列が 2 番目のテーブルの長い文字列の一部に含まれているかどうかに基づいて、2 つのテーブルを結合しようとしています。SAS で PROC SQL を使用していますが、SQL クエリの代わりにデータ ステップを使用することもできます。

このコードは小さなデータセットでは問題なく動作しますが、大量の比較を行う必要があるため、すぐに行き詰まります。単純な等値チェックならいいのですが、index()関数を使わないと大変です。

proc sql noprint;
  create table matched as
  select A.*, B.* 
  from  search_notes as B,
        names as A
  where index(B.notes,A.first) or 
        index(B.notes,A.last)
  order by names.name, notes.id;
quit;
run;

B.notes は 2000 文字 (完全に入力されている場合もあります) のテキスト ブロックであり、A の姓または名のいずれかを含む結果を探しています。

A のすべての行と B のすべての行を既に比較する必要があるため、2 つのステップで実行しても速度の利点は得られないと思います (名前と姓の両方をチェックすることはボトルネックではありません)。

実行するとNOTE: The execution of this query involves performing one or more Cartesian product joins that can not be optimized.、ログに記録されます。A=4000 観測と B=100,000 観測で実行すると、約 1000 の一致を生成するのに 30 分かかります。

これを最適化する方法はありますか?

4

3 に答える 3

0

データにはデカルト積が最適かもしれませんが、ここで試してみてください。私がやっていることは、データ ステップで CALL EXECUTE() を使用して、ステップ マッチングをデータ ステップに構築することです。これは、各テーブルを 1 回走査するだけでよいことを意味します。ただし、書き込みデータ ステップには 4000 の IF/THEN 句があります。これを行うと、サンプル データのランタイムが 55 秒から 40 秒に短縮されます。この比率が維持される場合、これは 30 分から約 24 分短縮されます。

この質問は開いたままにします。誰かがもっと良い方法を思いつくかもしれません。

%let n=50;
data B;
format notes $&n..;
choose = "ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
do j=1 to 9000000;
    notes = "";
    do i=1 to floor(5 + ranuni(123)*(&n-5));
        r = floor(ranuni(123)*62+1);
        notes = catt(notes,substr(choose,r,1));

    end;
    output;
    drop r choose i;
end;
run;

data a;
choose = "ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
format first last $2.;
do i=1 to 62 by 2;
    first = strip(substr(choose,i,1));
    first = catt(first,first);
    last =  strip(substr(choose,i+1,1));
    last = catt(last,last);
    output;
end;
drop choose ;
run;

proc sql noprint;
  create table matched as
  select A.*, B.* 
  from  B as B,
        A as A
  where index(B.notes,A.first) or 
        index(B.notes,A.last)
  order by B.notes, a.i;
quit;

options nosource;
data _null_;
set a end=l;
if _n_ = 1 then do;
    call execute("data matched2; set B;");
    call execute("format First Last $2. i best.;");
end;

format outStr $200.;
outStr = "if index(notes,'" || first || "') or index(notes,'" || last || "') then do;";
call execute(outStr);

outStr = "first = '" || first || "';";
call execute(outStr);
outStr = "last = '" || last || "';";
call execute(outStr);
outStr = "i = " || i || ";";
call execute(outStr);
call execute("output; end;");

if l then do;
    call execute("run;");
end;
run;

proc sort data=matched2;
by notes i;
run;
于 2013-09-10T01:28:58.057 に答える