エクスポート/インポート

何回やってもわすれちゃうので。メモ。エクスポート。

hbase org.apache.hadoop.hbase.mapreduce.Driver export (テーブル名) (ファイル名)

インポート

hbase org.apache.hadoop.hbase.mapreduce.Driver import (テーブル名) (ファイル名)

基本的にMapReduceジョブなので、ファイルはHDFSにあります。

case文で型パラメータをつかうとき

Scala でこんなプログラムを書いたとします。

tuple match{
  case t:(Int,String) => println("(Int,String) tuple")
  case _ =>  println("Not a (Int,String) tuple!")
}

これ、コンパイル通ります。ただし、例えば、(String,String)のtuple を渡した場合、2行めのt:(Int,String)にマッチしてしまいます。というのは、バイトコードに変換されてしまうと、tの2要素のタプルであることは判断できるものの、tの各要素の型まではわからなくなってしまうからです。

もう少し詳しくみると、型指定の

 (Int,String)

の部分は、

Tuple2[Int,String] 

というように、Tuple2に型パラメータを指定しているのと同じことですが、この型パラメータの[Int,String]の情報がバイトコードになるとごっそり抜け落ちます。Scalaの型パラメータはJavaジェネリクスに変換されるのですが、Javaバイトコードの下位互換性を保つためにバイトコード生成時にジェネリクス情報をすべて消し込むerasureモデルを採用するからです。だから、tはTuple2かどうかはわかるけど、Tuple2[Int,String]かはわからない。

同じ理由で以下のコードも「Stringの」Listかどうかは、みてません(みれないから)

list match{
   case l:List[String] => "This is String List!"
   case _ => "This is not a String List!!"
}

なんでこんなことが気になったかというと、このようなコードがScalaDoc生成時にwarningをいっぱいだしたから。warningを出さない方法は、2種類あります。まず、「「Stringの」Listかどうかなんてそんなに気にしないよ。」という場合。このような場合は、

list match{
  case l:List[_] => "This is a List!"
  case _ => "This is not a List!"
}

と、型パラメータの部分を _ にすればよいです。caseのあとの処理のブロックでListの要素に対してString型のメソッドを実行したい場合も、asInstanceOf を利用してキャストすればいけます。(なんとなくちょっと不細工ですが)

問題は、「Stringの」Listだ、ということを検証したい場合です。以下のページでも議論されていますが、ちょっと工夫しないと難しそうです。

http://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why-cant-i-get-the-type-parameter

Listの場合は、

  1. Array にする (Javaの配列はジェネリクスではないから、要素の型の評価ができる)
  2. StringのList をあらわす StringListクラスを作成する

などなどの方法が考えられます。Tupleなどは、2番目の「クラスを作る」という方法をとった方がコードがすっきりしそうな気がします。

今回は文脈上問題なかったので、List[_]の方法を採用しました。いろいろ勉強になります。

ローカルリポジトリのパスは変わってなかった。

maven3 だとローカルリポジトリのパスが変わっていますね。 - ayakobabaの日記 って昨日書いたけど、嘘でした!!

会社のCIサーバの設定は、権限もろもろがないのでみれないのですが、ローカルPCにインストールされているmaven3の設定をみたけど、ローカルリポジトリのぱす変わってないし、setting.xmlにも

<!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ~/.m2/repository

って書いてありました。信じてくれたひとごめんなさい。でも私的には川口さんと言葉を交わせたからいいやー。いやしかし驚いたよ。

maven3 だとローカルリポジトリのパスが変わっていますね。

jenkins(hudson)サーバとmaven の社内リポジトリを一緒にするといいことがある、きっと。 - ayakobabaの日記 で書いたように、会社ではCIサーバのユーザのローカルリポジトリを、社内のリポジトリとして公開しています。
で、今日みたらmaven3がJenkinsさんで使えるようになっていたので、maven3でビルドしてみました!が、社内リポジトリへ公開はされず。なんでだろうと思ったら、maven2では、ローカルリポジトリはデフォルトで $HOME/.m2/repository だったのが、 maven3 では$HOME/.maven/repo に変わってますね。

たいしたことではないですが、リモートのリポジトリをみないような設定を実施してた場合、maven3に変えると「ライブラリがない!」といってはまるかも。。(あんまりそういう人はいなさそうですが)。それだけです。

foldLeftとmutableMap

最近Scalaにちょーーっとだけ慣れてきたので、なんとなくvarやmutableな何かをつかったら負けた気分になってしまいます。何かを集計してMapを作る、みたいな処理も嬉々としてfoldLeftつかってやってたら、社内のコードレビューで「インスタンス生成爆発で遅くなるからmutable.Map使った方がよくない?」って。

そ、そんなことないんじゃないのかなあ(動揺)。というわけで調べた。
コード。

val list = List.range(0, 100000)
    for (time <- 1 to 10) {
      val startTime = System.currentTimeMillis()
      val map = list.foldLeft(Map[Int, String]()) {
        (m, i) =>
          m + (i -> ("value" + i))

      }
      println("foldLeft time: " + (System.currentTimeMillis() - startTime))
    }

    for (time <- 1 to 10) {
      val startTime = System.currentTimeMillis()
      val map2 = collection.mutable.Map[Int, String]()
      for (i <- list) {
        map2.put(i, "value" + i)
      }
      println("mutable time:" + (System.currentTimeMillis() - startTime))
    }

結果

foldLeft time: 415
foldLeft time: 137
foldLeft time: 147
foldLeft time: 146
foldLeft time: 154
foldLeft time: 152
foldLeft time: 136
foldLeft time: 136
foldLeft time: 128
foldLeft time: 127
mutable time:137
mutable time:96
mutable time:124
mutable time:84
mutable time:110
mutable time:110
mutable time:85
mutable time:104
mutable time:106
mutable time:107

。。。そりゃそうですよね。
正直、思ったよりfoldLeftは善戦してた。


これから書き直します。