ひしだまの変更履歴

ひしだまHPの更新履歴。
主にTRPGリプレイの元ネタ集、プログラミング技術メモと自作ソフト、好きなゲームや音楽です。

SQL to AsakusaFW:join(GroupView)

2019-12-14 08:46:03 | PG(分散処理)

Asakusa Framework Advent Calendar 2019の14日目、SQLをAsakusaFWに変換するポイントについてです。

SELECT文のFROM句におけるテーブル結合はCoGroupMasterJoinUpdate演算子で実現できるのですが、キーのデータが偏っている場合は問題になることがあります。

例えばエラーコードをキーにエラーメッセージテーブルからメッセージを取得(結合)する(エラーコードの種類は少ない)場合です。
処理は結合キーの種類の数だけ分散して行われるので、種類の数が少ないと、データがそれぞれに集中してしまい、あまり分散しません。集中した件数によっては、CoGroup演算子の引数にListを使っているとメモリーが足りなくてOutOfMemoryErrorになることがあります。(引数をIterableにすれば回避できますが、処理内容によっては常にIterableに出来るとも限らないので)

特に、上記の例でエラーメッセージテーブルとの結合がLEFT JOIN(エラーコードがnullの場合は取得しない)とすると、ほとんどがnullのデータであれば、CoGroup演算子に渡るnullデータの所にデータが集中してOutOfMemoryErrorになりえます。(こういう事はよくありますorz)

こういった場合、Extract演算子(出力件数が常に1件ならUpdate演算子)とGroupViewを使う方法も考えられます。
ExtractやUpdate演算子は結合キーに依らず適当に分散されるので、エラーメッセージテーブルをGroupViewとし、エラーコードを元にメッセージを取得すればいいのです。
ただしこの方法は、上記の例の様にGroupViewのレコード件数が比較的少ない場合しか使用できません。(本来の分散処理では、必要なデータ毎に分散するのでそれぞれのデータは少なくなる想定ですが、GroupViewはそこに渡されるデータを全てメモリー上に乗せるので、これが多いとメモリーが足りなくなってしまう為)

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

SQL to AsakusaFW:join(MasterJoinUpdate)

2019-12-13 00:00:00 | PG(分散処理)

Asakusa Framework Advent Calendar 2019の13日目、SQLをAsakusaFWに変換するポイントについてです。

SELECT文のFROM句におけるテーブル結合は、基本的にCoGroup演算子で良いと書きました。
その理由は、SQLの結合では複数レコード出力される可能性があるからです。
が、逆に言うと、1レコードしか出力しないケース、例えば結合先(マスター側)のプライマリキーやユニークキーで結合する場合は、MasterJoinUpdate演算子(あるいはMasterJoin演算子)を使うことが出来ます。

AsakusaFW(特にAsakusa on Spark)では、MasterJoin系演算子はマスター側のデータ量に応じて効率の良い方式で実装されるので、CoGroupよりMasterJoin系演算子を使いたいものです。
(と言いつつも、CoGroupで統一した方が楽だし分かりやすいとも思うのですが^^;)

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

SQL to AsakusaFW:join(CoGroup)

2019-12-12 00:00:00 | PG(分散処理)

Asakusa Framework Advent Calendar 2019の12日目、SQLをAsakusaFWに変換するポイントについてです。

SELECT文のFROM句ではテーブルを結合できます。
これはAsakusaFWではCoGroup演算子で実現できます。

AsakusaFWでは基本的にCoGroupを使わずに他の演算子を使った方が良いとされていますが、SQLのJOINに関してはCoGroupにしておくのが無難だと思います。
というのは、JOINではキーによる結合結果として複数レコード出力されることがあり、AsakusaFWで結合時に複数レコード出力できるのはCoGroupだけだからです。

ONで「=」によってキー同士を比較しているカラムは、CoGroupの結合キーとして使用できます。
そしてCoGroupの本体では、2つの入力を二重ループで処理します。
INNER JOINの場合、双方に存在しているレコードを出力するだけなので簡単ですが、
LEFT JOINの場合は、左側に存在しない場合は右側を出力するので、そういった処理が必要となります。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

SQL to AsakusaFW:WHERE(2)

2019-12-11 00:00:00 | PG(分散処理)

Asakusa Framework Advent Calendar 2019の11日目、SQLをAsakusaFWに変換するポイントについてです。

SELECT・UPDATEやDELETE文のWHERE条件は、基本的にBranch演算子で実現できます
基本的にと言うのは、入力レコードのみで判断できるものを指しています。
そして、そうでないものとは、別レコードとの結合を必要とするもの、すなわちSQLのexistsやin-selectです。
col in (select c from t)という形式はexists (select 1 from t where c = col)に置き換えられるので、実質同じです。

そして、existsはMasterCheck演算子で実現することが出来ます。
ただし、null同士の比較がありうるのであれば、そのままでは出来ません。一番簡単な解決策は、マスター側のnullデータを事前に別の値に更新しておくことでしょうか。そうすればnullとその値の比較はマッチしないので、SQLと同じ結果になります。

あと、existsのwhereに等値「=」以外の比較がある場合は、MasterSelectionで実現できると思います。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

SQL to AsakusaFW:WHERE(1)

2019-12-10 00:00:00 | PG(分散処理)

Asakusa Framework Advent Calendar 2019の10日目、SQLをAsakusaFWに変換するポイントについてです。

SELECT・UPDATEやDELETE文のWHERE条件は、基本的にBranch演算子で実現できます。
SELECTの場合は条件を満たしたものだけ抽出、DELETEは逆に条件を満たしたものは出力しない。UPDATEは条件を満たしたものだけ更新し、満たさなかったものと後で合流(core.confluent演算子)します。

ここで重要なのは、NULLの扱いです。
SQLではNULLとの比較演算の結果はUNKNOWNとなり、UNKNOWNはFALSE扱いです。
例えば等値演算「a=b」の場合、AsakusaFWのオペレーターではa.equals(b)となるわけですが、aもbもNULLの場合、SQLはUNKNOWNすなわちFALSEになるのに対し、AsakusaFWではtrue(null同士なので等しい)になります。
(aかbのどちらかのみがNULLの場合は、SQLの「a=b」はUNKNOWNでFALSE扱いとなり、AsakusaFWでは単純に不一致でfalseとなるので、結果は一致します)
なので、AsakusaFWではSQL用の演算を行うユーティリティーを作り、それを呼び出すようにした方が良いと思います。

それでもさらに問題があって、それは否定演算NOTです。
SQLでは「NOT(a=b)」に対してaかbがNULLの場合、「NOT UNKNWON」→「UNKOWN」→「FALSE扱い」となります。なので、AsakusaFWに変換するときはNOTは要注意。単純にJavaの否定演算子「!」を使えばいいというわけにはいきません。
このSQLの「3値Boolean」をJavaで厳密に扱うなら、専用のクラスを作るべきかもしれません…。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする