package storm.applications.bolt;
import java.util.ArrayList;
import java.util.List;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import static storm.applications.constants.MachineOutlierConstants.*;
import storm.applications.util.math.BFPRT;
/**
* The alert is triggered solely by the anomaly score of current data instance.
* @author Yexi Jiang (http://users.cs.fiu.edu/~yjian004)
*
*/
public class DataInstAlertTriggerBolt extends AbstractBolt {
private static final double dupper = 1.0;
private long previousTimestamp;
private List<Tuple> streamList;
@Override
public void initialize() {
previousTimestamp = 0;
streamList = new ArrayList<>();
}
@Override
public void execute(Tuple input) {
long timestamp = input.getLongByField(Field.TIMESTAMP);
if (timestamp > previousTimestamp) {
// new batch of stream scores
if (!streamList.isEmpty()) {
List<Tuple> abnormalStreams = identifyAbnormalStreams();
int medianIdx = (int)Math.round(streamList.size() / 2);
double minScore = abnormalStreams.get(0).getDouble(1);
double medianScore = abnormalStreams.get(medianIdx).getDouble(1);
for (int i = 0; i < abnormalStreams.size(); ++i) {
Tuple streamProfile = abnormalStreams.get(i);
double streamScore = streamProfile.getDouble(1);
boolean isAbnormal = false;
if (streamScore > 2 * medianScore - minScore) {
isAbnormal = true;
}
collector.emit(new Values(streamProfile.getString(0),
streamProfile.getDouble(1), streamProfile.getLong(2),
isAbnormal, streamProfile.getValue(3)));
}
streamList.clear();
}
previousTimestamp = timestamp;
}
streamList.add(input);
collector.ack(input);
}
@Override
public Fields getDefaultFields() {
return new Fields(Field.ANOMALY_STREAM, Field.STREAM_ANOMALY_SCORE, Field.TIMESTAMP, Field.IS_ABNORMAL, Field.OBSERVATION);
}
/**
* Identify the abnormal streams.
* @return
*/
private List<Tuple> identifyAbnormalStreams() {
List<Tuple> abnormalStreamList = new ArrayList<>();
int medianIdx = (int)Math.round(streamList.size() / 2);
Tuple medianTuple = BFPRT.bfprt(streamList, medianIdx);
double minScore = Double.MAX_VALUE;
for (int i = 0; i < medianIdx; ++i) {
double score = streamList.get(i).getDouble(1);
if (score < minScore) {
minScore = score;
}
}
double medianScore = medianTuple.getDouble(1);
abnormalStreamList.addAll(streamList);
return abnormalStreamList;
}
}