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 e0b0f3a [TE] detection - site-wide impact rule filter (#3482)
e0b0f3a is described below
commit e0b0f3aff3f518af15bbdac7f37de676ad0eaf60
Author: Jihao Zhang <[email protected]>
AuthorDate: Wed Nov 14 15:47:34 2018 -0800
[TE] detection - site-wide impact rule filter (#3482)
- site-wide impact rule filter
- detection patterns (UP/DOWN) in absolute and percentage change detection
---
.../detection/DefaultInputDataFetcher.java | 6 +-
.../com/linkedin/thirdeye/detection/Pattern.java | 25 ++++++
.../components/AbsoluteChangeRuleDetector.java | 17 +++--
.../components/PercentageChangeRuleDetector.java | 14 +++-
.../SitewideImpactRuleAnomalyFilter.java | 67 ++++++++++++++++
.../components/ThresholdRuleAnomalyFilter.java | 2 +-
.../components/ThresholdRuleDetector.java | 2 +-
.../spec/AbsoluteChangeRuleDetectorSpec.java | 28 +++++--
.../spec/PercentageChangeRuleDetectorSpec.java | 9 +++
.../spec/SitewideImpactRuleAnomalyFilterSpec.java | 40 ++++++++++
.../components/AbsoluteChangeRuleDetectorTest.java | 5 +-
.../PercentageChangeRuleDetectorTest.java | 28 +++++--
.../SitewideImpactRuleAnomalyFilterTest.java | 89 ++++++++++++++++++++++
13 files changed, 301 insertions(+), 31 deletions(-)
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/DefaultInputDataFetcher.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/DefaultInputDataFetcher.java
index 5e3ce05..2d4bb3d 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/DefaultInputDataFetcher.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/DefaultInputDataFetcher.java
@@ -50,10 +50,8 @@ public class DefaultInputDataFetcher implements
InputDataFetcher {
*/
public InputData fetchData(InputDataSpec inputDataSpec) {
Map<MetricSlice, DataFrame> timeseries =
provider.fetchTimeseries(inputDataSpec.getTimeseriesSlices());
- Map<MetricSlice, DataFrame> aggregates =
- provider.fetchAggregates(inputDataSpec.getAggregateSlices(),
Collections.<String>emptyList());
- Multimap<AnomalySlice, MergedAnomalyResultDTO> existingAnomalies =
- provider.fetchAnomalies(inputDataSpec.getAnomalySlices(), configId);
+ Map<MetricSlice, DataFrame> aggregates =
provider.fetchAggregates(inputDataSpec.getAggregateSlices(),
Collections.<String>emptyList());
+ Multimap<AnomalySlice, MergedAnomalyResultDTO> existingAnomalies =
provider.fetchAnomalies(inputDataSpec.getAnomalySlices(), configId);
Multimap<EventSlice, EventDTO> events =
provider.fetchEvents(inputDataSpec.getEventSlices());
Map<Long, MetricConfigDTO> metrics =
provider.fetchMetrics(inputDataSpec.getMetricIds());
Map<String, DatasetConfigDTO> datasets =
provider.fetchDatasets(inputDataSpec.getDatasetNames());
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/Pattern.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/Pattern.java
new file mode 100644
index 0000000..40b14bf
--- /dev/null
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/Pattern.java
@@ -0,0 +1,25 @@
+/*
+ * 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 com.linkedin.thirdeye.detection;
+
+/**
+ * Up or down detection pattern
+ */
+public enum Pattern {
+ UP,
+ DOWN
+}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetector.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetector.java
index a8008b8..0c812c7 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetector.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetector.java
@@ -24,6 +24,7 @@ import com.linkedin.thirdeye.datalayer.dto.DatasetConfigDTO;
import com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
import com.linkedin.thirdeye.detection.DetectionUtils;
import com.linkedin.thirdeye.detection.InputDataFetcher;
+import com.linkedin.thirdeye.detection.Pattern;
import com.linkedin.thirdeye.detection.annotation.Components;
import com.linkedin.thirdeye.detection.annotation.DetectionTag;
import com.linkedin.thirdeye.detection.annotation.Param;
@@ -46,21 +47,24 @@ import static
com.linkedin.thirdeye.dataframe.util.DataFrameUtils.*;
type = "ABSOLUTE_CHANGE_RULE",
tags = {DetectionTag.RULE_DETECTION},
presentation = {
- @PresentationOption(name = "absolute value", template = "comparing
${offset} is more than ${difference}"),
+ @PresentationOption(name = "absolute value", template = "comparing
${offset} is ${pattern} more than ${difference}"),
},
params = {
@Param(name = "offset", defaultValue = "wo1w"),
- @Param(name = "change", placeholder = "value")
+ @Param(name = "change", placeholder = "value"),
+ @Param(name = "pattern", allowableValues = {"up", "down"})
})
public class AbsoluteChangeRuleDetector implements
AnomalyDetector<AbsoluteChangeRuleDetectorSpec> {
private double absoluteChange;
private InputDataFetcher dataFetcher;
private Baseline baseline;
+ private Pattern pattern;
private static final String COL_CURR = "current";
private static final String COL_BASE = "baseline";
- private static final String COL_CHANGE = "change";
private static final String COL_ANOMALY = "anomaly";
private static final String COL_DIFF = "diff";
+ private static final String COL_PATTERN = "pattern";
+ private static final String COL_DIFF_VIOLATION = "diff_violation";
@Override
public List<MergedAnomalyResultDTO> runDetection(Interval window, String
metricUrn) {
@@ -82,7 +86,9 @@ public class AbsoluteChangeRuleDetector implements
AnomalyDetector<AbsoluteChang
// absolute change
if (!Double.isNaN(this.absoluteChange)) {
- df.addSeries(COL_ANOMALY,
df.getDoubles(COL_DIFF).abs().gte(this.absoluteChange));
+ df.addSeries(COL_PATTERN, this.pattern.equals(Pattern.UP) ?
df.getDoubles(COL_DIFF).gt(0) : df.getDoubles(COL_DIFF).lt(0));
+ df.addSeries(COL_DIFF_VIOLATION,
df.getDoubles(COL_DIFF).abs().gte(this.absoluteChange));
+ df.mapInPlace(BooleanSeries.ALL_TRUE, COL_ANOMALY, COL_PATTERN,
COL_DIFF_VIOLATION);
}
// make anomalies
@@ -92,10 +98,11 @@ public class AbsoluteChangeRuleDetector implements
AnomalyDetector<AbsoluteChang
@Override
public void init(AbsoluteChangeRuleDetectorSpec spec, InputDataFetcher
dataFetcher) {
- this.absoluteChange = spec.getAbsoluteChangeChange();
+ this.absoluteChange = spec.getAbsoluteChange();
this.dataFetcher = dataFetcher;
String timezone = spec.getTimezone();
String offset = spec.getOffset();
this.baseline = BaselineParsingUtils.parseOffset(offset, timezone);
+ this.pattern = Pattern.valueOf(spec.getPattern().toUpperCase());
}
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetector.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetector.java
index 1814e6c..14f09d5 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetector.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetector.java
@@ -25,6 +25,7 @@ import com.linkedin.thirdeye.datalayer.dto.DatasetConfigDTO;
import com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
import com.linkedin.thirdeye.detection.DetectionUtils;
import com.linkedin.thirdeye.detection.InputDataFetcher;
+import com.linkedin.thirdeye.detection.Pattern;
import com.linkedin.thirdeye.detection.annotation.Components;
import com.linkedin.thirdeye.detection.annotation.DetectionTag;
import com.linkedin.thirdeye.detection.annotation.Param;
@@ -49,20 +50,24 @@ import static
com.linkedin.thirdeye.dataframe.util.DataFrameUtils.*;
description = "Computes a multi-week aggregate baseline and compares the
current value "
+ "based on relative change.",
presentation = {
- @PresentationOption(name = "percentage change", template = "comparing
${offset} is more than ${change}")
+ @PresentationOption(name = "percentage change", template = "comparing
${offset} is ${pattern} more than ${change}")
},
params = {
@Param(name = "offset", defaultValue = "wo1w"),
- @Param(name = "change", placeholder = "value")
+ @Param(name = "change", placeholder = "value"),
+ @Param(name = "pattern", allowableValues = {"up", "down"})
})
public class PercentageChangeRuleDetector implements
AnomalyDetector<PercentageChangeRuleDetectorSpec> {
private double percentageChange;
private InputDataFetcher dataFetcher;
private Baseline baseline;
+ private Pattern pattern;
private static final String COL_CURR = "current";
private static final String COL_BASE = "baseline";
private static final String COL_CHANGE = "change";
private static final String COL_ANOMALY = "anomaly";
+ private static final String COL_PATTERN = "pattern";
+ private static final String COL_CHANGE_VIOLATION = "change_violation";
@Override
public List<MergedAnomalyResultDTO> runDetection(Interval window, String
metricUrn) {
@@ -89,7 +94,9 @@ public class PercentageChangeRuleDetector implements
AnomalyDetector<PercentageC
// relative change
if (!Double.isNaN(this.percentageChange)) {
- df.addSeries(COL_ANOMALY,
df.getDoubles(COL_CHANGE).abs().gte(this.percentageChange));
+ df.addSeries(COL_PATTERN, this.pattern.equals(Pattern.UP) ?
df.getDoubles(COL_CHANGE).gt(0) : df.getDoubles(COL_CHANGE).lt(0));
+ df.addSeries(COL_CHANGE_VIOLATION,
df.getDoubles(COL_CHANGE).abs().gte(this.percentageChange));
+ df.mapInPlace(BooleanSeries.ALL_TRUE, COL_ANOMALY, COL_PATTERN,
COL_CHANGE_VIOLATION);
}
// anomalies
@@ -104,5 +111,6 @@ public class PercentageChangeRuleDetector implements
AnomalyDetector<PercentageC
String timezone = spec.getTimezone();
String offset = spec.getOffset();
this.baseline = BaselineParsingUtils.parseOffset(offset, timezone);
+ this.pattern = Pattern.valueOf(spec.getPattern().toUpperCase());
}
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/SitewideImpactRuleAnomalyFilter.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/SitewideImpactRuleAnomalyFilter.java
new file mode 100644
index 0000000..fa95b44
--- /dev/null
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/SitewideImpactRuleAnomalyFilter.java
@@ -0,0 +1,67 @@
+package com.linkedin.thirdeye.detection.components;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.linkedin.thirdeye.dashboard.resources.v2.BaselineParsingUtils;
+import com.linkedin.thirdeye.dataframe.DataFrame;
+import com.linkedin.thirdeye.dataframe.util.MetricSlice;
+import com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
+import com.linkedin.thirdeye.detection.InputDataFetcher;
+import com.linkedin.thirdeye.detection.annotation.Components;
+import
com.linkedin.thirdeye.detection.spec.SitewideImpactRuleAnomalyFilterSpec;
+import com.linkedin.thirdeye.detection.spi.components.AnomalyFilter;
+import com.linkedin.thirdeye.detection.spi.model.InputDataSpec;
+import com.linkedin.thirdeye.rootcause.impl.MetricEntity;
+import com.linkedin.thirdeye.rootcause.timeseries.Baseline;
+import java.util.Arrays;
+import java.util.Map;
+
+import static com.linkedin.thirdeye.dataframe.util.DataFrameUtils.*;
+
+/**
+ * Site-wide impact anomaly filter
+ */
+@Components(type = "SITEWIDE_IMPACT_FILTER")
+public class SitewideImpactRuleAnomalyFilter implements
AnomalyFilter<SitewideImpactRuleAnomalyFilterSpec> {
+ private double threshold;
+ private InputDataFetcher dataFetcher;
+ private Baseline baseline;
+ private String siteWideMetricUrn;
+
+ @Override
+ public boolean isQualified(MergedAnomalyResultDTO anomaly) {
+ MetricEntity me = MetricEntity.fromURN(anomaly.getMetricUrn());
+ MetricSlice currentSlice =
+ MetricSlice.from(me.getId(), anomaly.getStartTime(),
anomaly.getEndTime(), me.getFilters());
+ MetricSlice baselineSlice = this.baseline.scatter(currentSlice).get(0);
+
+ String siteWideImpactMetricUrn =
Strings.isNullOrEmpty(this.siteWideMetricUrn) ? anomaly.getMetricUrn() :
this.siteWideMetricUrn;
+ MetricEntity siteWideEntity =
MetricEntity.fromURN(siteWideImpactMetricUrn).withFilters(ArrayListMultimap.<String,
String>create());
+ MetricSlice siteWideSlice =
this.baseline.scatter(MetricSlice.from(siteWideEntity.getId(),
anomaly.getStartTime(), anomaly.getEndTime())).get(0);
+
+ Map<MetricSlice, DataFrame> aggregates =
+ this.dataFetcher.fetchData(new
InputDataSpec().withAggregateSlices(Arrays.asList(currentSlice, baselineSlice,
siteWideSlice))).getAggregates();
+
+ double currentValue = getValueFromAggregates(currentSlice, aggregates);
+ double baselineValue = getValueFromAggregates(baselineSlice, aggregates);
+ double siteWideBaselineValue = getValueFromAggregates(siteWideSlice,
aggregates);
+
+ if (siteWideBaselineValue != 0 && (Math.abs(currentValue - baselineValue)
/ siteWideBaselineValue) < this.threshold) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void init(SitewideImpactRuleAnomalyFilterSpec spec, InputDataFetcher
dataFetcher) {
+ this.dataFetcher = dataFetcher;
+ this.baseline = BaselineParsingUtils.parseOffset(spec.getOffset(),
spec.getTimezone());
+ this.threshold = spec.getThreshold();
+ this.siteWideMetricUrn = spec.getSitewideMetricUrn();
+ }
+
+ private double getValueFromAggregates(MetricSlice slice, Map<MetricSlice,
DataFrame> aggregates) {
+ return aggregates.get(slice).getDouble(COL_VALUE, 0);
+ }
+}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleAnomalyFilter.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleAnomalyFilter.java
index cc6f8cc..b496d5e 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleAnomalyFilter.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleAnomalyFilter.java
@@ -40,7 +40,7 @@ import static
com.linkedin.thirdeye.dataframe.util.DataFrameUtils.*;
*/
@Components(title = "Aggregate Threshold Filter", type =
"THRESHOLD_RULE_FILTER", tags = {
DetectionTag.RULE_FILTER}, description = "Threshold rule filter. filters
the anomalies if either the min or max thresholds do not satisfied.",
presentation = {
- @PresentationOption(name = "absolute value", description = "aggregated
absolute value within a time period", template = "is between ${min} and
${max}")}, params = {
+ @PresentationOption(name = "absolute value", description = "aggregated
absolute value within a time period", template = "is higher than ${min} and
lower than ${max}")}, params = {
@Param(name = "min", placeholder = "value"), @Param(name = "max",
placeholder = "value")})
public class ThresholdRuleAnomalyFilter implements
AnomalyFilter<ThresholdRuleFilterSpec> {
private double min;
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleDetector.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleDetector.java
index 0fc2230..40809e7 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleDetector.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/components/ThresholdRuleDetector.java
@@ -41,7 +41,7 @@ import static
com.linkedin.thirdeye.dataframe.util.DataFrameUtils.*;
@Components(title = "Threshold", type = "THRESHOLD", tags = {
DetectionTag.RULE_DETECTION}, description = "Simple threshold rule
algorithm with (optional) upper and lower bounds on a metric value.",
presentation = {
- @PresentationOption(name = "absolute value", description = "aggregated
absolute value within a time period", template = "is lower than ${min} or
higher than ${max}")}, params = {
+ @PresentationOption(name = "absolute value", template = "is lower than
${min} or higher than ${max}")}, params = {
@Param(name = "min", placeholder = "value"), @Param(name = "max",
placeholder = "value")})
public class ThresholdRuleDetector implements
AnomalyDetector<ThresholdRuleDetectorSpec> {
private final String COL_TOO_HIGH = "tooHigh";
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/AbsoluteChangeRuleDetectorSpec.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/AbsoluteChangeRuleDetectorSpec.java
index c69659e..c6b25aa 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/AbsoluteChangeRuleDetectorSpec.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/AbsoluteChangeRuleDetectorSpec.java
@@ -16,10 +16,30 @@
package com.linkedin.thirdeye.detection.spec;
+import com.linkedin.thirdeye.detection.Pattern;
+
+
public class AbsoluteChangeRuleDetectorSpec extends AbstractSpec {
private double absoluteChange = Double.NaN;
private String offset = "wo1w";
private String timezone = "UTC";
+ private String pattern;
+
+ public double getAbsoluteChange() {
+ return absoluteChange;
+ }
+
+ public void setAbsoluteChange(double absoluteChange) {
+ this.absoluteChange = absoluteChange;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
public String getTimezone() {
return timezone;
@@ -36,12 +56,4 @@ public class AbsoluteChangeRuleDetectorSpec extends
AbstractSpec {
public void setOffset(String offset) {
this.offset = offset;
}
-
- public double getAbsoluteChangeChange() {
- return absoluteChange;
- }
-
- public void setAbsoluteChangeChange(double absoluteChange) {
- this.absoluteChange = absoluteChange;
- }
}
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/PercentageChangeRuleDetectorSpec.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/PercentageChangeRuleDetectorSpec.java
index c1e78fb..d58533e 100644
---
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/PercentageChangeRuleDetectorSpec.java
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/PercentageChangeRuleDetectorSpec.java
@@ -20,6 +20,15 @@ public class PercentageChangeRuleDetectorSpec extends
AbstractSpec {
private double percentageChange = Double.NaN;
private String offset = "wo1w";
private String timezone = "UTC";
+ private String pattern;
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
public String getTimezone() {
return timezone;
diff --git
a/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/SitewideImpactRuleAnomalyFilterSpec.java
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/SitewideImpactRuleAnomalyFilterSpec.java
new file mode 100644
index 0000000..7da2799
--- /dev/null
+++
b/thirdeye/thirdeye-pinot/src/main/java/com/linkedin/thirdeye/detection/spec/SitewideImpactRuleAnomalyFilterSpec.java
@@ -0,0 +1,40 @@
+package com.linkedin.thirdeye.detection.spec;
+
+public class SitewideImpactRuleAnomalyFilterSpec extends AbstractSpec {
+ private String timezone = "UTC";
+ private String sitewideMetricUrn;
+ private double threshold = Double.NaN;
+ private String offset = "wo1w";
+
+ public String getOffset() {
+ return offset;
+ }
+
+ public void setOffset(String offset) {
+ this.offset = offset;
+ }
+
+ public String getTimezone() {
+ return timezone;
+ }
+
+ public void setTimezone(String timezone) {
+ this.timezone = timezone;
+ }
+
+ public String getSitewideMetricUrn() {
+ return sitewideMetricUrn;
+ }
+
+ public void setSitewideMetricUrn(String sitewideMetricUrn) {
+ this.sitewideMetricUrn = sitewideMetricUrn;
+ }
+
+ public double getThreshold() {
+ return threshold;
+ }
+
+ public void setThreshold(double threshold) {
+ this.threshold = threshold;
+ }
+}
diff --git
a/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetectorTest.java
b/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetectorTest.java
index fc73e8d..8a25904 100644
---
a/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetectorTest.java
+++
b/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/AbsoluteChangeRuleDetectorTest.java
@@ -78,10 +78,11 @@ public class AbsoluteChangeRuleDetectorTest {
}
@Test
- public void testWeekOverWeekDifference() throws Exception {
+ public void testWeekOverWeekDifference() {
AbsoluteChangeRuleDetector detector = new AbsoluteChangeRuleDetector();
AbsoluteChangeRuleDetectorSpec spec = new AbsoluteChangeRuleDetectorSpec();
- spec.setAbsoluteChangeChange(400);
+ spec.setAbsoluteChange(400);
+ spec.setPattern("up");
detector.init(spec, new DefaultInputDataFetcher(this.provider, -1));
List<MergedAnomalyResultDTO> anomalies = detector.runDetection(new
Interval(1814400000L, 2419200000L), "thirdeye:metric:1");
diff --git
a/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetectorTest.java
b/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetectorTest.java
index b1e878c..d3f4e6d 100644
---
a/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetectorTest.java
+++
b/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/PercentageChangeRuleDetectorTest.java
@@ -78,9 +78,10 @@ public class PercentageChangeRuleDetectorTest {
}
@Test
- public void testWeekOverWeekChange() throws Exception {
+ public void testWeekOverWeekChange() {
PercentageChangeRuleDetector detector = new PercentageChangeRuleDetector();
PercentageChangeRuleDetectorSpec spec = new
PercentageChangeRuleDetectorSpec();
+ spec.setPattern("up");
spec.setPercentageChange(0.4);
detector.init(spec, new DefaultInputDataFetcher(this.provider, -1));
List<MergedAnomalyResultDTO> anomalies = detector.runDetection(new
Interval(1814400000L, 2419200000L), "thirdeye:metric:1");
@@ -92,23 +93,36 @@ public class PercentageChangeRuleDetectorTest {
}
@Test
- public void testThreeWeekMedianChange() throws Exception {
+ public void testThreeWeekMedianChange() {
PercentageChangeRuleDetector detector = new PercentageChangeRuleDetector();
PercentageChangeRuleDetectorSpec spec = new
PercentageChangeRuleDetectorSpec();
spec.setPercentageChange(0.3);
spec.setOffset("median3w");
+ spec.setPattern("up");
detector.init(spec, new DefaultInputDataFetcher(this.provider, -1));
List<MergedAnomalyResultDTO> anomalies = detector.runDetection(new
Interval(1814400000L, 2419200000L), "thirdeye:metric:1");
- Assert.assertEquals(anomalies.size(), 5);
+ Assert.assertEquals(anomalies.size(), 4);
Assert.assertEquals(anomalies.get(0).getStartTime(), 2005200000L);
Assert.assertEquals(anomalies.get(0).getEndTime(), 2008800000L);
Assert.assertEquals(anomalies.get(1).getStartTime(), 2134800000L);
Assert.assertEquals(anomalies.get(1).getEndTime(), 2138400000L);
Assert.assertEquals(anomalies.get(2).getStartTime(), 2152800000L);
Assert.assertEquals(anomalies.get(2).getEndTime(), 2156400000L);
- Assert.assertEquals(anomalies.get(3).getStartTime(), 2181600000L);
- Assert.assertEquals(anomalies.get(3).getEndTime(), 2185200000L);
- Assert.assertEquals(anomalies.get(4).getStartTime(), 2322000000L);
- Assert.assertEquals(anomalies.get(4).getEndTime(), 2325600000L);
+ Assert.assertEquals(anomalies.get(3).getStartTime(), 2322000000L);
+ Assert.assertEquals(anomalies.get(3).getEndTime(), 2325600000L);
+ }
+
+ @Test
+ public void testThreeWeekMedianChangeDown() {
+ PercentageChangeRuleDetector detector = new PercentageChangeRuleDetector();
+ PercentageChangeRuleDetectorSpec spec = new
PercentageChangeRuleDetectorSpec();
+ spec.setPercentageChange(0.3);
+ spec.setOffset("median3w");
+ spec.setPattern("down");
+ detector.init(spec, new DefaultInputDataFetcher(this.provider, -1));
+ List<MergedAnomalyResultDTO> anomalies = detector.runDetection(new
Interval(1814400000L, 2419200000L), "thirdeye:metric:1");
+ Assert.assertEquals(anomalies.size(), 1);
+ Assert.assertEquals(anomalies.get(0).getStartTime(), 2181600000L);
+ Assert.assertEquals(anomalies.get(0).getEndTime(), 2185200000L);
}
}
\ No newline at end of file
diff --git
a/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/SitewideImpactRuleAnomalyFilterTest.java
b/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/SitewideImpactRuleAnomalyFilterTest.java
new file mode 100644
index 0000000..fb9f57a
--- /dev/null
+++
b/thirdeye/thirdeye-pinot/src/test/java/com/linkedin/thirdeye/detection/components/SitewideImpactRuleAnomalyFilterTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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 com.linkedin.thirdeye.detection.components;
+
+import com.linkedin.thirdeye.dataframe.DataFrame;
+import com.linkedin.thirdeye.dataframe.util.MetricSlice;
+import com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
+import com.linkedin.thirdeye.detection.DataProvider;
+import com.linkedin.thirdeye.detection.DefaultInputDataFetcher;
+import com.linkedin.thirdeye.detection.DetectionTestUtils;
+import com.linkedin.thirdeye.detection.MockDataProvider;
+import
com.linkedin.thirdeye.detection.spec.SitewideImpactRuleAnomalyFilterSpec;
+import com.linkedin.thirdeye.rootcause.timeseries.Baseline;
+import com.linkedin.thirdeye.rootcause.timeseries.BaselineAggregate;
+import com.linkedin.thirdeye.rootcause.timeseries.BaselineAggregateType;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.joda.time.DateTimeZone;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static com.linkedin.thirdeye.dataframe.util.DataFrameUtils.*;
+
+
+public class SitewideImpactRuleAnomalyFilterTest {
+ private static final String METRIC_URN = "thirdeye:metric:123";
+
+ private List<MergedAnomalyResultDTO> anomalies;
+ private DataProvider testDataProvider;
+ private Baseline baseline;
+
+ @BeforeMethod
+ public void beforeMethod() {
+ this.baseline =
BaselineAggregate.fromWeekOverWeek(BaselineAggregateType.MEDIAN, 1, 1,
DateTimeZone.forID("UTC"));
+
+ MetricSlice slice1 = MetricSlice.from(123L, 0, 2);
+ MetricSlice baselineSlice1 = this.baseline.scatter(slice1).get(0);
+ MetricSlice slice2 = MetricSlice.from(123L, 4, 6);
+ MetricSlice baselineSlice2 = this.baseline.scatter(slice2).get(0);
+
+ Map<MetricSlice, DataFrame> aggregates = new HashMap<>();
+ aggregates.put(slice1, new DataFrame().addSeries(COL_VALUE, 150));
+ aggregates.put(baselineSlice1, new DataFrame().addSeries(COL_VALUE, 200));
+ aggregates.put(slice2, new DataFrame().addSeries(COL_VALUE, 500));
+ aggregates.put(baselineSlice2, new DataFrame().addSeries(COL_VALUE, 1000));
+
+ this.anomalies = Arrays.asList(makeAnomaly(0, 2), makeAnomaly(4, 6));
+
+ this.testDataProvider = new MockDataProvider().setAggregates(aggregates);
+ }
+
+ @Test
+ public void testSiteWideImpactFilter() {
+ SitewideImpactRuleAnomalyFilterSpec spec = new
SitewideImpactRuleAnomalyFilterSpec();
+ spec.setThreshold(0.5);
+ spec.setOffset("median3w");
+ SitewideImpactRuleAnomalyFilter filter = new
SitewideImpactRuleAnomalyFilter();
+ filter.init(spec, new DefaultInputDataFetcher(this.testDataProvider,
125L));
+
+ List<Boolean> results =
+ this.anomalies.stream().map(anomaly ->
filter.isQualified(anomaly)).collect(Collectors.toList());
+ Assert.assertEquals(results, Arrays.asList(false, true));
+ }
+
+ private static MergedAnomalyResultDTO makeAnomaly(long start, long end) {
+ Map<String, String> dimensions = new HashMap<>();
+ MergedAnomalyResultDTO anomaly = DetectionTestUtils.makeAnomaly(125L,
start, end, dimensions);
+ anomaly.setMetricUrn(METRIC_URN);
+ return anomaly;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]