package storm.applications.bolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import java.util.HashMap;
import java.util.Map;
import static storm.applications.constants.SmartGridConstants.*;
import storm.applications.util.math.RunningMedianCalculator;
/**
* Author: Thilina
* Date: 12/5/14
*/
public class PlugMedianCalculatorBolt extends AbstractBolt {
private Map<String, RunningMedianCalculator> runningMedians;
private Map<String, Long> lastUpdatedTsMap;
@Override
public void initialize() {
runningMedians = new HashMap<>();
lastUpdatedTsMap = new HashMap<>();
}
@Override
public void execute(Tuple tuple) {
int operation = tuple.getIntegerByField(Field.SLIDING_WINDOW_ACTION);
double value = tuple.getDoubleByField(Field.VALUE);
long timestamp = tuple.getLongByField(Field.TIMESTAMP);
String key = getKey(tuple);
RunningMedianCalculator medianCalc = runningMedians.get(key);
if (medianCalc == null) {
medianCalc = new RunningMedianCalculator();
runningMedians.put(key, medianCalc);
}
Long lastUpdatedTs = lastUpdatedTsMap.get(key);
if (lastUpdatedTs == null) {
lastUpdatedTs = 0l;
}
if (operation == SlidingWindowAction.ADD){
double median = medianCalc.getMedian(value);
if (lastUpdatedTs < timestamp) {
// the sliding window has moved
lastUpdatedTsMap.put(key, timestamp);
collector.emit(new Values(key, timestamp, median));
}
} else {
medianCalc.remove(value);
}
}
@Override
public Fields getDefaultFields() {
return new Fields(Field.PLUG_SPECIFIC_KEY, Field.TIMESTAMP, Field.PER_PLUG_MEDIAN);
}
private String getKey(Tuple tuple) {
return tuple.getStringByField(Field.HOUSE_ID) + ':' +
tuple.getStringByField(Field.HOUSEHOLD_ID) + ':' +
tuple.getStringByField(Field.PLUG_ID);
}
}