2014年振り返り

もう年が明けてますが、2014年について振り返っておきます。

  • スマフォ向けWebアプリを作った
  • アジャイルデータサイエンスの付録を書いた
  • fullbokをがっつり使ってみた
  • EMRを触った

ちなみに、去年は年末年始に仕事があってタイミングを逃して振り返りを書けませんでした。今年はその反省を活かして振り返りを書けて良かったです(今年も年末に仕事自体はしてたんですが、同僚のおかげで去年よりも忙しくなかったというのもあります。同僚の◯◯さん、ほんとありがとうございます!おかげさまで今年は嫁の実家に正月の挨拶に行けましたm(__)m)。

スマフォ向けWebアプリを作った

クライアント側はCreateJSを使ったCanvasベースのWebアプリで、サーバー側はNode.jsで、通信はSocket.IOみたいなものを1年ほどメンテしていました。どちらも他の方にベースを作ってもらったので私自身がスクラッチから作ったわけではないのですが、なるほどなーという感じでした。

クライアント側の開発にはMiddleman, Haml, SCSS, CoffeeScriptも使っていて、色々便利になってるなーという印象でした。まぁ、CoffeeScriptはあまり好きになれず、結局生成されたJS眺めてデバッグしてましたがw

当然実機のテストもするわけでiOSAndroidそれぞれテストして複数端末対応の厳しさを実感したりしました。iOS系はブラウザの挙動自体は安定してたんですが、端末によってアスペクト比が違ったり、iOSのバージョンによってSafariの描画領域のサイズが違ったり、横向きの場合のどうするかとか色々悩まされました。Androidに関しては標準ブラウウザがまともに動かなかったり、端末によって利用できる音声フォーマットに差があったり、そもそもスペックが低くてfpsの調整したりとかしてました。

インフラ構築/運用の部分もメンテしていて、やはり他の方にCloudFormationのテンプレートを作成してもらったのですが、これまた便利だなーという感じでした。S3やCloudFrontの使い方についても覚えたりした感じで、一部は会社のブログに書いたりしてました。

アジャイルデータサイエンスの付録を書いた

縁あってアジャイルデータサイエンスの付録を書かせていただきました。
「アジャイルデータサイエンス」の付録を寄稿しました | Developers.IO

付録を書く上で本文を原著で読んだのはいい経験でした。仕事上、英語のドキュメントをちょこっと読むことはありますが、あれだけまとまった分量のものを読んだ経験はなかったので、読もうと思えば読めるという自信?を持てました。まぁ、面倒なのでほぼ辞書は引かずに読める範囲をフィーリングで読んでたので理解度は怪しいですが(^_^;)一応、社内向けにConfluenceに要約書いたり、Pigのコードについても読み込んだりして、色々勉強になりました。

付録のFluentdに関しても使ったことはあっても特に詳しいわけではなかったので、ドキュメントをがっつり読んだりソースをちょこちょこ読んで理解が深まって良かったです。あとFluentdはほんとネット上のリソースが充実しているので、何を書いたものか悩ましかったりしました。

fullbokをがっつり使ってみた

負荷試験用にJMeterクラスタを構築できるfullbokというツールがあるんですが、こちらを使ってCloudFrontへ負荷試験やったりしました。
CM re:Growth 2014 Tokyoで負荷試験ツールであるfullbokについて話しました #cmdevio | Developers.IO

OriginがAMS(Adobe Media Server)でHDSとかHLSについて調べたりしました。あと、CloudFrontに関してはかなり詳しくなった気がします。

EMRを触った

Hadoop好きと名乗ってたりするのですが、おかげさまでEMRの導入支援案件をやったりしました。あと、何度かHadoop関係の勉強会に参加したりしました。

その割にはHadoop関連のブログは上の5本しか書いていないわけで、今年はもうちょっと書いていこうと考えています。

前述は Groveの温度センサーをEdisonにつないでみた | Developers.IOというエントリーを書いた際に思ったことなんですが、やはりHadoop関係は中途半端に知っているだけにブログを書きづらかったというのがありました(ブログのエントリー数が少ないのはそもそも仕事の忙しさに負けているというのもあるのですが)。ですが、全くHadoopやEMRを知らない人向けにブログを書くのは、それはそれで意味があることかなーと思い、今年はHadoopやEMR関連のエントリーを書いていくつもりです。

まとめ

振り返ってみると今年も色々と勉強したなーと思います。今年は定年(35歳)になりますが、おかげさまで毎年成長を感じられていますし、今後も学びたいことだらけだったりします。目標という意味では毎年思うのですが、今年こそはもうちょっとアウトプットを増やせるといいかなーと思ってます。

Linuxのプロセス名とは

ちょっと前の話なんですが、職場でZabbixの監視にプロセス名とコマンドラインが使えて、psコマンドでコマンドラインはとれるけどプロセス名はどうするんだとなりました。結局、同僚から/proc/${pid}/statusに入ってるNameでいいと聞いたのですが、もっと簡単に取れる方法はないのでしょうか。。ありました!。ちなみにWindowsはwmicコマンドで両方一気に取れました。

Linux

2014-08-11訂正: psコマンドでまとめて取れました。 @heroweenさんありがとうございます!

ps axww -o comm,args

まずはコマンドライン。psコマンドで取得できます。

ps auxww | grep キーワード

次にプロセス名は/procで確認できましたが、psコマンドと同様にキーワードから取得する方法はないんでしょうか。。

grep Name /proc/プロセスID/status

Windows

wmicコマンドでプロセス名とコマンドラインが一気に取れます。

wmic process where "name like \"%キーワード%\"" get name,commandline

実践 機械学習 〜レコメンデーションにおけるイノベーション〜

実践 機械学習 〜レコメンデーションにおけるイノベーション〜を読みました。60ページぐらいで1時間もかからず読むことが出来ます。内容は機械学習アルゴリズムの紹介ではなく、機械学習によるレコメンデーションの全体像を掴むことが出来るような内容でした。機械学習とはどういうもので、実際に構築するにはこういう要素が必要で、チューニングにはこういう手法があるといった内容です。そのため、機械学習に関する予備知識がなくともざっくり読めるのではないかと思います。

  • 機械学習とレコメンデーションとは
  • 正確さと開発コストのトレードオフを意識する必要がある。
  • 言動ではなく行動が重要。好みなどを回答するのは一部のユーザーであり、既に偏っている。そうではなくて、各ユーザーの実際の行動(参照ページ、リンクのクリック、スクロールなど)が重要であり、それらの情報を収集できるようにWebサイトを作っておく必要がある。
  • 履歴マトリクス、共起マトリクス、インジケーターマトリクス
    • インジケータマトリクスはMahoutのRowSimilarityJobを利用して作成する
  • レコメンデーションエンジンの実装にSolrを利用する。
    • ドキュメントのフィールドに共起インジケータを追加することでSolrクエリの結果をそのままレコメンデーションデータとして利用できる。
  • 音楽レコメンダーを例に実装の詳細について解説
  • ディザリングとアンチフラッド
  • マルチモーダルとクロスレコメンデーション

原書であるPractical Machine Learningも入手していたんですが、結局読まずにいたら日本語訳版も無料で公開されたので読んでみました。ありがたいはなしです。あと、先日のHadoop Conference Japan 2014でも本書に関するセッションがあったようです。動画とスライドが公開されています(このセッションも興味があったんですが、Prestoの方に参加しました)。

個人的にヒットしたのはどこまで正確さを求めるかという部分でした。

そのための重要なスキルは、「良いというの は、どのくらい良いのか?」という質問に答えることができる、というスキルです。

最近、仲間内でMahoutイン・アクションを読み合っているのですが、そこでも正確さの話が出ていて、その値はいいのか悪いのかみたいな話がありました。本書を読んで、自分自身の過去の経験も振り返り、正確さは本質ではないのだなーと思いました。結局、どれほど値が良くても、それをビジネス的に活かす部分まで繋げられていなければ、単に値がいいけどそれで?という話になるなーと(もちろん、モデルができていて、正確さを1%向上すると利益が0.5%向上するみたいなケースは絶対額にもよりますが正確さを上げることにリソースを割いた方がよいと思います)。

あと、RowSimilarityJobでインジケータマトリクスを作成するには「ログの対数尤度比検定(log likelihood ratio test = LLR)」を利用すると書いてあったのですが、これは具体的にはRowSimilarityJobクラスを実行する際の引数として--similarityClassnameオプションを指定する際にDistributedLoglikelihoodVectorSimilarityクラスを指定するということを指すようです。最初にmahout 0.5のRowSimilarityJobのJavaDocを読んだ際に--similarityClassnameオプションを見落としてて、どうやってインジケータマトリクスが作れるのか理解できずに1時間ほどググったりして悩んでましたorz(最終的にこのMLにたどり着いて複数実装がありそうなことに気づき、ローカルに入れていたmahoutのソースを確認したらDistributedVectorSimilarityインタフェースの実装が大量に見つかりました。。)

ちなみに、本書を読んで一番良かったのは、このブログを書くために色々調べたり、振り返ったことだと思います。やはりブログを書くのは重要ですねw

はてなブログに引っ越しました

いまさらなんですが、はてなブログに引っ越しました。
http://n3104.hatenablog.com/

何回か書いてみてからどうするか決めれば良いと思っていたので、実際には3月末からはてなブログ側で書いています(といっても、この日記を書く時点で3エントリーしかありませんが)。とりあえず暫くははてなブログで書いてみる予定です。

RDS for MySQLでEvent Schedulerを利用する

結論から書くと、Parameter Groupsでevent_schedulerを[ON]にするだけです。
http://stackoverflow.com/questions/14940910/creating-mysql-events-in-amazon-rds

event_schedulerのデフォルトは[engine-default]になっていました。この状態だと[OFF]扱いのようです。

mysql> SHOW GLOBAL VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | OFF   |
+-----------------+-------+
1 row in set (0.01 sec)

Event Schedulerはその名の通り、SQLを任意のタイミングで実行できるスケジューラーです。こんな機能あるんですね、知りませんでした(゚д゚)!
http://dev.mysql.com/doc/refman/5.6/en/events.html

cronのような一定間隔の実行も出来ますし、特定の日時に一回だけの実行もできます。どんな感じで設定するかはCREATE EVENT Syntaxを見るとイメージがわくと思います。 http://dev.mysql.com/doc/refman/5.6/en/create-event.html

ちなみに、event_schedulerがOFFでもイベント自体の登録は可能でした。あと、Event Schedulerは専用のスレッドが動作するので SHOW PROCESSLIST\G で存在を確認できたりします。
http://dev.mysql.com/doc/refman/5.6/en/events-configuration.html

既に登録済みのイベントは SHOW EVENTS\G で確認したり出来ます。 http://dev.mysql.com/doc/refman/5.6/en/show-events.html

参考
[MySQL] イベントスケジューラの起動と停止 - グローバル変数event_scheduler | idocsq.net

※一部の方へ
あっちのブログに書くのは結構大変なので、さらっと書けるんだけどEvernoteに貯めとくのもな~という内容はこちらのブログに書いていくつもりです。

データサイエンティスト養成読本を読みました

データサイエンティスト養成読本 [ビッグデータ時代のビジネスを支えるデータ分析力が身につく! ] (Software Design plus)

データサイエンティスト養成読本 [ビッグデータ時代のビジネスを支えるデータ分析力が身につく! ] (Software Design plus)

読みました。発刊当初は興味があったのですが、結構内容が重いかと思って読んでいませんでした。やはりデータ分析周りは興味があるので思い切って読んでみたら、思ったよりさらっと読めた感じですw以下が感想になります。

  • 全体的にデータ分析の流れや考え方について記述された記事が多い。RやPythonという言語の違いや、記事の切り口によって説明する角度が異なるだけなので、データ分析の流れは基本的に変わらないのだと理解した。
  • 特集2の2は前職の広告配信システムを開発していた頃を思い出す部分があり懐かしかったw
  • この本を読んですぐに実務に使えるという本ではなく、あくまでもデータ分析周りの地図を作るために利用する本だと思った(そもそも1冊読むだけで実務ができるわけがないですがw)。記事によって参考文献も書かれていてよかった。

ちなみに、書かれている内容について全て理解できているわけではなくて、概要レベルでつかめたものばかりです。そもそも全部理解できるなら読む必要ないですしwあとは、前職自体からデータ分析周りについて勉強を始めましたが、やっと雰囲気はつかめるようになったかなという感じです。去年の11月に転職してから忙しすぎて本を読めたり出来ていなかったのですが、今後はデータ分析周りも含めて勉強を再開していければと考えています。RやPythonアルゴリズム周りについても気長に取り組んでいくつもりです。

Fork/Join Framework についてちょろっと調べてみた

同僚と Fork/Join Framework について話す機会があり、ちょっと気になったので調べてみました。ちなみに、ソースは jdk1.7.0_25 です。

native なのか Java なのか?

native とかは使わないで普通に Java の Thred クラスを利用して実装しているようでした。そのように判断した理由は以下の通りです。

  • ForkJoinWorkerThread 自体は Thread クラスを継承している
  • ForkJoinPool#invoke から RecursiveTask#compute までのソースを見た感じ、普通に Java のコードだった
ForkJoinWorkerThread の生成タイミング

ForkJoinPool#invoke の中で ForkJoinWorkerThread を生成しているみたいでした。

registerWorker(ForkJoinWorkerThread) : int - java.util.concurrent.ForkJoinPool (3 matches)
	ForkJoinWorkerThread(ForkJoinPool) - java.util.concurrent.ForkJoinWorkerThread
		newThread(ForkJoinPool) : ForkJoinWorkerThread - java.util.concurrent.ForkJoinPool.DefaultForkJoinWorkerThreadFactory
			addWorker() : void - java.util.concurrent.ForkJoinPool
				signalWork() : void - java.util.concurrent.ForkJoinPool
					addSubmission(ForkJoinTask) : void - java.util.concurrent.ForkJoinPool
						invoke(ForkJoinTask)  : T - java.util.concurrent.ForkJoinPool

ちなみに、 ForkJoinPool#registerWorker まで書いているのはこの中で ForkJoinPoolクラス の workers フィールドに新しく生成した ForkJoinWorkerThread のインスタンスを代入しているように見えたためです。なお、 workers フィールドの初期化は ForkJoinPool のコンストラクタの中で行なっているようで、引数なしのコンストラクタを利用した場合はプロセッサ数の 2 倍の数を生成するようでした。

    public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        Thread.UncaughtExceptionHandler handler,
                        boolean asyncMode) {

// ... 中略 ...

        // initialize workers array with room for 2*parallelism if possible
        int n = parallelism << 1;
        if (n >= MAX_ID)
            n = MAX_ID;
        else { // See Hackers Delight, sec 3.2, where n < (1 << 16)
            n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8;
        }
        workers = new ForkJoinWorkerThread[n + 1];

引数なしのコンストラク

    public ForkJoinPool() {
        this(Runtime.getRuntime().availableProcessors(),
             defaultForkJoinWorkerThreadFactory, null, false);
    }
ForkJoinPool#invoke から RecursiveTask#compute の呼び出し階層

以下の様な感じで RecursiveTask が呼ばれてました。 work-stealing の実装部分は読んでいませんw

compute() : V - java.util.concurrent.RecursiveTask
     exec() : boolean - java.util.concurrent.RecursiveTask
          doJoin() : int - java.util.concurrent.ForkJoinTask
               join() : V - java.util.concurrent.ForkJoinTask
                    invoke(ForkJoinTask)  : T - java.util.concurrent.ForkJoinPool

ExecutorService との違いは?

2013-07-25 追記

  • 最初にいきなり native なのか Java なのかと書いてありますが、これは全く予備知識がなかったためです。ただ、たくさんのスレッドを利用するのだろうなという漠然としたイメージしかなく、同僚が native 使ってるかもと言ってたのでそこから調査しました。
  • 分割統治法を全体としており、再帰処理で分割する、かつ、 fork で並行処理するので幅優先探索を利用する処理に向いてそうという理解です。
    • 深さ優先だとシングルスレッドと変わらないはずなので。
    • 手軽に使えるのはいいですが、計算量の事前計算が必要だとは思いました。結局、タスクが大量に生成されるわけで、末端まで行かないとタスクが減り始めないので。
      • そういう場合は、プロセスで利用可能なメモリサイズを確認した上で、処理可能なサイズになるまでは自前でタスク分割と実行の制御を入れればいいんでしょうが。
  • MapReduce は分割統治法には向いてないのかなとは思いました。まぁ、処理時間を気にしなければ計算量を無視出来るオーダーが増えるので、そもそも比較すること自体がナンセンスですがw
    • 結局、 MapReduce って fork & join の深さ 1 ということなので、深さが 2 以上だとジョブ自体のループを実装することになり、面倒くさそうだなぁと。
  • 再帰なのでスレッドのディスパッチコストは低いのかなと思います。結局、末端からタスクが処理されるので、親は fork した子の処理が終わるまでスレッドの割り当てが戻ってこないので。 I/O 待ちでスレッド同士を切り替えるみたいな動きはあまりないという理解です。