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.LinkedList;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import storm.applications.constants.SpikeDetectionConstants.Conf;
import storm.applications.constants.SpikeDetectionConstants.Field;
/**
* Calculates the average over a window for distinct elements.
* http://github.com/surajwaghulde/storm-example-projects
*
* @author surajwaghulde
*/
public class MovingAverageBolt extends AbstractBolt {
private static final Logger LOG = LoggerFactory.getLogger(MovingAverageBolt.class);
private int movingAverageWindow;
private Map<String, LinkedList<Double>> deviceIDtoStreamMap;
private Map<String, Double> deviceIDtoSumOfEvents;
@Override
public void initialize() {
movingAverageWindow = config.getInt(Conf.MOVING_AVERAGE_WINDOW, 1000);
deviceIDtoStreamMap = new HashMap<>();
deviceIDtoSumOfEvents = new HashMap<>();
}
@Override
public void execute(Tuple input) {
String deviceID = input.getStringByField(Field.DEVICE_ID);
double nextDouble = input.getDoubleByField(Field.VALUE);
double movingAvergeInstant = movingAverage(deviceID, nextDouble);
collector.emit(input, new Values(deviceID, movingAvergeInstant, nextDouble));
collector.ack(input);
}
public double movingAverage(String deviceID, double nextDouble) {
LinkedList<Double> valueList = new LinkedList<>();
double sum = 0.0;
if (deviceIDtoStreamMap.containsKey(deviceID)) {
valueList = deviceIDtoStreamMap.get(deviceID);
sum = deviceIDtoSumOfEvents.get(deviceID);
if (valueList.size() > movingAverageWindow-1) {
double valueToRemove = valueList.removeFirst();
sum -= valueToRemove;
}
valueList.addLast(nextDouble);
sum += nextDouble;
deviceIDtoSumOfEvents.put(deviceID, sum);
deviceIDtoStreamMap.put(deviceID, valueList);
return sum/valueList.size();
} else {
valueList.add(nextDouble);
deviceIDtoStreamMap.put(deviceID, valueList);
deviceIDtoSumOfEvents.put(deviceID, nextDouble);
return nextDouble;
}
}
@Override
public Fields getDefaultFields() {
return new Fields(Field.DEVICE_ID, Field.MOVING_AVG, Field.VALUE);
}
}