#Scala で #Hadoop のjava.lang.Iterable[Writable]を処理する際の話
java.lang.IterableをasScalaした後にtoListすると全ての要素が末尾の値になってしまう現象に悩まされている。asScalaまでなら大丈夫。なんだこれ。
2012-12-25 16:32:30scala.collection.IterableをtoListしても当然問題ないのでJavaConverterの問題?
2012-12-25 16:37:37Iterableをメモリ消費を抑えたまま先頭と末尾に値を追加したいんだけどどうすればいいだろう。streamを仲介すればいいかな。
2012-12-25 16:50:53@choplin 普通にやっただけじゃ発生しないですね・・・こんな感じで https://t.co/qLPa0l76 もとのIterableのiteratorの動作が残念だと発生するかもしれませんが
2012-12-25 18:53:42@xuwei_k IterableはHadoopのReducerに渡ってくるものですね。中身は見てないですがscalaから使うことを想定しておらずに残念になっている可能性は高いです。こんな感じにtoListを挟むと値がおかしくなります。 https://t.co/eGr4xjFS
2012-12-26 12:02:08うーむ、結局Iterableのiteratorメソッドを何度読んでもちゃんと新しいiteratorが返ってくるようになっていないダメってことなのかな。
2012-12-26 12:44:20これ(iteratorメソッドを複数回呼び出し可にしておく)ってJavaの規約的にはどうなってるんだろう?Javaに詳しい人教えてくだされ。
2012-12-26 12:46:05.@choplin 以前Javadoc見た限りでは書いてなかったけど、現状のScalaのJavaConvertersの実装は「新しい同じiteratorが返ってくることを前提に実装」されてるので、何度も呼ばないように一気に変換するか、自前でラップするしかないですかね・・・
2012-12-26 13:08:42@xuwei_k ふーむ、なるほど。問題のIterablleを確認したところ正しいiteratorを一度しか返さなかったのでこれが原因でほぼ間違い無いですね。原因が分かったので何とか手は打てそうです。ありがとうございました。
2012-12-26 13:44:35Reducerの実装を見ると初期化時にiteratorを生成してい常にそれを返すようになっている。こりゃダメだ。こうするメリットって何かあるんだろうか?
2012-12-26 14:23:22そもそもIteratorが内部クラスになっていてIteratorの状態は外側クラスのメンバが管理するようになっているので単にiteratorの呼び出し毎に生成すればいいってわけでもないな
2012-12-26 14:29:43@choplin これってIteratorのせいじゃなくてVMAPがWritable的なものでBox化されているのが原因じゃないですか? toListってやると同じBoxのリストが出来上がりますので、mapとかで実際の値を取り出して、それをtoListする必要があると思います。
2012-12-26 14:46:21@ueshin @choplin あ、ここで言ったmapはMapReduceのmapじゃなくてScalaコレクションのmapです。
2012-12-26 14:47:26@ueshin Boxというのが今一理解できていないのですが、同じWritableのオブジェクトが使い回されて中の値だけが変わっているということですか?
2012-12-26 14:51:56@ueshin WritableSerialization.javaを見ると確かに使いまわしていますね。これが原因っぽいです。ありがとうございます。
2012-12-26 15:03:06@ueshin listではなくtoStreamでstreamにしてやるとwritableの評価がlazyになるので一つずつ処理できていい感じでした。ご参考までに。
2012-12-26 15:21:48@choplin なるほどです。 でも、1回使ったStreamをもう1度使おうとするとまた最後のやつだけになったりしませんかね?
2012-12-26 15:27:47@ueshin なりますね。同じくmapで値に変換しておけばOKです。Iterableのままmapすると全部メモリに載ってしまうんですが、Streamを介しておけば順番に読み取ってmapできるので多い日も安心です。
2012-12-26 15:32:35