Triggered Executionの対象ファイル
sbtではタスクの前に~(チルダ)をつけて実行すると、ファイルが更新されるたびに、再度タスクが実行される。再度タスクが実行されるためのトリガーは、タスクの依存関係などに関係なくProject traitのwatchPathsが返すパスで示されるファイルのいずれかが更新されることである。
タスクを新たに追加した際に、「タスク」と「タスクが依存するファイル集合」のペアをタスクの再実行のためにどこかに登録する必要があると勘違いしたため、メモ
サブプロジェクトを使う場合の注意
Simple Build Toolではサブプロジェクトを利用する際に、複数のサブプロジェクトで同じ外部Jarを利用する場合であっても、それぞれのプロジェクト毎にJarファイルを保存する。これを防ぐには、外部Jar専用のプロジェクトを作成し、外部Jarを利用するプロジェクトはそのプロジェクトに依存するようにする。
以下のように記述すると、project1/lib_managed、及びproject2/lib_managed以下にlog4jのjarがコピーされる。
import sbt._ class Project(info: ProjectInfo) extends DefaultProject(info) { lazy val project1 = project("project1", "Project 1", x => new DefaultProject(x) { val protobuf = "log4j" % "log4j" % "1.2.16" }) lazy val project2 = project("project2", "Project 2", x => new DefaultProject(x) { val protobuf = "log4j" % "log4j" % "1.2.16" }) }
これを以下のように外部Jar用のサブプロジェクトを作成するとexternaljars/lib_managed以下のみにlog4jのjarがコピーされ、その上でProject1, Project2からlog4jが利用できる。
import sbt._ class Project(info: ProjectInfo) extends DefaultProject(info) { lazy val externaljars = project("externaljars", "External Jar files", x => new DefaultProject(x) { val protobuf = "log4j" % "log4j" % "1.2.16" }) lazy val project1 = project("project1", "Project 1", x => new DefaultProject(x) { }, externaljars) lazy val project2 = project("project2", "Project 2", x => new DefaultProject(x) { }, externaljars) }
ScalaでHadoopのジョブを書く
HadoopのジョブをScalaで書くためのこんなものがある。
- http://blog.jonhnnyweslley.net/2008/05/shadoop.html
試したところ、サンプルがHadoop 0.20.2では動かないっぽい。
サンプルを動くように改変してみた。
WordCount.scala
import shadoop.SHadoop._ import java.util.Iterator import org.apache.hadoop.fs._ import org.apache.hadoop.io._ import org.apache.hadoop.mapreduce.lib.input.FileInputFormat import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat import org.apache.hadoop.mapreduce.Mapper import org.apache.hadoop.mapreduce.Reducer import org.apache.hadoop.conf.Configuration import org.apache.hadoop.fs.Path import org.apache.hadoop.mapreduce.Job import org.apache.hadoop.util.GenericOptionsParser import scala.collection.JavaConversions._ object WordCount { class Map extends Mapper[AnyRef, Text, Text, IntWritable] { val one: IntWritable = 1 override def map(key: AnyRef, value: Text, output: Mapper[AnyRef, Text, Text, IntWritable]#Context): Unit = { for (x <- value.split(" ")) { output.write(x, one) } } } class Reduce extends Reducer[Text, IntWritable, Text, IntWritable] { override def reduce(key: Text, values: java.lang.Iterable[IntWritable], context: Reducer[Text, IntWritable, Text, IntWritable]#Context): Unit = { val sum = values.reduceLeft( (x, y) => x + y) context.write(key, sum) } } def main(args: Array[String]) = { val conf = new Configuration() val otherArgs: Array[String] = (new GenericOptionsParser(conf, args)).getRemainingArgs() if (otherArgs.length != 2) { System.err.println("Usage: wordcount <in> <out>") exit(2) } val job = new Job(conf, "word count") job.setJarByClass(WordCount.getClass) job.setMapperClass(classOf[Map]); job.setCombinerClass(classOf[Reduce]); job.setReducerClass(classOf[Reduce]); job.setOutputKeyClass(classOf[Text]); job.setOutputValueClass(classOf[IntWritable]) FileInputFormat.addInputPath(job, new Path(otherArgs(0))) FileOutputFormat.setOutputPath(job, new Path(otherArgs(1))) exit(if (job.waitForCompletion(true)) 0 else 1) } }
overrideしたメソッドの引数のContextが書くのが激しくだるいので、SHadoopで工夫の余地する余地があるけど、他力本願的に何もしない。
Inner Class
JavaのInnerクラスを参照する際の方法
public class A { public class InnerClass { } }
上記のようなクラスが会った場合には"#"を使って以下のように参照できるようだ
A#InnerClass
優先順位付キュー
優先順位付キューを使おうとしたときにヘルプを見ても、使い方がよくわからなかったためメモ。*1
http://www.scala-lang.org/api/current/scala/collection/mutable/PriorityQueue.html
クラスはscala.collection.mutable.PriorityQueue
enqueueで要素を追加
scala> import scala.collection.mutable.PriorityQueue import scala.collection.mutable.PriorityQueue scala> val a = new PriorityQueue[Int]() a: scala.collection.mutable.PriorityQueue[Int] = PriorityQueue() scala> a.enqueue(1) scala> a.enqueue(2) scala> a.enqueue(10) scala> a res4: scala.collection.mutable.PriorityQueue[Int] = PriorityQueue(10, 2, 1)
dequeueで要素を取り出す
scala> a.dequeue res5: Int = 10 scala> a.dequeue res7: Int = 2 scala> a.dequeue res8: Int = 1
優先順位を変えるには、以下のようにnewの際に追加でOrdering型の引数を与える。
val b = new PriorityQueue[Int]()(scala.math.Ordering.Int.reverse)
*1:collection汎用のメソッドが多すぎて、enqueueとdequeueを見逃しただけなんですが