This is an automated email from the ASF dual-hosted git repository.
jihao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push:
new aa6d48f [TE] add threshold-based anomaly labeler (#5972)
aa6d48f is described below
commit aa6d48f183a6e7fd7c3c09e71bd165926da561aa
Author: Vincent Chen <[email protected]>
AuthorDate: Tue Sep 8 17:05:16 2020 -0700
[TE] add threshold-based anomaly labeler (#5972)
This PR is the first part of adding an anomaly labeler for better alerting
ThirdEye users. It adds a labeling phase and a threshold-based labeler. The
next PR is to add the logic of translating YAML to JSON config.
---
.../AnomalySeverity.java} | 28 +++-
.../datalayer/dto/MergedAnomalyResultDTO.java | 11 ++
.../datalayer/pojo/MergedAnomalyResultBean.java | 15 ++
.../thirdeye/detection/DetectionPipeline.java | 22 +++
.../detection/algorithm/DimensionWrapper.java | 22 +--
.../algorithm/LegacyAlertFilterWrapper.java | 16 +-
.../algorithm/LegacyDimensionWrapper.java | 24 +--
.../detection/algorithm/LegacyMergeWrapper.java | 17 +-
.../thirdeye/detection/algorithm/MergeWrapper.java | 15 +-
.../detection/annotation/DetectionTag.java | 3 +-
.../components/ThresholdSeverityLabeler.java | 88 ++++++++++
.../SeverityThresholdLabelerSpec.java} | 40 ++++-
.../components/Labeler.java} | 19 ++-
.../detection/wrapper/AnomalyFilterWrapper.java | 17 +-
...lterWrapper.java => AnomalyLabelerWrapper.java} | 79 +++------
.../thirdeye/detection/wrapper/GrouperWrapper.java | 15 +-
.../components/ThresholdRuleAnomalyFilterTest.java | 2 -
.../components/ThresholdSeverityLabelerTest.java | 181 +++++++++++++++++++++
18 files changed, 426 insertions(+), 188 deletions(-)
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/anomaly/AnomalySeverity.java
similarity index 64%
copy from
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
copy to
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/anomaly/AnomalySeverity.java
index c30120d..16b545a 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/anomaly/AnomalySeverity.java
@@ -17,12 +17,26 @@
* under the License.
*/
-package org.apache.pinot.thirdeye.detection.annotation;
+package org.apache.pinot.thirdeye.anomaly;
-public enum DetectionTag {
- ALGORITHM_DETECTION,
- RULE_DETECTION,
- ALGORITHM_FILTER,
- RULE_FILTER,
- GROUPER
+/**
+ * The severity of anomaly.
+ */
+public enum AnomalySeverity {
+ // the order of definition follows the severity from highest to lowest
+ CRITICAL ("critical"),
+ HIGH ("high"),
+ MEDIUM ("medium"),
+ LOW ("low"),
+ DEFAULT ("default");
+
+ private String severity;
+
+ AnomalySeverity(String severity) {
+ this.severity = severity;
+ }
+
+ public String getLabel() {
+ return severity;
+ }
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/dto/MergedAnomalyResultDTO.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/dto/MergedAnomalyResultDTO.java
index 415a252..69b08c5 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/dto/MergedAnomalyResultDTO.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/dto/MergedAnomalyResultDTO.java
@@ -44,6 +44,9 @@ public class MergedAnomalyResultDTO extends
MergedAnomalyResultBean implements A
private Set<MergedAnomalyResultDTO> children = new HashSet<>();
+ // flag to be set when severity changes but not to be persisted
+ private boolean renotify = false;
+
public MergedAnomalyResultDTO() {
setCreatedTime(System.currentTimeMillis());
}
@@ -107,6 +110,14 @@ public class MergedAnomalyResultDTO extends
MergedAnomalyResultBean implements A
this.children = children;
}
+ public boolean isRenotify() {
+ return renotify;
+ }
+
+ public void setRenotify(boolean renotify) {
+ this.renotify = renotify;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/MergedAnomalyResultBean.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/MergedAnomalyResultBean.java
index 834356d..cf9236c 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/MergedAnomalyResultBean.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/MergedAnomalyResultBean.java
@@ -20,6 +20,7 @@
package org.apache.pinot.thirdeye.datalayer.pojo;
import java.io.Serializable;
+import org.apache.pinot.thirdeye.anomaly.AnomalySeverity;
import org.apache.pinot.thirdeye.anomaly.AnomalyType;
import org.apache.pinot.thirdeye.common.dimension.DimensionMap;
import org.apache.pinot.thirdeye.constant.AnomalyResultSource;
@@ -60,6 +61,8 @@ public class MergedAnomalyResultBean extends AbstractBean
implements Comparable<
private Set<Long> childIds; // ids of the anomalies this anomaly merged from
private boolean isChild;
private AnomalyType type;
+ private AnomalySeverity severityLabel;
+
public Set<Long> getChildIds() {
return childIds;
@@ -264,6 +267,18 @@ public class MergedAnomalyResultBean extends AbstractBean
implements Comparable<
this.type = type;
}
+ public void setSeverityLabel(AnomalySeverity severityLabel) {
+ this.severityLabel = severityLabel;
+ }
+
+ public AnomalySeverity getSeverityLabel() {
+ // default severity level is debug
+ if (severityLabel == null) {
+ return AnomalySeverity.DEFAULT;
+ }
+ return severityLabel;
+ }
+
@Override
public int hashCode() {
return Objects.hash(getId(), startTime, endTime, collection, metric,
dimensions, score, impactToGlobal, avgBaselineVal, avgCurrentVal,
anomalyResultSource, metricUrn, detectionConfigId, childIds, isChild);
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionPipeline.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionPipeline.java
index d10a7f4..b6521da 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionPipeline.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionPipeline.java
@@ -19,7 +19,9 @@
package org.apache.pinot.thirdeye.detection;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Multimap;
+import java.util.HashMap;
import org.apache.pinot.thirdeye.common.dimension.DimensionMap;
import org.apache.pinot.thirdeye.dataframe.BooleanSeries;
import org.apache.pinot.thirdeye.dataframe.DataFrame;
@@ -244,6 +246,26 @@ public abstract class DetectionPipeline {
return anomalies;
}
+ /**
+ * Helper to initialize and run the next level wrapper
+ * @param nestedProps nested properties
+ * @return intermediate result of a detection pipeline
+ * @throws Exception
+ */
+ protected DetectionPipelineResult runNested(
+ Map<String, Object> nestedProps, final long startTime, final long
endTime) throws Exception {
+ Preconditions.checkArgument(nestedProps.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
+ Map<String, Object> properties = new HashMap<>(nestedProps);
+ DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
+ nestedConfig.setId(this.config.getId());
+ nestedConfig.setName(this.config.getName());
+ nestedConfig.setDescription(this.config.getDescription());
+ nestedConfig.setComponents(this.config.getComponents());
+ nestedConfig.setProperties(properties);
+ DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
startTime, endTime);
+ return pipeline.run();
+ }
+
// TODO anomaly should support multimap
private DimensionMap toFilterMap(Multimap<String, String> filters) {
DimensionMap map = new DimensionMap();
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/DimensionWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/DimensionWrapper.java
index a798cdb..77bdaa4 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/DimensionWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/DimensionWrapper.java
@@ -332,7 +332,8 @@ public class DimensionWrapper extends DetectionPipeline {
for (Map<String, Object> properties : this.nestedProperties) {
DetectionPipelineResult intermediate;
try {
- intermediate = this.runNested(metric, properties);
+ properties.put(this.nestedMetricUrnKey, metric.getUrn());
+ intermediate = this.runNested(properties, this.startTime,
this.endTime);
} catch (Exception e) {
LOG.warn("[DetectionConfigID{}] detecting anomalies for window {} to
{} failed for metric urn {}.",
this.config.getId(), this.start, this.end, metric.getUrn(), e);
@@ -446,23 +447,4 @@ public class DimensionWrapper extends DetectionPipeline {
}
return false;
}
-
- protected DetectionPipelineResult runNested(MetricEntity metric, Map<String,
Object> template) throws Exception {
- Preconditions.checkArgument(template.containsKey(PROP_CLASS_NAME), "Nested
missing " + PROP_CLASS_NAME);
-
- Map<String, Object> properties = new HashMap<>(template);
-
- properties.put(this.nestedMetricUrnKey, metric.getUrn());
-
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(properties);
- nestedConfig.setComponents(this.config.getComponents());
-
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- return pipeline.run();
- }
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyAlertFilterWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyAlertFilterWrapper.java
index c100306..776271c 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyAlertFilterWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyAlertFilterWrapper.java
@@ -95,26 +95,14 @@ public class LegacyAlertFilterWrapper extends
DetectionPipeline {
@Override
public DetectionPipelineResult run() throws Exception {
List<MergedAnomalyResultDTO> candidates = new ArrayList<>();
- for (Map<String, Object> propertiesRaw : this.nestedProperties) {
- Map<String, Object> properties = new HashMap<>(propertiesRaw);
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
-
- Preconditions.checkArgument(properties.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
-
+ for (Map<String, Object> properties : this.nestedProperties) {
if (!properties.containsKey(PROP_SPEC)) {
properties.put(PROP_SPEC, this.anomalyFunctionSpecs);
}
if (!properties.containsKey(PROP_ANOMALY_FUNCTION_CLASS)) {
properties.put(PROP_ANOMALY_FUNCTION_CLASS,
this.config.getProperties().get(PROP_ANOMALY_FUNCTION_CLASS));
}
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(properties);
-
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime - this.alertFilterLookBack, this.endTime);
-
- DetectionPipelineResult intermediate = pipeline.run();
+ DetectionPipelineResult intermediate = this.runNested(properties,
this.startTime - this.alertFilterLookBack, this.endTime);
candidates.addAll(intermediate.getAnomalies());
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyDimensionWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyDimensionWrapper.java
index 6ba74bb..31b75f7 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyDimensionWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyDimensionWrapper.java
@@ -83,25 +83,15 @@ public class LegacyDimensionWrapper extends
DimensionWrapper {
}
@Override
- protected DetectionPipelineResult runNested(MetricEntity metric, Map<String,
Object> template) throws Exception {
- Map<String, Object> properties = new HashMap<>(template);
-
- properties.put(this.nestedMetricUrnKey, metric.getUrn());
- if (!properties.containsKey(PROP_SPEC)) {
- properties.put(PROP_SPEC, this.anomalyFunctionSpecs);
+ protected DetectionPipelineResult runNested(
+ Map<String, Object> nestedProps, final long startTime, final long
endTime) throws Exception {
+ if (!nestedProps.containsKey(PROP_SPEC)) {
+ nestedProps.put(PROP_SPEC, this.anomalyFunctionSpecs);
}
- if (!properties.containsKey(PROP_ANOMALY_FUNCTION_CLASS)) {
- properties.put(PROP_ANOMALY_FUNCTION_CLASS,
this.anomalyFunctionClassName);
+ if (!nestedProps.containsKey(PROP_ANOMALY_FUNCTION_CLASS)) {
+ nestedProps.put(PROP_ANOMALY_FUNCTION_CLASS,
this.anomalyFunctionClassName);
}
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(properties);
-
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- return pipeline.run();
+ return super.runNested(nestedProps, startTime, endTime);
}
private static DetectionConfigDTO augmentConfig(DetectionConfigDTO config) {
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyMergeWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyMergeWrapper.java
index 7d3435e..51ea009 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyMergeWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/LegacyMergeWrapper.java
@@ -143,27 +143,14 @@ public class LegacyMergeWrapper extends DetectionPipeline
{
// generate anomalies
List<MergedAnomalyResultDTO> generated = new ArrayList<>();
- for (Map<String, Object> propertiesRaw : this.nestedProperties) {
- Map<String, Object> properties = new HashMap<>(propertiesRaw);
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
-
- Preconditions.checkArgument(properties.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
-
+ for (Map<String, Object> properties : this.nestedProperties) {
if (!properties.containsKey(PROP_SPEC)) {
properties.put(PROP_SPEC, this.anomalyFunctionSpecs);
}
if (!properties.containsKey(PROP_ANOMALY_FUNCTION_CLASS)) {
properties.put(PROP_ANOMALY_FUNCTION_CLASS,
this.anomalyFunctionClassName);
}
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(properties);
-
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- DetectionPipelineResult intermediate = pipeline.run();
-
+ DetectionPipelineResult intermediate = this.runNested(properties,
startTime, endTime);
generated.addAll(intermediate.getAnomalies());
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/MergeWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/MergeWrapper.java
index f9a55f3..ee67927 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/MergeWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/algorithm/MergeWrapper.java
@@ -123,20 +123,8 @@ public class MergeWrapper extends DetectionPipeline {
int i = 0;
Set<Long> lastTimeStamps = new HashSet<>();
for (Map<String, Object> properties : this.nestedProperties) {
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
-
- Preconditions.checkArgument(properties.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
-
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(properties);
- nestedConfig.setComponents(this.config.getComponents());
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- DetectionPipelineResult intermediate = pipeline.run();
+ DetectionPipelineResult intermediate = this.runNested(properties,
this.startTime, this.endTime);
lastTimeStamps.add(intermediate.getLastTimestamp());
-
generated.addAll(intermediate.getAnomalies());
predictionResults.addAll(intermediate.getPredictions());
evaluations.addAll(intermediate.getEvaluations());
@@ -376,6 +364,7 @@ public class MergeWrapper extends DetectionPipeline {
to.setWeight(from.getWeight());
to.setProperties(from.getProperties());
to.setType(from.getType());
+ to.setSeverityLabel(from.getSeverityLabel());
return to;
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
index c30120d..cef608a 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
@@ -24,5 +24,6 @@ public enum DetectionTag {
RULE_DETECTION,
ALGORITHM_FILTER,
RULE_FILTER,
- GROUPER
+ GROUPER,
+ LABELER
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/components/ThresholdSeverityLabeler.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/components/ThresholdSeverityLabeler.java
new file mode 100644
index 0000000..ff04015
--- /dev/null
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/components/ThresholdSeverityLabeler.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.pinot.thirdeye.detection.components;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.pinot.thirdeye.anomaly.AnomalySeverity;
+import org.apache.pinot.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
+import org.apache.pinot.thirdeye.detection.InputDataFetcher;
+import org.apache.pinot.thirdeye.detection.annotation.Components;
+import org.apache.pinot.thirdeye.detection.annotation.DetectionTag;
+import org.apache.pinot.thirdeye.detection.spec.SeverityThresholdLabelerSpec;
+import org.apache.pinot.thirdeye.detection.spi.components.Labeler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static
org.apache.pinot.thirdeye.detection.spec.SeverityThresholdLabelerSpec.Threshold;
+
+/**
+ * Threshold-based severity labeler, which labels anomalies with severity
based on deviation from baseline and duration
+ * of the anomalies. It tries to label anomalies from highest to lowest if
deviation or duration exceeds the threshold
+ */
+@Components(title = "ThresholdSeverityLabeler", type =
"THRESHOLD_SEVERITY_LABELER",
+ tags = {DetectionTag.LABELER}, description = "An threshold-based labeler
for anomaly severity")
+public class ThresholdSeverityLabeler implements
Labeler<SeverityThresholdLabelerSpec> {
+ private final static Logger LOG =
LoggerFactory.getLogger(ThresholdSeverityLabeler.class);
+ // severity map ordered by priority from top to bottom
+ private TreeMap<AnomalySeverity, Threshold> severityMap;
+
+ @Override
+ public void label(List<MergedAnomalyResultDTO> anomalies) {
+ for (MergedAnomalyResultDTO anomaly : anomalies) {
+ double currVal = anomaly.getAvgCurrentVal();
+ double baseVal = anomaly.getAvgBaselineVal();
+ if (Double.isNaN(currVal) || Double.isNaN(baseVal)) {
+ LOG.warn("Unable to label anomaly for detection {} from {} to {}, so
skipping labeling...",
+ anomaly.getDetectionConfigId(), anomaly.getStartTime(),
anomaly.getEndTime());
+ continue;
+ }
+ double deviation = Math.abs(currVal - baseVal) / baseVal;
+ long duration = anomaly.getEndTime() - anomaly.getStartTime();
+ for (Map.Entry<AnomalySeverity, Threshold> entry :
severityMap.entrySet()) {
+ if (deviation >= entry.getValue().change || duration >=
entry.getValue().duration) {
+ if (anomaly.getSeverityLabel() != entry.getKey()) {
+ // find the severity from highest to lowest
+ if (anomaly.getId() != null &&
anomaly.getSeverityLabel().compareTo(entry.getKey()) > 0) {
+ // only set renotify if the anomaly exists and its severity gets
higher
+ anomaly.setRenotify(true);
+ }
+ anomaly.setSeverityLabel(entry.getKey());
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void init(SeverityThresholdLabelerSpec spec, InputDataFetcher
dataFetcher) {
+ this.severityMap = new TreeMap<>();
+ for (String key : spec.getSeverity().keySet()) {
+ try {
+ AnomalySeverity severity = AnomalySeverity.valueOf(key);
+ this.severityMap.put(severity, spec.getSeverity().get(key));
+ } catch (IllegalArgumentException e) {
+ LOG.error("Cannot find valid anomaly severity, so ignoring...", e);
+ }
+ }
+ }
+}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/spec/SeverityThresholdLabelerSpec.java
similarity index 50%
copy from
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
copy to
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/spec/SeverityThresholdLabelerSpec.java
index c30120d..8390580 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/spec/SeverityThresholdLabelerSpec.java
@@ -17,12 +17,36 @@
* under the License.
*/
-package org.apache.pinot.thirdeye.detection.annotation;
-
-public enum DetectionTag {
- ALGORITHM_DETECTION,
- RULE_DETECTION,
- ALGORITHM_FILTER,
- RULE_FILTER,
- GROUPER
+package org.apache.pinot.thirdeye.detection.spec;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import java.util.Map;
+
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class SeverityThresholdLabelerSpec extends AbstractSpec{
+ private Map<String, Threshold> severity;
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class Threshold {
+ public double change = Double.MAX_VALUE;
+ public long duration = Long.MAX_VALUE;
+
+ public Threshold() {
+
+ }
+
+ public Threshold(double change, long duration) {
+ this.change = change;
+ this.duration = duration;
+ }
+ }
+
+ public Map<String, Threshold> getSeverity() {
+ return severity;
+ }
+
+ public void setSeverity(Map<String, Threshold> severity) {
+ this.severity = severity;
+ }
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/spi/components/Labeler.java
similarity index 65%
copy from
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
copy to
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/spi/components/Labeler.java
index c30120d..61541a4 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/annotation/DetectionTag.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/spi/components/Labeler.java
@@ -17,12 +17,17 @@
* under the License.
*/
-package org.apache.pinot.thirdeye.detection.annotation;
+package org.apache.pinot.thirdeye.detection.spi.components;
-public enum DetectionTag {
- ALGORITHM_DETECTION,
- RULE_DETECTION,
- ALGORITHM_FILTER,
- RULE_FILTER,
- GROUPER
+import java.util.List;
+import org.apache.pinot.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
+import org.apache.pinot.thirdeye.detection.spec.AbstractSpec;
+
+
+public interface Labeler <T extends AbstractSpec> extends BaseComponent<T> {
+ /**
+ * add or modify labels of anomalies in place
+ * @param anomalies
+ */
+ void label(List<MergedAnomalyResultDTO> anomalies);
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
index 2b8eb1f..565d277 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
@@ -46,7 +46,6 @@ import org.apache.commons.collections4.MapUtils;
*/
public class AnomalyFilterWrapper extends DetectionPipeline {
private static final String PROP_NESTED = "nested";
- private static final String PROP_CLASS_NAME = "className";
private static final String PROP_METRIC_URN = "metricUrn";
private static final String PROP_FILTER = "filter";
@@ -81,21 +80,7 @@ public class AnomalyFilterWrapper extends DetectionPipeline {
Set<Long> lastTimeStamps = new HashSet<>();
for (Map<String, Object> properties : this.nestedProperties) {
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
-
- Preconditions.checkArgument(properties.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
- HashMap<String, Object> nestedProp = new HashMap<>(properties);
- if (this.metricUrn != null){
- nestedProp.put(PROP_METRIC_URN, this.metricUrn);
- }
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(nestedProp);
- nestedConfig.setComponents(this.config.getComponents());
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- DetectionPipelineResult intermediate = pipeline.run();
+ DetectionPipelineResult intermediate = this.runNested(properties,
this.startTime, this.endTime);
lastTimeStamps.add(intermediate.getLastTimestamp());
diagnostics.putAll(intermediate.getDiagnostics());
evaluations.addAll(intermediate.getEvaluations());
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyLabelerWrapper.java
similarity index 51%
copy from
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
copy to
thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyLabelerWrapper.java
index 2b8eb1f..5d59e9b 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyFilterWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/AnomalyLabelerWrapper.java
@@ -20,10 +20,13 @@
package org.apache.pinot.thirdeye.detection.wrapper;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
+import org.apache.commons.collections4.MapUtils;
import org.apache.pinot.thirdeye.datalayer.dto.DetectionConfigDTO;
import org.apache.pinot.thirdeye.datalayer.dto.EvaluationDTO;
import org.apache.pinot.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
@@ -33,80 +36,48 @@ import
org.apache.pinot.thirdeye.detection.DetectionPipeline;
import org.apache.pinot.thirdeye.detection.DetectionPipelineResult;
import org.apache.pinot.thirdeye.detection.DetectionUtils;
import org.apache.pinot.thirdeye.detection.PredictionResult;
-import org.apache.pinot.thirdeye.detection.spi.components.AnomalyFilter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.collections4.MapUtils;
-
+import org.apache.pinot.thirdeye.detection.spi.components.Labeler;
/**
- * This anomaly filter wrapper runs the anomaly filter component to filter
anomalies generated by detector based on the filter implementation.
+ * This anomaly labeler wrapper runs the anomaly labeler component to label
anomalies generated by detector based on the labeler implementation.
*/
-public class AnomalyFilterWrapper extends DetectionPipeline {
+public class AnomalyLabelerWrapper extends DetectionPipeline {
private static final String PROP_NESTED = "nested";
- private static final String PROP_CLASS_NAME = "className";
- private static final String PROP_METRIC_URN = "metricUrn";
- private static final String PROP_FILTER = "filter";
+ private static final String PROP_LABELER = "labeler";
private final List<Map<String, Object>> nestedProperties;
- private final AnomalyFilter anomalyFilter;
- private String metricUrn;
+ private String labelerName;
+ private Labeler labeler;
- public AnomalyFilterWrapper(DataProvider provider, DetectionConfigDTO
config, long startTime, long endTime) {
+ public AnomalyLabelerWrapper(DataProvider provider, DetectionConfigDTO
config, long startTime, long endTime) {
super(provider, config, startTime, endTime);
Map<String, Object> properties = config.getProperties();
this.nestedProperties = ConfigUtils.getList(properties.get(PROP_NESTED));
-
Preconditions.checkArgument(this.config.getProperties().containsKey(PROP_FILTER));
- String detectorReferenceKey =
DetectionUtils.getComponentKey(MapUtils.getString(config.getProperties(),
PROP_FILTER));
-
Preconditions.checkArgument(this.config.getComponents().containsKey(detectorReferenceKey));
- this.anomalyFilter = (AnomalyFilter)
this.config.getComponents().get(detectorReferenceKey);
-
- this.metricUrn = MapUtils.getString(properties, PROP_METRIC_URN);
+
Preconditions.checkArgument(this.config.getProperties().containsKey(PROP_LABELER));
+ this.labelerName =
DetectionUtils.getComponentKey(MapUtils.getString(config.getProperties(),
PROP_LABELER));
+
Preconditions.checkArgument(this.config.getComponents().containsKey(this.labelerName));
+ this.labeler = (Labeler) this.config.getComponents().get(this.labelerName);
}
- /**
- * Runs the nested pipelines and calls the isQualified method in the anomaly
filter stage to check if an anomaly passes the filter.
- * @return the detection pipeline result
- * @throws Exception
- */
@Override
- public final DetectionPipelineResult run() throws Exception {
- List<MergedAnomalyResultDTO> candidates = new ArrayList<>();
- List<PredictionResult> predictionResults = new ArrayList<>();
+ public DetectionPipelineResult run() throws Exception {
+ List<MergedAnomalyResultDTO> anomalies = new ArrayList<>();
Map<String, Object> diagnostics = new HashMap<>();
+ List<PredictionResult> predictionResults = new ArrayList<>();
List<EvaluationDTO> evaluations = new ArrayList<>();
Set<Long> lastTimeStamps = new HashSet<>();
for (Map<String, Object> properties : this.nestedProperties) {
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
-
- Preconditions.checkArgument(properties.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
- HashMap<String, Object> nestedProp = new HashMap<>(properties);
- if (this.metricUrn != null){
- nestedProp.put(PROP_METRIC_URN, this.metricUrn);
- }
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(nestedProp);
- nestedConfig.setComponents(this.config.getComponents());
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- DetectionPipelineResult intermediate = pipeline.run();
+ DetectionPipelineResult intermediate = this.runNested(properties,
this.startTime, this.endTime);
lastTimeStamps.add(intermediate.getLastTimestamp());
- diagnostics.putAll(intermediate.getDiagnostics());
- evaluations.addAll(intermediate.getEvaluations());
predictionResults.addAll(intermediate.getPredictions());
- candidates.addAll(intermediate.getAnomalies());
+ evaluations.addAll(intermediate.getEvaluations());
+ diagnostics.putAll(intermediate.getDiagnostics());
+ anomalies.addAll(intermediate.getAnomalies());
}
-
- Collection<MergedAnomalyResultDTO> anomalies =
- Collections2.filter(candidates, mergedAnomaly -> mergedAnomaly != null
&& !mergedAnomaly.isChild() && anomalyFilter.isQualified(mergedAnomaly));
-
- return new DetectionPipelineResult(new ArrayList<>(anomalies),
DetectionUtils.consolidateNestedLastTimeStamps(lastTimeStamps),
+ this.labeler.label(anomalies);
+ return new DetectionPipelineResult(anomalies,
DetectionUtils.consolidateNestedLastTimeStamps(lastTimeStamps),
predictionResults, evaluations).setDiagnostics(diagnostics);
}
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/GrouperWrapper.java
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/GrouperWrapper.java
index b786cfa..6a13bbf 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/GrouperWrapper.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/wrapper/GrouperWrapper.java
@@ -49,7 +49,6 @@ import static
org.apache.pinot.thirdeye.detection.yaml.translator.DetectionConfi
*/
public class GrouperWrapper extends DetectionPipeline {
private static final String PROP_NESTED = "nested";
- private static final String PROP_CLASS_NAME = "className";
private static final String PROP_GROUPER = "grouper";
public static final String PROP_DETECTOR_COMPONENT_NAME =
"detectorComponentName";
@@ -88,20 +87,8 @@ public class GrouperWrapper extends DetectionPipeline {
Set<Long> lastTimeStamps = new HashSet<>();
for (Map<String, Object> properties : this.nestedProperties) {
- DetectionConfigDTO nestedConfig = new DetectionConfigDTO();
-
- Preconditions.checkArgument(properties.containsKey(PROP_CLASS_NAME),
"Nested missing " + PROP_CLASS_NAME);
-
- nestedConfig.setId(this.config.getId());
- nestedConfig.setName(this.config.getName());
- nestedConfig.setDescription(this.config.getDescription());
- nestedConfig.setProperties(properties);
- nestedConfig.setComponents(this.config.getComponents());
- DetectionPipeline pipeline = this.provider.loadPipeline(nestedConfig,
this.startTime, this.endTime);
-
- DetectionPipelineResult intermediate = pipeline.run();
+ DetectionPipelineResult intermediate = this.runNested(properties,
this.startTime, this.endTime);
lastTimeStamps.add(intermediate.getLastTimestamp());
-
predictionResults.addAll(intermediate.getPredictions());
evaluations.addAll(intermediate.getEvaluations());
diagnostics.putAll(intermediate.getDiagnostics());
diff --git
a/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdRuleAnomalyFilterTest.java
b/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdRuleAnomalyFilterTest.java
index ebee72f..63e244e 100644
---
a/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdRuleAnomalyFilterTest.java
+++
b/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdRuleAnomalyFilterTest.java
@@ -24,10 +24,8 @@ import
org.apache.pinot.thirdeye.datalayer.dto.DetectionConfigDTO;
import org.apache.pinot.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
import org.apache.pinot.thirdeye.datalayer.dto.MetricConfigDTO;
import org.apache.pinot.thirdeye.detection.DataProvider;
-import org.apache.pinot.thirdeye.detection.DefaultInputDataFetcher;
import org.apache.pinot.thirdeye.detection.DetectionPipelineResult;
import org.apache.pinot.thirdeye.detection.DetectionTestUtils;
-import org.apache.pinot.thirdeye.detection.InputDataFetcher;
import org.apache.pinot.thirdeye.detection.MockDataProvider;
import org.apache.pinot.thirdeye.detection.MockPipeline;
import org.apache.pinot.thirdeye.detection.MockPipelineLoader;
diff --git
a/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdSeverityLabelerTest.java
b/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdSeverityLabelerTest.java
new file mode 100644
index 0000000..56c13d4
--- /dev/null
+++
b/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/components/ThresholdSeverityLabelerTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pinot.thirdeye.detection.components;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import org.apache.pinot.thirdeye.anomaly.AnomalySeverity;
+import org.apache.pinot.thirdeye.dataframe.DataFrame;
+import org.apache.pinot.thirdeye.dataframe.util.MetricSlice;
+import org.apache.pinot.thirdeye.datalayer.dto.DatasetConfigDTO;
+import org.apache.pinot.thirdeye.datalayer.dto.DetectionConfigDTO;
+import org.apache.pinot.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
+import org.apache.pinot.thirdeye.datalayer.dto.MetricConfigDTO;
+import org.apache.pinot.thirdeye.detection.DataProvider;
+import org.apache.pinot.thirdeye.detection.DetectionPipelineResult;
+import org.apache.pinot.thirdeye.detection.DetectionTestUtils;
+import org.apache.pinot.thirdeye.detection.MockDataProvider;
+import org.apache.pinot.thirdeye.detection.MockPipeline;
+import org.apache.pinot.thirdeye.detection.MockPipelineLoader;
+import org.apache.pinot.thirdeye.detection.MockPipelineOutput;
+import org.apache.pinot.thirdeye.detection.wrapper.AnomalyLabelerWrapper;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.apache.pinot.thirdeye.dataframe.util.DataFrameUtils.*;
+import static
org.apache.pinot.thirdeye.detection.spec.SeverityThresholdLabelerSpec.Threshold;
+
+public class ThresholdSeverityLabelerTest {
+ private static final String METRIC_URN = "thirdeye:metric:123";
+ private static final long CONFIG_ID = 125L;
+
+ private List<MergedAnomalyResultDTO> anomalies;
+ private MockPipelineLoader loader;
+ private List<MockPipeline> runs;
+ private DataProvider testDataProvider;
+ private Map<String, Object> properties;
+ private DetectionConfigDTO config;
+ private Map<String, Object> specs;
+ private AnomalyLabelerWrapper thresholdSeverityLabeler;
+
+ @BeforeMethod
+ public void beforeMethod(){
+ Map<MetricSlice, DataFrame> aggregates = new HashMap<>();
+ aggregates.put(MetricSlice.from(123L, 1000L, 2000L), new
DataFrame().addSeries(COL_VALUE, 1200));
+ aggregates.put(MetricSlice.from(123L, 2000L, 3000L), new
DataFrame().addSeries(COL_VALUE, 1600));
+ aggregates.put(MetricSlice.from(123L, 3000L, 4000L), new
DataFrame().addSeries(COL_VALUE, 4800));
+ aggregates.put(MetricSlice.from(123L, 4000L, 6000L), new
DataFrame().addSeries(COL_VALUE, 2500));
+
+ MetricConfigDTO metricConfigDTO = new MetricConfigDTO();
+ metricConfigDTO.setId(123L);
+ metricConfigDTO.setName("thirdeye-test");
+ metricConfigDTO.setDataset("thirdeye-test-dataset");
+
+ DatasetConfigDTO datasetConfigDTO = new DatasetConfigDTO();
+ datasetConfigDTO.setId(124L);
+ datasetConfigDTO.setDataset("thirdeye-test-dataset");
+ datasetConfigDTO.setTimeDuration(2);
+ datasetConfigDTO.setTimeUnit(TimeUnit.MILLISECONDS);
+ datasetConfigDTO.setTimezone("UTC");
+
+ this.config = new DetectionConfigDTO();
+ this.config.setId(CONFIG_ID);
+ this.properties = new HashMap<>();
+ this.properties.put("nested",
Collections.singletonList(Collections.singletonMap("className", "dummy")));
+ this.properties.put("labeler", "$test_labeler");
+ this.specs = new HashMap<>();
+ this.specs.put("className", ThresholdSeverityLabeler.class.getName());
+
+ this.config.setComponentSpecs(ImmutableMap.of("test_labeler", this.specs));
+ this.config.setProperties(this.properties);
+
+ this.anomalies =
+ Arrays.asList(DetectionTestUtils.makeAnomaly(1000L, 2000L, METRIC_URN,
1200, 1000),
+ DetectionTestUtils.makeAnomaly(2000L, 3000, METRIC_URN, 1700,
2000),
+ DetectionTestUtils.makeAnomaly(3000L, 4000L, METRIC_URN, 4800,
5000),
+ DetectionTestUtils.makeAnomaly(4000L, 6000L, METRIC_URN, 2500,
3000));
+ this.runs = new ArrayList<>();
+ this.loader = new MockPipelineLoader(this.runs,
+ Collections.singletonList(new MockPipelineOutput(this.anomalies,
6000L)));
+ this.testDataProvider = new MockDataProvider().setLoader(this.loader)
+ .setMetrics(Collections.singletonList(metricConfigDTO))
+ .setDatasets(Collections.singletonList(datasetConfigDTO))
+ .setAggregates(aggregates);
+ }
+
+
+ @Test
+ public void testLabeling() throws Exception {
+ Map<String, Object> severityMap = new HashMap<>();
+ severityMap.put(AnomalySeverity.CRITICAL.toString(), new Threshold(0.2,
3000));
+ severityMap.put(AnomalySeverity.HIGH.toString(), new Threshold(0.15,
2000));
+ severityMap.put(AnomalySeverity.MEDIUM.toString(), new Threshold(0.12,
1500));
+ this.specs.put("severity", severityMap);
+ this.thresholdSeverityLabeler = new
AnomalyLabelerWrapper(this.testDataProvider, this.config, 1000L, 6000L);
+ DetectionPipelineResult result = this.thresholdSeverityLabeler.run();
+ List<MergedAnomalyResultDTO> anomalies = result.getAnomalies();
+ Assert.assertEquals(anomalies.size(), 4);
+ Assert.assertEquals(anomalies.get(0).getSeverityLabel(),
AnomalySeverity.CRITICAL);
+ Assert.assertEquals(anomalies.get(1).getSeverityLabel(),
AnomalySeverity.HIGH);
+ Assert.assertEquals(anomalies.get(2).getSeverityLabel(),
AnomalySeverity.DEFAULT);
+ Assert.assertEquals(anomalies.get(3).getSeverityLabel(),
AnomalySeverity.HIGH);
+ }
+
+ @Test
+ public void testLabelingSingleThreshold() throws Exception {
+ Map<String, Object> severityMap = new HashMap<>();
+ Threshold singleThreshold = new Threshold();
+ singleThreshold.duration = 2000L;
+ severityMap.put(AnomalySeverity.CRITICAL.toString(), singleThreshold);
+ severityMap.put(AnomalySeverity.HIGH.toString(), new Threshold(0.15,
2000));
+ this.specs.put("severity", severityMap);
+ this.thresholdSeverityLabeler = new
AnomalyLabelerWrapper(this.testDataProvider, this.config, 1000L, 6000L);
+ DetectionPipelineResult result = this.thresholdSeverityLabeler.run();
+ List<MergedAnomalyResultDTO> anomalies = result.getAnomalies();
+ Assert.assertEquals(anomalies.size(), 4);
+ Assert.assertEquals(anomalies.get(0).getSeverityLabel(),
AnomalySeverity.HIGH);
+ Assert.assertEquals(anomalies.get(1).getSeverityLabel(),
AnomalySeverity.HIGH);
+ Assert.assertEquals(anomalies.get(2).getSeverityLabel(),
AnomalySeverity.DEFAULT);
+ Assert.assertEquals(anomalies.get(3).getSeverityLabel(),
AnomalySeverity.CRITICAL);
+ }
+
+ @Test
+ public void testLabelingHigherSeverity() throws Exception {
+ Map<String, Object> severityMap = new HashMap<>();
+ severityMap.put(AnomalySeverity.CRITICAL.toString(), new Threshold(0.2,
3000));
+ severityMap.put(AnomalySeverity.HIGH.toString(), new Threshold(0.15,
2000));
+ severityMap.put(AnomalySeverity.MEDIUM.toString(), new Threshold(0.12,
1500));
+ this.specs.put("severity", severityMap);
+ MergedAnomalyResultDTO anomaly = DetectionTestUtils.makeAnomaly(4000L,
6000L, METRIC_URN, 2400, 3000);
+ anomaly.setSeverityLabel(AnomalySeverity.HIGH);
+ anomaly.setId(125L);
+ this.anomalies.set(this.anomalies.size() - 1, anomaly);
+ this.thresholdSeverityLabeler = new
AnomalyLabelerWrapper(this.testDataProvider, this.config, 1000L, 6000L);
+ DetectionPipelineResult result = this.thresholdSeverityLabeler.run();
+ List<MergedAnomalyResultDTO> anomalies = result.getAnomalies();
+ Assert.assertEquals(anomalies.size(), 4);
+ Assert.assertEquals(anomalies.get(3).getSeverityLabel(),
AnomalySeverity.CRITICAL);
+ Assert.assertTrue(anomalies.get(3).isRenotify());
+
+ }
+
+ @Test
+ public void testLabelingLowerSeverity() throws Exception {
+ Map<String, Object> severityMap = new HashMap<>();
+ severityMap.put(AnomalySeverity.CRITICAL.toString(), new Threshold(0.2,
3000));
+ severityMap.put(AnomalySeverity.HIGH.toString(), new Threshold(0.15,
2000));
+ severityMap.put(AnomalySeverity.MEDIUM.toString(), new Threshold(0.10,
1500));
+ this.specs.put("severity", severityMap);
+ MergedAnomalyResultDTO anomaly = DetectionTestUtils.makeAnomaly(4000L,
6000L, METRIC_URN, 2700, 3000);
+ anomaly.setSeverityLabel(AnomalySeverity.HIGH);
+ anomaly.setId(125L);
+ this.anomalies.set(this.anomalies.size() - 1, anomaly);
+ this.thresholdSeverityLabeler = new
AnomalyLabelerWrapper(this.testDataProvider, this.config, 1000L, 6000L);
+ DetectionPipelineResult result = this.thresholdSeverityLabeler.run();
+ List<MergedAnomalyResultDTO> anomalies = result.getAnomalies();
+ Assert.assertEquals(anomalies.size(), 4);
+ Assert.assertEquals(anomalies.get(3).getSeverityLabel(),
AnomalySeverity.MEDIUM);
+ Assert.assertFalse(anomalies.get(3).isRenotify());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]