package com.linkedin.thirdeye.anomalydetection.model.merge;
import com.linkedin.thirdeye.anomalydetection.context.AnomalyDetectionContext;
import com.linkedin.thirdeye.anomalydetection.context.TimeSeries;
import com.linkedin.thirdeye.anomalydetection.model.detection.MinMaxThresholdDetectionModel;
import com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
import java.util.Properties;
import org.joda.time.Interval;
public class MinMaxThresholdMergeModel extends AbstractMergeModel {
public static final String DEFAULT_MESSAGE_TEMPLATE = "change : %.2f %%, currentVal : %.2f, min : %.2f, max : %.2f";
public static final String MIN_VAL = "min";
public static final String MAX_VAL = "max";
@Override public void update(AnomalyDetectionContext anomalyDetectionContext,
MergedAnomalyResultDTO anomalyToUpdated) {
// Get min / max props
Properties props = getProperties();
Double min = null;
if (props.containsKey(MIN_VAL)) {
min = Double.valueOf(props.getProperty(MIN_VAL));
}
Double max = null;
if (props.containsKey(MAX_VAL)) {
max = Double.valueOf(props.getProperty(MAX_VAL));
}
String metricName =
anomalyDetectionContext.getAnomalyDetectionFunction().getSpec().getTopicMetric();
TimeSeries timeSeries = anomalyDetectionContext.getTransformedCurrent(metricName);
Interval timeSeriesInterval = timeSeries.getTimeSeriesInterval();
long windowStartInMillis = timeSeriesInterval.getStartMillis();
long windowEndInMillis = timeSeriesInterval.getEndMillis();
double currentAverageValue = 0d;
int currentBucketCount = 0;
double deviationFromThreshold = 0d;
long anomalyStartTime = anomalyToUpdated.getStartTime();
long anomalyEndTime = anomalyToUpdated.getEndTime();
Interval anomalyInterval = new Interval(anomalyStartTime, anomalyEndTime);
for (long time : timeSeries.timestampSet()) {
if (anomalyInterval.contains(time)) {
double value = timeSeries.get(time);
if (value != 0d) {
if (windowStartInMillis <= time && time <= windowEndInMillis) {
currentAverageValue += value;
++currentBucketCount;
deviationFromThreshold += MinMaxThresholdDetectionModel.getDeviationFromThreshold(value, min, max);
} // else ignore unknown time key
}
}
}
if (currentBucketCount > 0) {
currentAverageValue /= currentBucketCount;
deviationFromThreshold /= currentBucketCount;
}
anomalyToUpdated.setScore(currentAverageValue);
anomalyToUpdated.setWeight(deviationFromThreshold);
anomalyToUpdated.setAvgCurrentVal(currentAverageValue);
double value = 0d;
if (min != null) {
value = min;
} else if (max != null) {
value = max;
}
anomalyToUpdated.setAvgBaselineVal(value);
String message =
String.format(DEFAULT_MESSAGE_TEMPLATE, deviationFromThreshold, currentAverageValue, min, max);
anomalyToUpdated.setMessage(message);
}
}