The book <Akka Essential>'s examples are based on Akka 2.0, my revision gets these examples adapted to Akka 2.3 API, so I can play with these examples in new API, more fun, isn't it?
import java.util.concurrent.TimeUnit; import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; import akka.pattern.Patterns; import akka.util.Timeout; public class MapReduceApplication { public static void main(String[] args) throws Exception { Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS)); ActorSystem _system = ActorSystem.create("MapReduceApp"); ActorRef master = _system.actorOf(Props.create(MasterActor.class), "master"); master.tell( "The quick brown fox tried to jump over the lazy dog and fell on the dog", null); master.tell("Dog is man's best friend", null); // NULL SELF! master.tell("Dog and Fox belong to the same family", null); Thread.sleep(5000); Future<Object> future = Patterns.ask(master, new Result(), timeout); String result = (String) Await.result(future, timeout.duration()); System.out.println(result); _system.shutdown(); } }
import akka.actor.ActorRef; import akka.actor.Props; import akka.actor.UntypedActor; import akka.routing.RoundRobinRouter; public class MasterActor extends UntypedActor { ActorRef mapActor = getContext().actorOf( Props.create(MapActor.class).withRouter(new RoundRobinRouter(5)), "map"); ActorRef reduceActor = getContext() .actorOf( Props.create(ReduceActor.class).withRouter( new RoundRobinRouter(5)), "reduce"); ActorRef aggregateActor = getContext().actorOf( Props.create(AggregateActor.class), "aggregate"); @Override public void onReceive(Object message) throws Exception { if (message instanceof String) { mapActor.tell(message, getSelf()); } else if (message instanceof MapData) { reduceActor.tell(message, getSelf()); } else if (message instanceof ReduceData) { aggregateActor.tell(message, getSelf()); } else if (message instanceof Result) { aggregateActor.forward(message, getContext()); } else unhandled(message); } }
import java.util.HashMap; import java.util.List; import akka.actor.UntypedActor; public class ReduceActor extends UntypedActor { @Override public void onReceive(Object message) throws Exception { if (message instanceof MapData) { MapData mapData = (MapData) message; // reduce the incoming data and forward the result to Master actor getSender().tell(reduce(mapData.getDataList()), getSelf()); } else unhandled(message); } private ReduceData reduce(List<WordCount> dataList) { HashMap<String, Integer> reducedMap = new HashMap<String, Integer>(); for (WordCount wordCount : dataList) { if (reducedMap.containsKey(wordCount.getWord())) { Integer value = (Integer) reducedMap.get(wordCount.getWord()); value++; reducedMap.put(wordCount.getWord(), value); } else { reducedMap.put(wordCount.getWord(), Integer.valueOf(1)); } } return new ReduceData(reducedMap); } }
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; import akka.actor.UntypedActor; public class MapActor extends UntypedActor { String[] STOP_WORDS = { "a", "am", "an", "and", "are", "as", "at", "be", "do", "go", "if", "in", "is", "it", "of", "on", "the", "to" }; List<String> STOP_WORDS_LIST = Arrays.asList(STOP_WORDS); @Override public void onReceive(Object message) throws Exception { if (message instanceof String) { String work = (String) message; // map the words in the sentence and send the result to MasterActor getSender().tell(evaluateExpression(work), getSelf()); } else unhandled(message); // dig it! } private MapData evaluateExpression(String line) { List<WordCount> dataList = new ArrayList<WordCount>(); StringTokenizer parser = new StringTokenizer(line); while (parser.hasMoreTokens()) { String word = parser.nextToken().toLowerCase(); if (!STOP_WORDS_LIST.contains(word)) { dataList.add(new WordCount(word, Integer.valueOf(1))); } } return new MapData(dataList); } }
import java.util.HashMap; import java.util.Map; import akka.actor.UntypedActor; public class AggregateActor extends UntypedActor { private Map<String, Integer> finalReducedMap = new HashMap<String, Integer>(); @Override public void onReceive(Object message) throws Exception { if (message instanceof ReduceData) { ReduceData reduceData = (ReduceData) message; aggregateInMemoryReduce(reduceData.getReduceDataList()); } else if (message instanceof Result) { getSender().tell(finalReducedMap.toString(), getSelf()); } else unhandled(message); } private void aggregateInMemoryReduce(Map<String, Integer> reducedList) { Integer count = null; for (String key : reducedList.keySet()) { if (finalReducedMap.containsKey(key)) { count = reducedList.get(key) + finalReducedMap.get(key); finalReducedMap.put(key, count); } else { finalReducedMap.put(key, reducedList.get(key)); } } } }
import java.util.List; public class MapData { private final List<WordCount> dataList; public List<WordCount> getDataList() { return dataList; } public MapData(List<WordCount> dataList) { this.dataList = dataList; } }
import java.util.HashMap; public class ReduceData { private final HashMap<String, Integer> reduceDataList; public HashMap<String, Integer> getReduceDataList() { return reduceDataList; } public ReduceData(HashMap<String, Integer> reduceDataList) { this.reduceDataList = reduceDataList; } }
public class Result { }
public class WordCount { private final String word; private final Integer count; public WordCount(String inWord, Integer inCount) { word = inWord; count = inCount; } public String getWord() { return word; } public Integer getCount() { return count; } }
Reference:
[1] Akka Essential.