goo blog サービス終了のお知らせ 

ひしだまの変更履歴

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

SQL to AsakusaFW:group by

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

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

SELECT文のGROUP BYのカラムは、集約Summarize演算子で行う場合は集約キー、Fold演算子で行う場合は@Keyに指定すればいいです。

SQLのNULL同士の比較はUNKNOWNでFALSE扱いとなりますが、確か、(例外的に)GROUP BYではNULL同士は等しいものとして扱われるはずです。これはAsakusaFWの挙動と同じです。


SQL to AsakusaFW:集約

2019-12-16 21:35:33 | PG(分散処理)

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

SELECT文は集約(SUMやCOUNT等)することが出来ます。
これは、AsakusaFWではSummarize演算子が該当します。
しかし、ここでもNULLの挙動は異なります。SQLのCOUNT(値)では、値がNULLだとカウントの対象外、SUM(値)では値がNULLだと合算の対象外です。が、Summarize演算子ではcountはnullでも関係なくカウントされ、sumはnullだとNullPointerExceptionが発生します。

このため、Summarize演算子を使わず、Fold演算子でnullチェックを行いつつカウント・集計を行う必要があります。
もしくは、NULLを0扱いしてよいのであれば、事前にUpdate演算子でnullを0に更新しておき、Summarize演算子に渡すということも出来ます。


SQL to AsakusaFW:join(null同士の結合)

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

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

SELECT文のFROM句におけるテーブル結合を実現する方法としてCoGroupMasterJoinUpdateExtract(+GroupView)演算子を使う方法を紹介してきました。
これらの方法に共通するSQLの問題点として、(WHERE条件の話でも出した)NULL同士の結合があります。
SQLではNULL同士の結合(「=」による演算)はUNKNOWNなのでFALSE扱い、すなわち結合しないのですが、AsakusaFWではnull==nullはtrueなので結合することになります。

大抵の結合ではマスターテーブルのプライマリキーに対して結合することになる(と思いたい)ので、プライマリキーならNOT NULLなのでこの問題を考える必要は無いのですが。

これを厳密に対処するなら、
CoGroup演算子の場合:渡ってきたデータの結合キー項目がnullかどうかチェックする
MasterJoinUpdate演算子の場合:MasterSelectionで結合キー項目がnullかどうかチェックする
GroupViewの場合:結合キー項目がnullだったらGroupViewから取得しない
のような処理を入れる必要があるでしょう。


個人的には、AsakusaFWの結合方法のオプションとして「null同士だったら一致しないものとして扱うモード」があると上記の問題の対処が楽になるなーと思うのですが、
しかしSQLに似せる為だけにそういうオプションを入れるのは微妙だとも思います^^;


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はそこに渡されるデータを全てメモリー上に乗せるので、これが多いとメモリーが足りなくなってしまう為)


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で統一した方が楽だし分かりやすいとも思うのですが^^;)