object Matcher { def main(args:Array[String]):Unit = { val nekoz = genCats() nekoz.foreach{ x => x match { case MyCat(a,b) if a > 5 => println("Adult neko.") case _ => println("..") } } nekoz match { case l @ List(MyCat(8, _), _*) => println(s"okay, starting with 8 year old cat - $l") case _ => println("..") } } def genCats() = { MyCat(8, "Tora") :: MyCat(4, "Mikeyo") :: List() } } case class MyCat(age:Int, name:String)
木曜日, 12月 31, 2015
Scala - Sequenceマッチ
Scalaのmatch文は極めて強力で,そのうちの一つのリスト要素へのパターンマッチも便利なものの一つだろう.以下の例はMyCatへのコンストラクタマッチとリスト要素へのシーケンスパターンマッチの組み合わせの例.もしパターンマッチ内でジェネリック型も含めた型パターンマッチ等をしていて,かつJavaからそのscalaコードから作られたクラスを利用する場合は,Javaの型消去の特性に気を付けるように.
水曜日, 12月 30, 2015
Scala - ワードカウント
SparkではreduceByKeyで簡単にワードカウントができるが,scalaではfoldLeftで実装出来る.
val x = """kiji,saru,saru#saru,inu,kiji,saru#inu,kiji,kiji#kiji#inu,inu#saru""" val v = x.split("#").flatMap(_.split(",")).map(s => (s,1)) val z = v.foldLeft(Map[String,Int]())((accm, elem) => { if(accm.contains(elem._1)) accm.updated(elem._1, elem._2 + accm(elem._1)) else accm + elem })
火曜日, 12月 29, 2015
scala - ディレクトリのファイル操作
妻のパソコンの,とあるフォルダにある画像ファイルのタイムスタンプが何故かおかしくなってしまった.ファイルの数が膨大ということもあり,scalaでさっとコードを書いて修正した.
import java.io.File import java.time.{LocalDateTime, ZoneId} import java.util.Date import org.apache.commons.io.FileUtils /** * Created by neko32 on 2015/12/28. */ class FileDateChanger(preProcessDir:String, postProcessDir:String) { implicit def dateToLDate(d:Date):LocalDateTime = { d.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() } def process(): Unit = { clean() val files = new File(preProcessDir).listFiles().filter(f => dateToLDate(new Date(f.lastModified())).getYear() == 2007) val totalNum = files.size var at = 0 println(s"Total number of files - ${totalNum}") files.foreach { f => var dat = new Date(f.lastModified()) var f2 = new File(postProcessDir + "\\" + f.getName()) println(s"processing .. ${f.getName()}[${new Date(f.lastModified())}]") FileUtils.copyFile(f, f2) f2.setLastModified(dat.plusYears(8).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli) println(s"to ${new Date(f2.lastModified())}") if(at % 10 == 0) println(s"processed ${at}") at += 1 } println(s"done. # of processed files [${at}]") } private def clean(): Unit = { println(s"cleaning ${postProcessDir}") new File(postProcessDir).listFiles().foreach(_.delete()) println("cleaning done.") } } object Runner { def main(args:Array[String]) = { val pre = "C:\\tmp\\pre_process" val post = "C:\\tmp\\post_process" new FileDateChanger(pre, post).process() } }
日曜日, 12月 27, 2015
Scala - 乱数生成プロバイダを用いるstream
val r = new Random(System.currentTimeMillis()) def rand(max:Int):Stream[Int] = Stream.cons(r.nextInt(max), rand(max)) rand(100) take 10 foreach println // assign index starting from 1. zipWithIndex()'s index starts from 0 rand(50) take 5 zip(Stream from 1) foreach println
金曜日, 12月 25, 2015
Scala - Enumeration
ScalaでEnumerationを継承してenumを定義する例.
object Weekdays extends Enumeration { type WEEKDAY = Value val MON, TUE, WED = Value } object MyMain { def isMonday(w:Weekdays.Value) = { w == Weekdays.MON } def main(args:Array[String]) = { val w = Weekdays.MON val w2 = Weekdays.WED println(isMonday(w)) println(isMonday(w2)) } }
木曜日, 12月 24, 2015
Scala - akka アクタ
Akka actorのサンプルメモ..
import akka.actor._ /** * Created by neko32 on 2015/12/23. */ sealed abstract trait Message case class Request(a:Int, b:Int, op:Operator) extends Message case class Response(a:Int, b:Int, op:Operator, result:Int) extends Message case class ExecStart(cmd:String) extends Message case class ExecEnd(a:Any) extends Message sealed abstract class Operator(a:Int, b:Int) { def calc():Int } case class Plus(a:Int, b:Int) extends Operator(a,b) { override def calc() = a + b override def toString() = " + " } case class Minus(a:Int, b:Int) extends Operator(a,b) { override def calc() = a - b override def toString() = " - " } case class Multiply(a:Int, b:Int) extends Operator(a,b) { override def calc() = a * b override def toString() = " * " } case class Divide(a:Int, b:Int) extends Operator(a,b) { require(b != 0, "zero divide not allowed") override def calc() = a / b override def toString() = " / " } class CalcWorker extends Actor { override def receive = { case Request(a,b,op) if op.isInstanceOf[Plus] => println("sending.."); sender ! Response(a, b, op, a + b) case Request(a,b,op) if op.isInstanceOf[Minus] => sender ! Response(a, b, op, a - b) case Request(a,b,op) if op.isInstanceOf[Multiply] => sender ! Response(a, b, op, a * b) case Request(a,b,op) if op.isInstanceOf[Divide] => sender ! Response(a, b, op, a / b) case ExecEnd => context.stop(self) } } trait Requester extends Actor with ActorLogging { override def receive = { case Response(a, b, op, rez) => log.info(s"got result from calc agent .. ${a}${op}${b} = ${rez}") case ExecStart(cmd) => run(cmd) case ExecEnd => context.stop(self) case _ => log.info("....") } def run(cmd:String) } class CalcRequester(calcAgent:ActorRef) extends Requester { def toOp(vals:Array[String]):Operator = vals(2) match { case s if s == "plus" => Plus(vals(0).toInt, vals(1).toInt) case s if s == "minus" => Minus(vals(0).toInt, vals(1).toInt) case s if s == "mult" => Multiply(vals(0).toInt, vals(1).toInt) case s if s == "div" => Divide(vals(0).toInt, vals(1).toInt) } override def run(cmd:String) = { // parse a,b assume(cmd.count(_ == ',') == 2) val vals = cmd.toLowerCase().split(",") println("parsed input - " + vals(0) + "," + vals(1) + "," + vals(2)) val res = calcAgent ! Request(vals(0).toInt, vals(1).toInt, toOp(vals)) } } object MyApp { def main(args:Array[String]) = { val sys = ActorSystem("CalcSys") val calcAgent = sys.actorOf(Props[CalcWorker], "CalcAgent") val calcReq = sys.actorOf(Props(new CalcRequester(calcAgent)), "CalcReq") calcReq ! ExecStart("3,8,plus") Thread.sleep(3000) calcReq ! ExecEnd calcAgent ! ExecEnd val f = sys.terminate() } }
水曜日, 12月 23, 2015
Scala - Mixin, traitそしてselfによる型間依存関係の表現
Scalaのmixinとtraitそしてselfアノテーションを利用することにより,Javaと比較してより明快に型間の依存関係を宣言出来る.Javaではミックスインが出来ない為,クラス間の依存関係はあるクラスのprivate or protectedフィールドとして表現されていることがご想像いただけるかと思う.
case class Neko(name:String,pattern:String, age:Int) trait CatManage { self: CatManage with DefNekoCheck => var nekoz:List[Neko] def init():Unit def lookupCat(name:String):Neko } trait DefNekoCheck { def ? (neko:Neko) = neko != null } trait NekoCheck extends DefNekoCheck { override def ? (neko:Neko) = neko.name == "NA" } trait NekozManage extends CatManage with NekoCheck { override var nekoz = List[Neko]() override def init():Unit = { nekoz ::= Neko("Mikeyo", "Mike", 3) nekoz ::= Neko("Tora", "Chatora", 8) nekoz ::= Neko("Powder", "Mike", 8) nekoz ::= Neko("Machiko", "Mike", 10) } override def lookupCat(name:String):Neko = { val n = nekoz find(_.name == name) n.getOrElse(Neko("NA", "NA", -1)) } } trait Act { def start(f: => List[String]) } trait App { self: Act with CatManage => override def start(execPlan: => List[String]) = { init val l = execPlan l.foreach{ name => lookupCat(name) match { case x if x.name == "NA" => println(s"${name} not found..") case x => println(x) } } } }
日曜日, 12月 20, 2015
Scala - visitorパターンのようなもの
ScalaではVisitorパターンを割合簡潔に書くことが出来る.以下の例はあるデータベース上で接続・検索を実行するモジュールで,この例では通常のRDB, HiveそしてインメモリDBをサポートしているとする.また,(乱暴ではあるが簡略のために)RDBとHiveserver2はコネクトとクエリを同一の手順,インメモリはコネクトを必要としないと仮に想定している.
package tanuneko /** * Created by neko32 on 2015/12/20. */ sealed abstract class DB(host:String, userId:String, passwd:String) case class RegularRDB(host:String, userId:String, passwd:String) extends DB(host, userId, passwd) case class InMemoryDB(userId:String, passwd:String) extends DB(null, userId, passwd) case class HiveDB(host:String, userId:String, passwd:String) extends DB(host, userId, passwd) case class ResultSet(data:String) trait DBAction { def connect():Unit = {} def runQuery(str:String):ResultSet } class RegularDBAction(host:String, userId:String, passwd:String) extends DBAction { override def connect(): Unit = { println(s"connecting to ${host} with user[${userId}]") } override def runQuery(sql: String): ResultSet = { println(s"send query[${sql} to Database[${host}]") new ResultSet("returned data.") } } class InMemoryDBAction(userId:String, passwd:String) extends DBAction { override def runQuery(sql: String): ResultSet = { println(s"[inmem] running query[${sql}]") new ResultSet("returned data.") } } object Runner { def main(args:Array[String]):Unit = { val userId = "neko" val passwd = "miPasswd150X" val host = "myhost.org:16500" val sql = "select * from mydb.mytbl" def runQueryAfterConnect = (db:DB) => db match { case r:RegularRDB => { val act = new RegularDBAction(r.host, r.userId, r.passwd) act.connect() println(s"result - ${act.runQuery(sql)}") } case i:InMemoryDB => { val act = new InMemoryDBAction(i.userId, i.passwd) println(s"[inmem] result - ${act.runQuery(sql)}") } case r:HiveDB => { val act = new RegularDBAction(r.host, r.userId, r.passwd) act.connect() println(s"result - ${act.runQuery(sql)}") } } val sybase = new RegularRDB(host, userId, passwd) runQueryAfterConnect(sybase) val inmem = new InMemoryDB(userId, passwd) runQueryAfterConnect(inmem) val hive = new HiveDB(host, userId, passwd) runQueryAfterConnect(hive) } }
月曜日, 12月 14, 2015
scala - tailrecアノテーション
scalaではtailrecアノテーションを使って末尾再帰の最適化をすることができる.
関数は再起呼び出しで終わっている必要がある.
関数は再起呼び出しで終わっている必要がある.
@tailrec def fact(i:BigInt, accm:BigInt):BigInt = { i match { case _ if i == 1 => accm case _ => fact(i - 1, i * accm) } }
火曜日, 12月 01, 2015
Javaの関数プログラミングで偏差
暇つぶしに統計の基礎の動画を見ていたら,サンプルのコードを書きたくなったので,メモとして..
この例ではカンマ区切りの名前と点数 の行からなるデータを読み込んで,平均,分散,偏差,標準偏差そして偏差値を計算する.
この例ではカンマ区切りの名前と点数 の行からなるデータを読み込んで,平均,分散,偏差,標準偏差そして偏差値を計算する.
package org.tanuneko; import com.google.common.base.Function; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.io.Files; import com.google.common.io.LineProcessor; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; import java.util.stream.Stream; public class STDDev { public static void main(String args[]) throws Exception { new STDDev(); } public STDDev() throws IOException { File scoreFile = new File(STDDev.class.getClassLoader().getResource("score.txt").getPath()); ImmutableList<Record> rec = Files.asCharSource(scoreFile, Charset.defaultCharset()) .readLines(new LineProcessor<ImmutableList<Record>>() { List<Record> results = Lists.newArrayList(); @Override public boolean processLine(String line) throws IOException { List<String> elems = Splitter.on(",").splitToList(line); Preconditions.checkState(elems.size() == 2); results.add(new Record(elems.get(0), Integer.parseInt(elems.get(1)))); return true; } @Override public ImmutableList<Record> getResult() { return ImmutableList.copyOf(results); } }); int totalScore = rec.stream().mapToInt(x->x.getScore()).sum(); double avg = totalScore / rec.size(); rec.stream().forEach(x->x.setDev(x.getScore() - avg)); double v = calcVariation(rec); double d = calcStddev(rec); System.out.println("total:" + totalScore + ", avg:" + avg); System.out.println("variation:" + v); System.out.println("stddev:" + d); System.out.println(checkDev(rec)); rec.stream().forEach(x -> { x.setScoreDev(50 + 10 * (x.getDev()/d)); }); System.out.println(rec); } private double calcVariation(ImmutableList<Record> rec) { return rec.stream().mapToDouble(x->x.getDev()) .reduce(0, (x,y)-> x + Math.pow(y, 2)) / rec.size(); } private double calcStddev(ImmutableList<Record> rec) { return Math.sqrt(calcVariation(rec)); } private boolean checkDev(ImmutableList<Record> rec) { double d = rec.stream().mapToDouble(x->x.getDev()) .sum(); System.out.println(d); return d == 0; } } class Record { private String name; private int score; private double dev; private double scoreDev; public Record(String name, int score) { this.name = name; this.score = score; dev = scoreDev = 0d; } public String getName() { return name; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("name", name) .add("score", score) .add("dev", dev) .add("score dev", scoreDev) .toString(); } public int getScore() { return score; } public double getDev() { return dev; } public void setDev(double dev) { this.dev = dev; } public double getScoreDev() { return scoreDev; } public void setScoreDev(double scoreDev) { this.scoreDev = scoreDev; } }
火曜日, 11月 24, 2015
ねこ。。
google guavaの関数の合成やtransformを使ってみた.(今さらながら。。)
以下のコードはID:にゃんこクラスのマップのルックアップ関数とにゃんこクラスからそのにゃんこ情報のStringに変更する関数を合成したものと,
そのにゃんこ情報列からmで始まりかつみけねこである条件でフィルタをかける例.
そしてこれはうちのめんこいにゃんこ.
以下のコードはID:にゃんこクラスのマップのルックアップ関数とにゃんこクラスからそのにゃんこ情報のStringに変更する関数を合成したものと,
そのにゃんこ情報列からmで始まりかつみけねこである条件でフィルタをかける例.
package org.tanuneko; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import java.util.*; public class Nekosagashi { public static void main(String args[]) { new Nekosagashi(); } public Nekosagashi() { Map<Integer,Cat> neko = getMap(); Function<Integer,Cat> lookup = Functions.forMap(neko); Function<Cat,String> patExt = new CatInfoExt(); Function<Integer,String> getCatInfoAsStringByID = Functions.compose(patExt, lookup); List<Integer> vals = Arrays.asList(IVAL(1),IVAL(2),IVAL(3),IVAL(4)); Collection<String> nekos = Collections2.transform(vals, getCatInfoAsStringByID); Collections2.filter(nekos, Predicates.and(new IsStartWithM(), new IsMikeneko())) .forEach(System.out::println); } class IsStartWithM implements Predicate<String> { @Override public boolean apply(String input) { return input.toLowerCase().startsWith("m"); } } class IsMikeneko implements Predicate<String> { @Override public boolean apply(String input) { return input.toLowerCase().contains("mike"); } } class Decorator implements Function<String,String> { @Override public String apply(String input) { return "***" + input + "***"; } } class CatInfoExt implements Function<Cat,String> { @Override public String apply(Cat input) { return input.getName() + ":" + input.getPattern(); } } public Map<Integer,Cat> getMap() { Map<Integer,Cat> map = new HashMap<>(); map.put(1, new Cat("Powder", "seiyoumike")); map.put(2, new Cat("Machiko", "orangemike")); map.put(3, new Cat("Torachan", "chatora")); map.put(4, new Cat("Mikeyo", "wafumike")); return map; } class Cat { private String name; private String pattern; public Cat(String name, String pattern) { this.name = name; this.pattern = pattern; } public String getName() { return name; } public String getPattern() { return pattern; } } private static Integer IVAL(int i) { return new Integer(i); } }
そしてこれはうちのめんこいにゃんこ.
日曜日, 11月 15, 2015
[scala] unapplyメモ
extractorとしてのunapplyのサンプルコードメモ.
Message.scala - メッセージ コンパニオンクラス
MessageTestSpec.scala - メッセージspec2テスト
Message.scala - メッセージ コンパニオンクラス
package tanuneko.ui2 class Message(val msg:String) { def this() = this(msg = "") override def toString():String = { s"msg:${msg}" } def show(): Unit = { println(msg) } } object Message { def apply(): Unit = new Message() def apply(msg:String) = new Message(msg) def unapply(res:Message) = Some(res.msg + "dayon") }
MessageTestSpec.scala - メッセージspec2テスト
package tanuneko.test import tanuneko.ui2.Message import org.specs2._ class MessageTestSpec extends mutable.Specification { "Message unapply" should { "return its msg field" in { val resp = Message("nyanchan") var isOk = resp match { case Message(x) if x == "nyanchandayon" => true case _ => false } isOk must beTrue } } }
木曜日, 9月 24, 2015
scala勉強メモ
些細なバブルソート.いいコード書けるように頑張ります.
object BubbleSort { def bubble(v:Array[Int]): Unit = { var t = 0 def iter = (x:Array[Int]) => { for(i <- 0 until x.length) println(x(i)) } println("**before**") iter(v) for(i <- 0 until v.size) { for(j <- i until v.size - 1) { if(v(i) >= v(j)) { t = v(i) v(i) = v(j) v(j) = t } } } println("**after**") iter(v) } def main(args:Array[String]): Unit = { var v = Array(32,25,40,10,38,50) bubble(v) } }
日曜日, 8月 23, 2015
Scala始めます
最近仕事でどうやらSparkを使い始めることになりそう.
Sparkの調査過程で明らかになったのは,JavaでSparkのコードを書くべきでなく,scalaで書くべきだということ.(既にSparkを使われている方々にとっては当然のことだと思うが).
まず第一にコードの量が違いすぎる.JavaでのSparkコードは冗長である一方Scalaでのコードは短くエレガントだ.
問題は私自身のscala経験が無いので一から勉強である.
C++, bash, Javaそしてgroovyを主に使ってきた私にしてもscala習得はかなり歯ごたえがありそうな気がする.
以下のコードは一応私にとってhello worldのようなもの.年末までくらいに自身がどれくらいのscalaコードを書けるようになっているか楽しみである.
Sparkの調査過程で明らかになったのは,JavaでSparkのコードを書くべきでなく,scalaで書くべきだということ.(既にSparkを使われている方々にとっては当然のことだと思うが).
まず第一にコードの量が違いすぎる.JavaでのSparkコードは冗長である一方Scalaでのコードは短くエレガントだ.
問題は私自身のscala経験が無いので一から勉強である.
C++, bash, Javaそしてgroovyを主に使ってきた私にしてもscala習得はかなり歯ごたえがありそうな気がする.
以下のコードは一応私にとってhello worldのようなもの.年末までくらいに自身がどれくらいのscalaコードを書けるようになっているか楽しみである.
import scala.util.Random object Test { def main(args: Array[String]) { val r = new Random() // does not work def l1 = r.shuffle((0 to 20).toList) def l2 = r.shuffle((0 until 20).toList) l1.foreach { it => println(it) } println(l1 sameElements l2) } }
土曜日, 3月 28, 2015
リストのループ検出
リストのループ重複検出をするコードを書いてください,という質問は候補者が勉強をしてきたかどうかを見るのに加減の良い問題だと,昨今のインタビューをしていて思った次第である.
様々な解の仕方があるが,やはりウサギさんとカメさんを期待するだろう.
様々な解の仕方があるが,やはりウサギさんとカメさんを期待するだろう.
#include <iostream> class Node { // to make code simpler, members are public public: int _data; Node* _next; Node(int data) :_data(data) { _next = NULL; } ~Node(){} Node(Node& n) { _data = n._data; _next = n._next; } Node& operator=(Node& n) { _data = n._data; _next = n._next; return *this; } }; void iterate(Node* root) { Node* p = root; int cnt = 0; while (p) { std::cout << p->_data << std::endl; p = p->_next; if (cnt++ >= 100) { std::cerr << "!!!! potential loop found" << std::endl; return; } } } void add(Node* root, int val) { Node* n = new Node(val); Node* p = root; while (p->_next) { p = p->_next; } p->_next = n; } bool detectLoop(Node* root) { Node* slow_ptr = root; Node* fast_ptr = root; while (slow_ptr && fast_ptr && fast_ptr->_next) { slow_ptr = slow_ptr->_next; fast_ptr = fast_ptr->_next->_next; std::cout << slow_ptr->_data << ":" << fast_ptr->_data << std::endl; if (slow_ptr == fast_ptr) { return true; } } return false; } int main() { Node r(10); add(&r, 32); add(&r, 64); add(&r, 128); // simulate loop here r._next->_next->_next->_next = r._next; iterate(&r); std::cout << "loop exists?" << (detectLoop(&r) ? "TRUE" : "FALSE") << std::endl; return 0; }
日曜日, 1月 18, 2015
guice
現在のプロジェクトからguiceを使うことになったが,これはなかなかの優れものだと思う.
今まで使ったDIフレームワークと比べても,コードを簡潔に短くことが出来るようになったと思う.
以下の例はFTPでファイルを送信するロジックを仮実装した例.コンフィグのバインドの例は決して真似をせぬ様.あくまでguiceの基本バインドの例である.
FileTransmit.java
FileTransmitProgram.java
FTPFileSender.java
今まで使ったDIフレームワークと比べても,コードを簡潔に短くことが出来るようになったと思う.
以下の例はFTPでファイルを送信するロジックを仮実装した例.コンフィグのバインドの例は決して真似をせぬ様.あくまでguiceの基本バインドの例である.
FileTransmit.java
ackage org.tanuneko; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; public class FileTransmit { public static void main(String args[]) { String[] myArgs = {"/home/neko32", "tako.log", "640"}; Config c = new AppConfig(myArgs); Injector injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { bind(FileSenderIF.class).to(FTPFileSender.class); bind(Config.class).toInstance(c); } }); FileTransmitProgram ft = injector.getInstance(FileTransmitProgram.class); ft.run(); } class MyAppConfig extends Config { MyAppConfig(String[] args) { // do not do this in product code super.logFileLocation = args[0]; super.logFileName = args[1]; super.maxFileSize = Integer.parseInt(args[2]); } } }
FileTransmitProgram.java
package org.tanuneko; import com.google.inject.Inject; public class FileTransmitProgram { @Inject private FileSenderIF sender; @Inject private Config conf; public void run() { sender.setLogging(conf.getLogFileLocation(), conf.getLogFileName()); sender.setFileMaxFileSize(conf.getMaxFileSize()); sender.send("ABC", "DATA"); } }
FTPFileSender.java
package org.tanuneko; public class FTPFileSender implements FileSenderIF { private int maxFileSize = -1; public void setLogging(String logLocation, String fileName) { System.out.println(String.format("Setting logs[%s/%s]", logLocation, fileName)); } public void setFileMaxFileSize(int maxFileSize) { int prevMax = maxFileSize; this.maxFileSize = maxFileSize; System.out.println(String.format("max file size has changed from %d to %d", prevMax, this.maxFileSize)); } @Override public void send(String fileName, String data) { System.out.println(String.format("file %s(%s) was sent via FTP", fileName, data)); } }
日曜日, 1月 11, 2015
Java8 - Function::compose
Java8のFunctionクラスのcompose()メソッドを使えば,簡単にメソッドチェインを実装できる.
上手く使えばコードをかなり簡潔にできるだろう.以下のコードは3つの文字列操作フィルタをチェインして適用させた例.
上手く使えばコードをかなり簡潔にできるだろう.以下のコードは3つの文字列操作フィルタをチェインして適用させた例.
package org.tanuneko; import java.util.function.Function; import java.util.stream.Stream; public class FuncComposer { public FuncComposer() { } public void run() throws Exception { Function<String,String> addPrefixFilter = x -> "***" + x; Function<String,String> addPostfixFilter = x -> x + "***"; Function<String,String> toLowerCaseFilter = x -> x.toLowerCase(); String base = "WOW"; Function<String,String> composedFilter = Stream.of(addPrefixFilter, addPostfixFilter, toLowerCaseFilter) .reduce((func, nxt)->func.compose(nxt)) .orElseGet(Function::identity); System.out.println(composedFilter.apply(base)); } public static void main(String args[]) throws Exception { FuncComposer c = new FuncComposer(); c.run(); } }
ElasticSearch IntegrationTest
ElasticSearch IntegrationTestを使えば,メモリ上での仮想クラスタ上で単体テストを走らせることができる優れものだが,あまりサンプルコードが見つからない気がする.
package org.tanuneko; import org.apache.commons.io.FileUtils; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.query.FilterBuilders; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; import org.junit.Test; import java.io.File; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.Date; import java.util.Map; import java.util.function.Function; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.core.Is.is; @ClusterScope(scope= ElasticsearchIntegrationTest.Scope.SUITE,numDataNodes=2) public class ESIntegrationTest extends ElasticsearchIntegrationTest { private static final String INDEX_NAME = "tanuapp"; private static final String DOCTYPE_NAME = "posting_msg"; private static final String TODAY_DATE_STR = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); @Test public void testSearch() throws Exception { createIndex(INDEX_NAME); client().admin().indices().preparePutMapping(INDEX_NAME) .setType(DOCTYPE_NAME) .setSource(readMappingFile(DOCTYPE_NAME + "_mappings.json")) .execute().actionGet(); assertThat(indexDoc(INDEX_NAME, DOCTYPE_NAME, "1", "neko32", "hellou").isCreated(), is(true)); assertThat(indexDoc(INDEX_NAME, DOCTYPE_NAME, "2", "ushi", "poooo").isCreated(), is(true)); assertThat(indexDoc(INDEX_NAME, DOCTYPE_NAME, "3", "neko64", "ka-kakinkin ka-kinkin").isCreated(), is(true)); flushAndRefresh(INDEX_NAME); ensureGreen(INDEX_NAME); assertThat(indexExists(INDEX_NAME), is(true)); GetResponse resp = client().prepareGet(INDEX_NAME, DOCTYPE_NAME, "3") .execute() .actionGet(); Mapsource = resp.getSource(); assertThat((String)source.get("user"), is("neko64")); assertThat((String)source.get("message"), is("ka-kakinkin ka-kinkin")); final String postedDate = (String)source.get("postDate"); Function isSameDate = x -> x.startsWith(TODAY_DATE_STR); assertTrue(isSameDate.apply(convertToGMT(postedDate)).booleanValue()); SearchResponse searchResp = client().prepareSearch(INDEX_NAME) .setTypes(DOCTYPE_NAME) .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.fuzzyLikeThisFieldQuery("user").likeText("neko50")) .setPostFilter(FilterBuilders.idsFilter(DOCTYPE_NAME).ids("1")) .execute() .actionGet(); assertThat(searchResp.getHits().getHits().length, is(1)); assertThat(searchResp.getHits().getAt(0).getSource().get("user"), is("neko32")); } private String readMappingFile(final String fileName) throws Exception { return FileUtils.readFileToString(new File(ESIntegrationTest.class.getClassLoader().getResource(fileName).getPath())); } private String convertToGMT(String dateStr) { return LocalDateTime.parse(dateStr.substring(0,dateStr.length()-1)).toString(); } private IndexResponse indexDoc(final String idxName, final String docName, final String id, final String user, final String msg) throws Exception { return client().prepareIndex(INDEX_NAME, DOCTYPE_NAME) .setSource(genMsg(user, msg)) .setId(id) .execute().actionGet(); } private XContentBuilder genMsg(String user, String msg) throws Exception { return jsonBuilder().startObject() .field("user", user) .field("postDate", new Date()) .field("message", msg) .endObject(); } }
登録:
投稿 (Atom)