#Scala で #Hadoop のjava.lang.Iterable[Writable]を処理する際の話

4
Akihiro Okuno @choplin

java.lang.IterableをasScalaした後にtoListすると全ての要素が末尾の値になってしまう現象に悩まされている。asScalaまでなら大丈夫。なんだこれ。

2012-12-25 16:32:30
Akihiro Okuno @choplin

scala.collection.IterableをtoListしても当然問題ないのでJavaConverterの問題?

2012-12-25 16:37:37
Akihiro Okuno @choplin

Iterableをメモリ消費を抑えたまま先頭と末尾に値を追加したいんだけどどうすればいいだろう。streamを仲介すればいいかな。

2012-12-25 16:50:53
Kenji Yoshida @xuwei_k

@choplin 普通にやっただけじゃ発生しないですね・・・こんな感じで https://t.co/qLPa0l76 もとのIterableのiteratorの動作が残念だと発生するかもしれませんが

2012-12-25 18:53:42
Akihiro Okuno @choplin

@xuwei_k IterableはHadoopのReducerに渡ってくるものですね。中身は見てないですがscalaから使うことを想定しておらずに残念になっている可能性は高いです。こんな感じにtoListを挟むと値がおかしくなります。 https://t.co/eGr4xjFS

2012-12-26 12:02:08
Akihiro Okuno @choplin

うーむ、結局Iterableのiteratorメソッドを何度読んでもちゃんと新しいiteratorが返ってくるようになっていないダメってことなのかな。

2012-12-26 12:44:20
Akihiro Okuno @choplin

これ(iteratorメソッドを複数回呼び出し可にしておく)ってJavaの規約的にはどうなってるんだろう?Javaに詳しい人教えてくだされ。

2012-12-26 12:46:05
Kenji Yoshida @xuwei_k

.@choplin 以前Javadoc見た限りでは書いてなかったけど、現状のScalaのJavaConvertersの実装は「新しい同じiteratorが返ってくることを前提に実装」されてるので、何度も呼ばないように一気に変換するか、自前でラップするしかないですかね・・・

2012-12-26 13:08:42
Akihiro Okuno @choplin

@xuwei_k ふーむ、なるほど。問題のIterablleを確認したところ正しいiteratorを一度しか返さなかったのでこれが原因でほぼ間違い無いですね。原因が分かったので何とか手は打てそうです。ありがとうございました。

2012-12-26 13:44:35
Akihiro Okuno @choplin

Reducerの実装を見ると初期化時にiteratorを生成してい常にそれを返すようになっている。こりゃダメだ。こうするメリットって何かあるんだろうか?

2012-12-26 14:23:22
Akihiro Okuno @choplin

そもそもIteratorが内部クラスになっていてIteratorの状態は外側クラスのメンバが管理するようになっているので単にiteratorの呼び出し毎に生成すればいいってわけでもないな

2012-12-26 14:29:43
Akihiro Okuno @choplin

あぁ、counterもiteratorと一緒に回している…これは簡単に切り離すのはむりぽ。

2012-12-26 14:37:54
Takuya UESHIN @ueshin

@choplin これってIteratorのせいじゃなくてVMAPがWritable的なものでBox化されているのが原因じゃないですか? toListってやると同じBoxのリストが出来上がりますので、mapとかで実際の値を取り出して、それをtoListする必要があると思います。

2012-12-26 14:46:21
Takuya UESHIN @ueshin

@ueshin @choplin あ、ここで言ったmapはMapReduceのmapじゃなくてScalaコレクションのmapです。

2012-12-26 14:47:26
Akihiro Okuno @choplin

@ueshin Boxというのが今一理解できていないのですが、同じWritableのオブジェクトが使い回されて中の値だけが変わっているということですか?

2012-12-26 14:51:56
Takuya UESHIN @ueshin

@choplin あ、はい、そうです。Writableは使い回されます。(Boxの方がわかりにくかったですね。。。

2012-12-26 14:53:15
Akihiro Okuno @choplin

@ueshin WritableSerialization.javaを見ると確かに使いまわしていますね。これが原因っぽいです。ありがとうございます。

2012-12-26 15:03:06
Akihiro Okuno @choplin

Iterableをmapしてしまうとその場で全要素が読み取られてしまうのでできれば避けたい感じが

2012-12-26 15:16:23
Akihiro Okuno @choplin

@ueshin listではなくtoStreamでstreamにしてやるとwritableの評価がlazyになるので一つずつ処理できていい感じでした。ご参考までに。

2012-12-26 15:21:48
Akihiro Okuno @choplin

また一つscalaでhadoopする際のtipsが溜まってしまった

2012-12-26 15:22:09
Takuya UESHIN @ueshin

@choplin なるほどです。 でも、1回使ったStreamをもう1度使おうとするとまた最後のやつだけになったりしませんかね?

2012-12-26 15:27:47
Akihiro Okuno @choplin

@ueshin なりますね。同じくmapで値に変換しておけばOKです。Iterableのままmapすると全部メモリに載ってしまうんですが、Streamを介しておけば順番に読み取ってmapできるので多い日も安心です。

2012-12-26 15:32:35
Akihiro Okuno @choplin

scalaのstreamって結合のコストはどんなもんなんだろう?

2012-12-26 15:34:30
Takuya UESHIN @ueshin

@choplin んー? mapで値に変換してStreamを作ってもメモリに載ってしまうと思います。

2012-12-26 15:40:17