イクジニアブログ

育児 + エンジニア = イクジニア

Cloudera World Tokyo 2015でLTしてきた

やはり、新しい職場に慣れるには時間かかるなーって感じているにいやんです。こんばんわ。

さて、職場変わったばかりなのですが、ClouderaWorldTokyoでLTしてきました。

最近は色々なとこで発表をしていきたいなーって思っていて、申し込んだらまさかの当選&LT1番手・・・

いやー、さすがに誰かの話をちょっと聞いてから話したかったですね・・・

1番手は場の空気も微妙なので、ちょっと緊張しましたよ。話した内容はこのブログで過去に書いた記事の寄せ集めだったのですが、そこそこ反応は良かったのかなと思います!

www.slideshare.net

LTの後は主にSparkの話を聞いていたのですが、やはり今年はSparkですねー。

kafka,sparkを組み合わせた、リアルタイム処理基盤はこれからデファクトスタンダードになっていきそうです。

今のうちに色々知っておかないとですね!

楽天から去ることになりました

毎日コーヒーが欠かせないにいやんです。 こんばんわ。

先月末で、6年半ぐらいお世話になった楽天を離れる事になりました。

入った初日は腕を怪我していて、片手しか使えない状態という、ひどい印象で入ったのですが、6年以上もの間契約を続けてくれた楽天には本当に感謝です。

元々Javaエンジニアとして入り、最初はseasar2使ってAPIやBatchの開発を行っていましたが、途中からphpperlもやらしてもらい、Hadoopを使うようになり、PMを任され、Scrumを実践し、Rubyに出会い、OSSにコミットするという経験も積み、今まで経験した現場の中では1番自分の成長を感じれた現場であったと思います。

楽天ではパートナーという立場であったのに関わらず、リーダーを任せてもらい、素晴らしい仲間とも出会い、かなり自分の好きなように仕事も進めさせてもらっていて、こんなにいい現場はないのじゃないかと思っていました。

ただ、フリーランスという立場での成長に限界を感じ始め、今後の自分のキャリアのためには正社員として、どこかの会社で働いた方がいいかなぁという思いが出てきたので、思い切って転職をする事になりました。 (正社員の肩書って以外と大事なのですねと痛感する事が多くて・・・)

ビックデータが扱えて、兼業OKで、そこそこ給料もらえて、家から近くて、私服OK・・・って考えると、そんな会社片手で収まるぐらいしかなかったのですが、なんとかその中からお声がかかり、今月からは新たな職場で働いています。

今までとかなり勝手が違うので、慣れるまで色々大変そうですが、刺激の多い現場なのでなんとか頑張っていきたいと思います。

YAPC::Asiaに参加してきました

寝不足気味のにいやんです。こんばんわ。

最近毎朝娘が5時台から泣き始めて、全然寝てくれなくて・・・
なかなかまとまって睡眠が取れません
それなのに明日は6時半出社とか・・・   

さてさて、毎年のお楽しみYAPCに参加してきました!!
やはりYAPCは楽しいですねー。
今まで参加したカンファレンスの中で1番好きです。
それなのに、今年が最後だなんて・・・ToT

今回はいくつか聞いた話の中から気になったものをかいつまんで

◾️EffectiveES6
Javascriptの新しいバージョンが今年出たので、その概要の説明でした。  
classが出来たよ  
IE11では使えないのでBabel使いましょう  
継承できるようになった  
変数の宣言にlet,const追加された   
組み込みクラスでmap,set使えるようになった  
シャローコピー出来るようになった  
など、まあ他の言語では当たり前だったのですが、当たり前の事が当たり前に出来るようになったという印象ですね!  
これだけの機能が増えればCoffeeScriptとか使わないでいけそうですよね!  
ちょっとJavaScript触りたくなりましたよ。

◾️Perlで学ぼう!文系プログラマのための、知識ゼロからのデータ構造と計算量  
Cを使って変数を宣言したときのどのようにメモリが使われるか。    リスト使いたいとき連続したメモリ領域取れないときは線形リスト使ってごにょごにょ。    など、メモリの使い方の基本から  
2分木の話  
BTreeの話  
B+Treeの話  
まで、わかりやすいイラストつきで解説してくれました。  
私も文系ですが、ちょっとBTree分かった木がしましたよ!いや、気がしましたかw  

◾️我々はどのように冗長化を失敗したのか   
redisやmysqlをどうやって冗長化させようとして、なんで失敗したかという話  
redisはセンチネルとconsul使って冗長化(センチネルだけでいけると思うけどな・・・)  
mysqlはmysqlfailover使って冗長化  
みたいな話でした。  
mysqlfailoverは知らなかったのでちょっと調べてみたいですね!  
これがうまく使えれば、Hiveのメタデータ持ってるmysqlとか冗長化出来るかもしれない!  

◾️MySQLで2億件のシリアルデータと格闘したチューニングの話  
2億件データ入れないといけないのに用意されたサーバがあまりにしょぼくて泣いたって話。  
/tmpがorder_byすると枯渇するとか  
count帰ってくるのに1分以上かかるとか  
3億件データ入れるのに70時間かかったとか  
うんうん。私が今の現場に入ったとき最初の仕事がこんなんでした・・・  
で、あまりにつらいので、どうにかこうにかしたんだよなぁ・・・ 懐かしい。  
innodb_buffer_pool多めに取りましょうとかほんとそうですよね!!  

他にもLT聞いてげらげら笑ったり、当日まで話す内容がTBDだったMatzの話聞いたりとか、昔の会社の同僚にあったりとか、楽しい2日間でした!

また来年もうっかり開催されないかなぁ〜・・・

PrestoのGUIが便利な件

最近ハイボールにはまっているにいやんです。こんばんわ。

ビールももちろん美味しいですが、こんな暑い日はキーンと冷やしたハイボールも美味しいですよね! ビールよりもカロリー少ないし、がぶがぶ飲みたい時にはハイボールですね。

さて、Prestoのドキュメントにはあまり(まったく?)書かれていないですが、実はGUIが用意されています。
GUIへのアクセスはprestoが動いてる状態で以下のURLへ

http://prestohost.co.jp:8080/

イメージ f:id:nii_yan:20150727215733p:plain

このGUIではどんなクエリを投げたか確認出来て、クエリ毎には実行計画や実行にかかった時間など確認出来ます。
クエリが失敗した際はエラーログも確認出来るので、GUIを見れば結果の確認はほぼOK。
TimeLineも見れるので時間のかかるクエリを確認したい際など便利ですよね。

ただこのGUI1点残念なのが、クエリを実行した時間がぱっと見でわからないのですよ・・・
一応実行したクエリのIDに時間が入ってるので、それ見ればわかるのですが、UTC時間なので、日本時間にするには9時間足して・・・などと、非常にわずらわしいのです。

そこで、せっかくPrestoはOSSなので、自分で時間を追加してビルドしてしまいましょう。
時間の表示の仕方は実はとても簡単で、

▪️Prestoのソースをcloneしてローカルに持ってきて

 0.112だったら以下のように
 git clone -b 0.112 https://github.com/facebook/presto.git
 (バージョン指定しないと、まだリリースされてないソース取れちゃうので注意)

▪️presto-main/src/main/resources/webapp/index.htmlを開いて143行目ぐらいから以下のソースを追加
stateの変数に値を突っ込んでるあたり

        if (query.state == 'FINISHED' || query.state == 'FAILED') {  
             var fmtFunc = d3.time.format("%Y-%m-%d %H:%M:%S");  
             state += " (" + fmtFunc(new Date(query.endTime)) + ")";  
         }  

▪️あとはmvn clean install -DskipTestsしてビルド!

そうするとpresto-main-0.XXX.jarが出来上がるので、prestoをインストールしたディレクトリのlibしたにぽいって突っ込んであげればあら完成!

以下のようにFINISHEDなどのstateの後ろに時間が表示されるようになりました!
f:id:nii_yan:20150727221317p:plain

これは便利だーって思ってprestoにプルリク出したら、index.htmlはもう情報いっぱいあるからこれ以上だすなと言われてちょっと悲しかったのは内緒ですw
ひとつもぐったquery.htmlに追加した分はマージされました。よかった。

ベビーカー用 おすすめ虫除けネット

青信号でベビーカーを押していたら、車に轢かれそうになったにいやんです。こんばんわ。

完全に信号無視で突っ込んできた車がいまして、後ろを歩いてた人が「あぶない!」って叫んでくれたので気づけましたが、もし気づいてなかったらと思うと・・・

青信号でも安心してはいけないですね・・・
何もなくてよかった。

さてさて、最近暑くなってきましたね。
そこでやはりみなさん気になるのが蚊ではないでしょうか?
赤ちゃんはただでさえ蚊にさされやすいと言われています。

そこで、虫除けをぶら下げたり、虫除けスプレーをつけたりと色々対策をしていると思いますがやはり、それでもちょっと心配がありますよね。

そこで、我が家ではベビーカーにネットをつけてしまっています。 UVカットもできるので一石二鳥。 ネットをつけても赤ちゃん側からこちらを見る事はできるので、赤ちゃんも安心です。

我が家はベビーカーにピジョンのランフィを使っているのですが、この虫除けネットを使っています。

ランフィにかぶせるときはちょっときつめなのですが、その分虫も入ってきにくいと思いますし、持ち運び用の小袋もついてるので、使わないときはその袋に入れてベビーカーの下などに入れておけば持ち運びも楽ちん。

ちょっと公園に行った際など重宝します。

さらに、このネットは柄も選べるのが嬉しいですね。

ランフィにかぶせた際は以下のような感じになります。 f:id:nii_yan:20150713223925j:plain

花柄がよい感じです。

これに加えて、以前に紹介した ピジョン ランフィに合うレインカバー - イクジニアブログ も一緒に持ち運べば、雨にも虫にも対応出来るので、かなり安心になるかと。

みなさんも虫除けネット検討してみてはいかがでしょう?

CDH5.4 Hiveでwhere句が効かない現象について

うるう秒が迫ってきてビクビクしているにいやんです。こんばんわ。

とりあえず、うるう秒の時はHadoopクラスタ止めておくかな、どうしよかな・・・

前回CDH5.4でカラムずれが起きるバグの事を書いたのですが、同じようにleft outer joinを使った際にwhere句が効かないというか、where句が代入になるというか、なんといえば良いかわからないバグに遭遇したので、まとめてみました。

以下のような4つのテーブルを作成します。

create table t_1 (
aid int,
bid int,
t_1name string);

create table t_2 (
aid int,
bid int,
t_2name string);

create table t_3 (
aid int,
bid int,
t_3name string);

create table t_4 (
aid int,
bid int,
t_4name string);

t-1からt-3までには以下のデータを

1       2
1       2
1       2

t-4には以下のデータを入れます

1       2
1       2
1       2       moge

それで以下のSQLでselect

select
  d.aid,
  d.bid,
  d.t_4name
from t_1 a
left outer join
  t_2 b
on 
  (a.aid = b.aid and b.t_2name = "test")
left outer join
  t_3 c
on
  a.bid = c.bid
left outer join
  t_4 d
on
  a.aid = d.aid
where
  d.t_4name = "hoge";

d.t_4name = "hoge"にはどのデータもひっかからないので、このselect文の期待値は何も表示されないですが、このSQLの結果は・・・・

1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge
1       2       hoge

hoge キタ━━━(゚∀゚).━━━!!!

d.t_4nameに入ってるデータは「moge」なのですが、なぜかそれが「hoge」にかわり、結果が返されました・・・orz

explainも取ってみたいのですが、以下のようになってました。

STAGE DEPENDENCIES:
  Stage-8 is a root stage
  Stage-6 depends on stages: Stage-8
  Stage-0 depends on stages: Stage-6

STAGE PLANS:
  Stage: Stage-8
    Map Reduce Local Work
      Alias -> Map Local Tables:
        b 
          Fetch Operator
            limit: -1
        c 
          Fetch Operator
            limit: -1
        d 
          Fetch Operator
            limit: -1
      Alias -> Map Local Operator Tree:
        b 
          TableScan
            alias: b
            Statistics: Num rows: 1 Data size: 15 Basic stats: COMPLETE Column stats: NONE
            Filter Operator
              predicate: (t_2name = 'test') (type: boolean)
              Statistics: Num rows: 0 Data size: 0 Basic stats: NONE Column stats: NONE
              HashTable Sink Operator
                keys:
                  0 aid (type: bigint)
                  1 aid (type: bigint)
                  2 aid (type: bigint)
        c 
          TableScan
            alias: c
            Statistics: Num rows: 1 Data size: 15 Basic stats: COMPLETE Column stats: NONE
            HashTable Sink Operator
              keys:
                0 _col1 (type: bigint)
                1 bid (type: bigint)
        d 
          TableScan
            alias: d
            Statistics: Num rows: 1 Data size: 19 Basic stats: COMPLETE Column stats: NONE
            HashTable Sink Operator
              keys:
                0 aid (type: bigint)
                1 aid (type: bigint)
                2 aid (type: bigint)

  Stage: Stage-6
    Map Reduce
      Map Operator Tree:
          TableScan
            alias: a
            Statistics: Num rows: 0 Data size: 15 Basic stats: PARTIAL Column stats: NONE
            Map Join Operator
              condition map:
                   Left Outer Join0 to 1
                   Left Outer Join0 to 2
              keys:
                0 aid (type: bigint)
                1 aid (type: bigint)
                2 aid (type: bigint)
              outputColumnNames: _col1, _col12, _col13
              Statistics: Num rows: 2 Data size: 41 Basic stats: COMPLETE Column stats: NONE
              Map Join Operator
                condition map:
                     Left Outer Join0 to 1
                keys:
                  0 _col1 (type: bigint)
                  1 bid (type: bigint)
                outputColumnNames: _col12, _col13
                Statistics: Num rows: 2 Data size: 45 Basic stats: COMPLETE Column stats: NONE
                Select Operator
                  expressions: _col12 (type: bigint), _col13 (type: bigint), 'hoge' (type: string)
                  outputColumnNames: _col0, _col1, _col2
                  Statistics: Num rows: 2 Data size: 45 Basic stats: COMPLETE Column stats: NONE
                  File Output Operator
                    compressed: false
                    Statistics: Num rows: 2 Data size: 45 Basic stats: COMPLETE Column stats: NONE
                    table:
                        input format: org.apache.hadoop.mapred.TextInputFormat
                        output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
                        serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
      Local Work:
        Map Reduce Local Work

  Stage: Stage-0
    Fetch Operator
      limit: -1
      Processor Tree:
        ListSink

explainを見ると「d.t_4name = "hoge";」のwhere条件がなくなっています。

そして
「expressions: col12 (type: bigint), col13 (type: bigint), 'hoge' (type: string)」
ここを見てもらえればわかるように「d.t_4name」をselectした場所が「hoge」に変わってしまってます。

この現象が起きる条件としてわかってる範囲では以下の5つの条件が必要になるようです。

  • 4つ以上のテーブルをleft outer joinでつなぐ

  • 複数のkeyでjoinする(今回ではaidとbid)

  • 複数のkeyのjoinを入れ子にする。(aidでjoinの後にbidでjoinしてからaidでjoinの様に)

  • どこかのon句にkeyのjoin以外の条件を追加(今回では「b.t_2name = "test"」)

  • 入れ子にした後のテーブルのカラムでwhere句を生成

HiveのJIRAも検索したのですが、同じ様な現象は発見出来ませんでした。(どなたか知ってたら教えてください)

前回に紹介したカラムずれといい、今回の紹介のバグといい、left outer joinちょっと怖いですね・・・

早く治ります様に(ー人ー)

-- 2015/07/08 追記
CDH5.4.3では直っている事を確認出来ました。

CDH5.4 Hiveでのカラムずれ問題

ビールはキリン党のにいやんです。こんばんわ。

一番搾りが好きですが、プリン体がラガーの方が少ないと聞き、ラガーに浮気しようかと・・・

さてさて、先日CDH5.4のアップデート方法を書いて、特に問題なかったぜ!って思ったのですが。 後から大問題が確認されました。。。

なんとHiveのバグを思いっきり踏んでいたらしく、selectした際のカラムずれが起きてました...orz

バグは以下のチケットにあがっています。

[HIVE-9613] Left join query plan outputs wrong column when using subquery - ASF JIRA

どのようなバグかざっくりいうと、
「left outer joinを繰り返すと、select したのと違うカラムが表示される場合がある」
という、なんとも悲惨なバグです。

すでにチケットはクローズされ、Hive1.2では修正されているようなのですが、CDH5.4.2ではbackportされていないようで、バグが出てしまうようです。

回避策としてはleft outer join をする度に別名をつけると回避できるようです。

バグが出るSQL(バグのチケットより抜粋)

select
    a.category,
    a.city,
    a.rank,
    b.src_category_en,
    c.src_city_name_en
from
    hivetemp.category_city_rank a
left outer join
(select
    src_category_en,
    dst_category_en
from
    hivetemp.category_match) b
on  a.category = b.dst_category_en
left outer join
(select
    src_city_name_en,
    dst_city_name_en
from
    hivetemp.city_match) c
on  a.city = c.dst_city_name_en

以下のように修正することで回避

select
    aa.category,
    aa.city,
    aa.rank,
    aa.src_category_en,
    c.src_city_name_en
from
(
select
    a.category,
    a.city,
    a.rank,
    b.src_category_en
from
    hivetemp.category_city_rank a
left outer join
(select
    src_category_en,
    dst_category_en
from
    hivetemp.category_match) b
on  a.category = b.dst_category_en
) aa
left outer join
(select
    src_city_name_en,
    dst_city_name_en
from
    hivetemp.city_match) c
on  aa.city = c.dst_city_name_en

CDHでも早めにバグが修正されるとよいですね。