Distributed Control Break

まず始めに断っておきますが、このワードの発案は@marblejenkaさんによるものです。個人的には、言い得て妙だと思っています。この手の言葉の使い方のセンスはマーブル先生は時々天才な時があり、このワーディングもそれに属します。尚、社内では「この言い方は若干、一種の中二病的な側面もある」という意見のため、公式のドキュメントから削除されています。残念です。よってブログに残す。

まずもってControl Breakですが、COBOLの必殺技のひとつで最上位古代魔法(ハイ・エンシェント・ロア)のひとつに属します。JavaとかJavaとかJavaとか、な人たちにはちょっと意味がわからない感じになりますが、ある一定の処理の固まりを順におこなっている時に、なにかのタイミングで(大抵はキーの切り替え)で別の処理を一時的に行う(コントロールがブレイクする)ことを言います。

まず単純な例では、例えば、明細がダラダラある順編成ファイル(これも死語だが)を適当に伝票の単位で区切って伝票イメージをつくるときに頻繁に利用されます。各要素のキーを決めて、小計・中計を各項目毎に集計し、かつそれをレイアウト単位で整形するようなケースがこれにあたりますね。普通は、そのままではうまく行かないので事前にソートしたり、マージしながらキー順でそろえておくことが必要になります。実際、そうそう簡単な集計はあまりなく、かなりの例外処理がてんこ盛りになるので、うまく整理しないと大変なことになることが多いです。

普通にJavaだろうと、なんだろうと自分でカウンターうっておいて、状態を見ながらネスト処理すればコードには落とせます。ま、簡単に言えば、「制御が複雑なLoop文の塊」ということになりますね。

大抵の業務系SEの方は、まず間違いなく経験していると思いますが、いい加減に書くとバグの温床になりやすいアレです。普通は面倒だと、SQLのGROUP BYで逃げる。んでストプロに持ってきて、それでもパフォーマンスが出なくて、そもそもDBサーバーのスペックがですね、とかやり始めて、Indexがとか、非正規化がとかお茶を濁しにかかって、最後はお客さんに殴られるという例のアレです。

COBOLは言語レベルでこの制御がやりやすいようにサポートがされていて、多層ネストになってもかなり楽勝で制御できるし、(少なくとも他の言語よりは格段に)見通しも良いかと。このコントロールブレイクについては、使い方によっては現時点ですら簡単・最強のレイアウト編成手法の一つであることは間違いないでしょう。

これについては一言どころか、一晩語らせろというお父さんがゴマンということも良くわかっています、のでそういう人はブログでも書くように。ググればわかるように、実際に使われている以上にネット上の情報は少ないですね。

コントロール・ブレイクに限らず、70-80年代の枯れた技術で、もはやセオリーになっているにもかかわらず、ネット上の情報が少ないため、ロスト・テクノロジーになっているものが非常に多いです。お父さんたちは、「今時の若い者は・・・」とか説教たれる暇があったら、自分の技術をちゃんとネットに公開するように。別に一般に大受けする必要はないが、一部で確実に拾ってくれる人達はいるわけです。

閑話休題

というか、そもそも、今時こんなものを自作しないと駄目な言語が大杉というかですね・・・。実際の業務系のプロジェクトでは「あれば便利lib」の筆頭だったりするので、大抵の業務SI屋さんのよくできた標準ライブラリには実装されていることも多いです。特にレポートや帳票系では、俺様コントロールブレイクなフレームワークとか散見されます。とはいえ、Javaとかでオレオレコントロール・ブレイクなlibを見ると、これはこれでなぜか非常に残念な感じがするわけですが・・・使ったら異様に遅いとか、中途半端感満載です。

んで、Asakusa上でコイツはどうやったら良いか?という話があって、実はAsakusaではこれを比較的簡易に実装できます。コントロール・ブレイクを分散させるので、Distributed Control Breakですよ、と。言い方的に必殺技感が満載な感じですよ、と。以下各論点。

1 コントロールの処理は実は分散処理になじむ。
何を言ってんだ、お前は?とか言われそうですが、これは多分間違いないです。制御(コントロール)内部でのデータ操作は、基本的に相互に独立しており、同期を取る必要がない。これに加え、データの一様性が暗黙に想定されているため、分散処理されているデータ層へのアクセスも一様アクセスが仮定される。したがって効率が良い。たしかにキーのアンバランスは問題にはなるが、これは事前の調査次第の部分もあるし、わかっていれば対処もできる。(尚、この対処方法も既存のコントロールの効率化と同じだったりする。)原則データフローベースの非同期処理であり、非同期の最中は、状態はその内部に閉じていて、外部的には非決定的でよい。

しかも、大抵の分散系実装は普通に分散ソートも提供されることもおおいので、工夫をそればそのまま実行できる素地もある。なので、割と向いていますよ、と。

2. ただし単純なMapReduceには還元できない。
コントロール処理は、極論すると多層的なワードカウントでしかない。したがって理屈からいうとHadoopには合っているし、MapReduceに押し込めることはできると言えばできる。

ただし、普通にHadoopで書くと死にます。論理的な構成はミドル的にはK-Vの制御の外側に制御層を一層設ける手法に近い。IterativeにK-Vとかを処理していると、何かのタイミングで繰り返し制御を抜けたり、復帰したりする必要が必ずある訳で、その処理にあたる。普通にやると、外側からカウンター叩いたり、中で状態を持ち回ったり、識別フラグを擬似的に立てたりする感じになる。

もちろんネストを擬似的に並列的に”直列化”すればできるし、実際に手書きでガリガリ実装するのであれば、効率化を考えて、冗長的に多層ループを単ループに構成し直すことになります。ま、普通に考えると「やりたくないな〜」ということに落ち着きます。この辺のHadoopの使い勝手の悪さは、わりと半端ない感じなので、単ループの単純分散ならいいのですが、複雑なコントロールブレイクは、Hadoopで生実装すると、即死確定だと思います。なのでフレームワークで取り込むというのが筋でしょう。

3 あると強烈に便利
これはすでにCOBOLで証明されていると思います。言語レベルで透過的にコントロールの利用ができることは、かなり便利で品質もあがる。・・ただし、だからやっぱこれからはCOBOLでしょう!というのは、相当な勘違いなので病院にいってください。

この手の連続データの制御処理はCOBOLは、さすがに実装を含めた環境として、白眉の部分は未だにあります。が、それは業務系の処理をある程度想定した、「実装系業務フレームワーク」としての位置づけであり、汎用的なものではありません。なので、COBOLにむりやりオブジェクト指向いれたり、実装基盤から引きはがしてオープン化してみたり、むりやりMapReduceしたりするのは、生産性や実行効率性を逆に下げます。むしろ考え方を換骨奪胎して、別の形に昇華させるというの方向が本来は正しいです。(コンパイラがなんでもやればいい、という発想は一応却下でお願いします。)

4 DSL的にどう考えるか?
まずAsakusaですが、なんとデフォルトで準備されていたりします。
CoGroup演算子がこれにあたり、「複数の入力をキーでグループ化し、キーが一致する入力ごとのグループをまとめて操作する演算子です。」
http://asakusafw.s3.amazonaws.com/documents/0.2/release/ja/html/dsl/operators.html#id66
ただし、「非常に複雑な操作を表現できますが、コンパイラの最適化を適用しにくかったり、グループごとの大きさに制限があるなどの問題もあります。」(原文ママ
という感じです。

要するにあまり連発するな、と言っています。非常に残念な感じですが、世の中そんなもんです。

よく考えなくても、世の中でのコントロールブレイク的な処理の多さを考えれば、大抵の業務系の処理は、このCoGroupで済んでしまいます。実際某Prjでは一時期、「使い方がよくわからないので、全部CoGroupで実装しちゃいました」的な話もあったぐらいです。当たり前ですが、そうなると最適化が効かなくなので、まー非常にパフォーマンスはよろしくないです。

まーAsakusaのステマというわけではないですが、業務系をまじめに分散処理しようとすると、こういった形になった、ということは偶然ではありません。もちろん、インターフェイス的にCoGroupが最適か?という話は当然ありますし、今のところは最適とは言いがたいもの事実でしょう。というかこれはJavaという制約にかかわる部分もあるので、なんともいえませんが。

なので、業務処理を行うPrjに参加するよーん、というフレームワークな人や、多少なりとも世の中に役にたつDSLとか出したい、という人は、頭の隅にでも置いておくと役に立つかもしれません。
まー、そんな感じです。

取り急ぎ。