package stormapplied.heatmap.topology;
import backtype.storm.Config;
import backtype.storm.Constants;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.BasicOutputCollector;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseBasicBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import com.google.code.geocoder.model.LatLng;
import java.util.*;
public class HeatMapBuilder extends BaseBasicBolt {
private Map<Long, List<LatLng>> heatmaps;
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("time-interval", "hotzones"));
}
@Override
public void prepare(Map stormConf,
TopologyContext context) {
heatmaps = new HashMap<Long, List<LatLng>>();
}
@Override
public Map<String, Object> getComponentConfiguration() {
Config conf = new Config();
conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 60);
return conf;
}
@Override
public void execute(Tuple tuple,
BasicOutputCollector outputCollector) {
if (isTickTuple(tuple)) {
emitHeatmap(outputCollector);
} else {
Long time = tuple.getLongByField("time");
LatLng geocode = (LatLng) tuple.getValueByField("geocode");
Long timeInterval = selectTimeInterval(time);
List<LatLng> checkins = getCheckinsForInterval(timeInterval);
checkins.add(geocode);
}
}
private boolean isTickTuple(Tuple tuple) {
String sourceComponent = tuple.getSourceComponent();
String sourceStreamId = tuple.getSourceStreamId();
return sourceComponent.equals(Constants.SYSTEM_COMPONENT_ID)
&& sourceStreamId.equals(Constants.SYSTEM_TICK_STREAM_ID);
}
private void emitHeatmap(BasicOutputCollector outputCollector) {
Long now = System.currentTimeMillis();
Long emitUpToTimeInterval = selectTimeInterval(now);
Set<Long> timeIntervalsAvailable = heatmaps.keySet();
for (Long timeInterval : timeIntervalsAvailable) {
if (timeInterval <= emitUpToTimeInterval) {
List<LatLng> hotzones = heatmaps.remove(timeInterval);
outputCollector.emit(new Values(timeInterval, hotzones));
}
}
}
private Long selectTimeInterval(Long time) {
return time / (15 * 1000);
}
private List<LatLng> getCheckinsForInterval(Long timeInterval) {
List<LatLng> hotzones = heatmaps.get(timeInterval);
if (hotzones == null) {
hotzones = new ArrayList<LatLng>();
heatmaps.put(timeInterval, hotzones);
}
return hotzones;
}
}