You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ji...@apache.org on 2019/06/19 17:10:12 UTC

[incubator-pinot] branch master updated: [TE] frontend - harleyjj/alert-overview - show bounds on Alert Overview (#4314)

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 2377037  [TE] frontend - harleyjj/alert-overview - show bounds on Alert Overview (#4314)
2377037 is described below

commit 2377037f0c816b722e156ca151fa15effca4de1a
Author: Harley Jackson <hj...@linkedin.com>
AuthorDate: Wed Jun 19 10:10:07 2019 -0700

    [TE] frontend - harleyjj/alert-overview - show bounds on Alert Overview (#4314)
    
    * [TE] pinot - harleyjj/granularity - get dataset details by name
    
    * [TE] frontend - harleyjj/alert-overview - show bounds, rules, and predicted on Alert Overview for daily granularity with no dimensions
---
 .../app/pods/components/alert-details/component.js | 70 +++++++++++++++-------
 .../app/pods/components/alert-details/template.hbs |  4 +-
 .../pods/components/timeseries-chart/component.js  | 12 +++-
 .../app/pods/manage/explore/route.js               |  7 ++-
 .../app/pods/manage/explore/template.hbs           |  1 +
 thirdeye/thirdeye-frontend/app/utils/anomaly.js    | 19 +++++-
 .../thirdeye-frontend/app/utils/api/anomaly.js     | 18 +++++-
 thirdeye/thirdeye-frontend/app/utils/utils.js      | 14 ++++-
 .../thirdeye/detection/DetectionResource.java      | 10 +++-
 9 files changed, 124 insertions(+), 31 deletions(-)

diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
index d1c8a29..9cd60ae 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
@@ -22,6 +22,7 @@ import { colorMapping, makeTime, toMetricLabel, extractTail } from 'thirdeye-fro
 import { getYamlPreviewAnomalies,
   getAnomaliesByAlertId,
   getFormattedDuration,
+  getBoundsAndAnomalies,
   anomalyResponseMapNew,
   anomalyResponseObj,
   anomalyResponseObjNew,
@@ -91,6 +92,7 @@ export default Component.extend({
   isLoadingTimeSeries: false,
   granularity: null,
   alertYaml: null,
+  dimensionExploration: null,
 
 
 
@@ -99,10 +101,11 @@ export default Component.extend({
    * @type {Array}
    */
   baselineOptions: computed(
-    'isPreviewMode',
+    'showRules',
     function() {
+      const showRules = get(this, 'showRules');
       let options;
-      if (get(this, 'isPreviewMode')) {
+      if (showRules) {
         options = [
           { name: 'predicted', isActive: true},
           { name: 'wo1w', isActive: false},
@@ -163,7 +166,7 @@ export default Component.extend({
           return {
             detectorName: detector,
             name: nameOnly
-          }
+          };
         });
       }
       return [];
@@ -183,6 +186,24 @@ export default Component.extend({
   ),
 
   /**
+   * flag to differentiate whether we show bounds and rules or not
+   * @type {Boolean}
+   */
+  showRules: computed(
+    'isPreviewMode',
+    'granularity',
+    'dimensionExploration',
+    function() {
+      const {
+        isPreviewMode,
+        granularity,
+        dimensionExploration
+      } = this.getProperties('isPreviewMode', 'granularity', 'dimensionExploration');
+      return (isPreviewMode || (!dimensionExploration && (granularity === 'DAYS')));
+    }
+  ),
+
+  /**
    * dimensions to display in dimensions dropdown
    * @type {Array}
    */
@@ -361,18 +382,19 @@ export default Component.extend({
     'metricUrn',
     'selectedRule',
     'selectedDimension',
+    'showRules',
     function() {
       let currentAnomalies = [];
       const {
-        metricUrn, anomalies, selectedRule
-      } = getProperties(this, 'metricUrn', 'anomalies', 'selectedRule');
+        metricUrn, anomalies, selectedRule, showRules
+      } = getProperties(this, 'metricUrn', 'anomalies', 'selectedRule', 'showRules');
       if (!_.isEmpty(anomalies)) {
 
         currentAnomalies = anomalies.filter(anomaly => {
           if (anomaly.metricUrn === metricUrn) {
-            if(get(this, 'isPreviewMode') && anomaly.properties && typeof anomaly.properties === 'object' && selectedRule && typeof selectedRule === 'object') {
+            if(showRules && anomaly.properties && typeof anomaly.properties === 'object' && selectedRule && typeof selectedRule === 'object') {
               return (anomaly.properties.detectorComponentName.includes(selectedRule.detectorName));
-            } else if (!get(this, 'isPreviewMode')) {
+            } else if (!showRules) {
               // This is necessary until we surface rule selector in Alert Overview
               return true;
             }
@@ -417,8 +439,8 @@ export default Component.extend({
     'metricUrn',
     function () {
       const {
-        currentAnomalies, timeseries, baseline
-      } = getProperties(this, 'currentAnomalies', 'timeseries', 'baseline');
+        currentAnomalies, timeseries, baseline, showRules
+      } = getProperties(this, 'currentAnomalies', 'timeseries', 'baseline', 'showRules');
 
       const series = {};
       if (!_.isEmpty(currentAnomalies)) {
@@ -440,7 +462,7 @@ export default Component.extend({
       }
 
       // The current time series has a different naming convention in Preview
-      if (get(this, 'isPreviewMode')) {
+      if (showRules) {
         if (timeseries && !_.isEmpty(timeseries.current)) {
           series['Current'] = {
             timestamps: timeseries.timestamp,
@@ -628,9 +650,10 @@ export default Component.extend({
       analysisRange,
       anomaliesRange,
       notifications,
-      isPreviewMode,
-      alertId
-    } = this.getProperties('analysisRange', 'anomaliesRange', 'notifications', 'isPreviewMode', 'alertId');
+      showRules,
+      alertId,
+      granularity
+    } = this.getProperties('analysisRange', 'anomaliesRange', 'notifications', 'showRules', 'alertId', 'granularity');
     //detection alert fetch
     const start = analysisRange[0];
     const end = analysisRange[1];
@@ -642,8 +665,8 @@ export default Component.extend({
     let metricUrnList;
     let firstDimension;
     try {
-      if(isPreviewMode){
-        applicationAnomalies = yield getYamlPreviewAnomalies(alertYaml, startAnomalies, endAnomalies, alertId);
+      if(showRules){
+        applicationAnomalies = (granularity === 'DAYS') ? yield getBoundsAndAnomalies(alertId, startAnomalies, endAnomalies) : yield getYamlPreviewAnomalies(alertYaml, startAnomalies, endAnomalies, alertId);
         if (applicationAnomalies && applicationAnomalies.diagnostics && applicationAnomalies.diagnostics['0']) {
           metricUrnList = Object.keys(applicationAnomalies.diagnostics['0']);
           set(this, 'metricUrnList', metricUrnList);
@@ -716,13 +739,18 @@ export default Component.extend({
 
   init() {
     this._super(...arguments);
-    const isPreviewMode = get(this, 'isPreviewMode');
+    const {
+      granularity,
+      isPreviewMode,
+      dimensionExploration
+    } = this.getProperties('granularity', 'isPreviewMode', 'dimensionExploration');
     if (!isPreviewMode) {
       this.setProperties({
         analysisRange: [moment().add(1, 'day').subtract(1, 'month').startOf('day').valueOf(), moment().add(1, 'day').startOf('day').valueOf()],
         duration: '1m',
         selectedDimension: 'Choose a dimension',
-        selectedBaseline: 'wo1w'
+        // For now, we will only show predicted and bounds on daily metrics with no dimensions, for the Alert Overview page
+        selectedBaseline: (granularity === 'DAYS' && !dimensionExploration) ? 'predicted' : 'wo1w'
       });
       this._fetchAnomalies();
     } else {
@@ -746,10 +774,10 @@ export default Component.extend({
       metricUrn,
       analysisRange,
       selectedBaseline,
-      isPreviewMode,
+      showRules,
       selectedRule,
       uniqueTimeSeries
-    } = this.getProperties('metricUrn', 'analysisRange', 'selectedBaseline', 'isPreviewMode', 'selectedRule', 'uniqueTimeSeries');
+    } = this.getProperties('metricUrn', 'analysisRange', 'selectedBaseline', 'showRules', 'selectedRule', 'uniqueTimeSeries');
     const timeZone = 'America/Los_Angeles';
 
     this.setProperties({
@@ -757,7 +785,7 @@ export default Component.extend({
       isLoadingTimeSeries: true
     });
 
-    if (isPreviewMode) {
+    if (showRules) {
       const seriesSet = uniqueTimeSeries.find(series => {
         if (series.detectorName === selectedRule.detectorName && series.metricUrn === metricUrn) {
           return series;
@@ -997,7 +1025,7 @@ export default Component.extend({
       const metricUrnList = get(this, 'metricUrnList');
       const newMetricUrn = metricUrnList.find(urn => {
         const dimensionUrn = toMetricLabel(extractTail(decodeURIComponent(urn)));
-        if ( dimensionUrn === selected) {
+        if (dimensionUrn === selected) {
           return urn;
           // if there is no tail, this will be called 'All Dimensions' in the UI
         } else if (dimensionUrn === '' && selected === 'All Dimensions') {
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
index be93e9b..66f9a03 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
@@ -87,7 +87,7 @@
           {{/if}}
 
           <div class="te-content-block">
-            {{#if isPreviewMode}}
+            {{#if showRules}}
               <h4 class="te-self-serve__block-title">{{selectedRule.name}} {{#if alertHasDimensions}}/ {{selectedDimension}}{{/if}} anomalies over time ({{numCurrentAnomalies}})</h4>
             {{else}}
               <h4 class="te-self-serve__block-title">{{#if alertHasDimensions}}{{selectedDimension}} a{{else}}A{{/if}}nomalies over time ({{numCurrentAnomalies}})</h4>
@@ -99,7 +99,7 @@
 
             <div class="te-form__select te-form__select--same-line col-md-3">
               {{!-- Rule selector --}}
-              {{#if isPreviewMode}}
+              {{#if showRules}}
                 {{#power-select
                   triggerId="select-rule"
                   triggerClass="te-form__select"
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/timeseries-chart/component.js b/thirdeye/thirdeye-frontend/app/pods/components/timeseries-chart/component.js
index 46fbf60..1e744bb 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/timeseries-chart/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/timeseries-chart/component.js
@@ -243,7 +243,17 @@ export default Component.extend({
       if (upperBoundVals && lowerBoundVals) {
         upperBoundVals = upperBoundVals.values.map(e => e.value);
         lowerBoundVals = lowerBoundVals.values.map(e => e.value);
-
+        // If all upper bound vals are null, we assume that there is only a lower bound
+        if (upperBoundVals.every(val => val === null)) {
+          let currentVals = chart.internal.data.targets.find(target => {
+            return target.id === 'Current';
+          });
+          if (currentVals) {
+            currentVals = currentVals.values.map(e => e.value);
+            const currentMax = Math.max(...currentVals);
+            upperBoundVals = upperBoundVals.map(() => 2 * currentMax);
+          }
+        }
         const area_main = d3.svg.area()
           .interpolate('linear')
           .x(d => xscale(xVals[d]))
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/explore/route.js b/thirdeye/thirdeye-frontend/app/pods/manage/explore/route.js
index ff8651e..89f00f5 100644
--- a/thirdeye/thirdeye-frontend/app/pods/manage/explore/route.js
+++ b/thirdeye/thirdeye-frontend/app/pods/manage/explore/route.js
@@ -49,7 +49,12 @@ export default Route.extend({
           });
 
           try {
-            granularity = detection_json.properties.nested[0].nested[0].nested[0].windowUnit;
+            if (detectionInfo.dataset) {
+              const datasetUrl = `/detection/dataset?name=${detectionInfo.dataset}`;
+              const dataset_result = await fetch(datasetUrl, getProps);
+              const dataset_json = await dataset_result.json();
+              granularity = dataset_json.timeUnit;
+            }
           } catch (error) {
             granularity = null;
           }
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs b/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs
index 8aeef63..fa2e091 100644
--- a/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/manage/explore/template.hbs
@@ -33,6 +33,7 @@
         metricUrn=model.metricUrn
         metricUrnList=model.metricUrnList
         granularity=model.granularity
+        dimensionExploration=model.alertData.dimensionExploration
       }}
     {{/if}}
   </div>
diff --git a/thirdeye/thirdeye-frontend/app/utils/anomaly.js b/thirdeye/thirdeye-frontend/app/utils/anomaly.js
index fe16601..41077fa 100644
--- a/thirdeye/thirdeye-frontend/app/utils/anomaly.js
+++ b/thirdeye/thirdeye-frontend/app/utils/anomaly.js
@@ -4,7 +4,8 @@ import _ from 'lodash';
 import {
   checkStatus,
   postProps,
-  postYamlProps
+  postYamlProps,
+  getProps
 } from 'thirdeye-frontend/utils/utils';
 import fetch from 'fetch';
 import {
@@ -12,7 +13,8 @@ import {
   getAnomaliesForYamlPreviewUrl,
   getAnomaliesByAlertIdUrl,
   getAnomalyFiltersByTimeRangeUrl,
-  getAnomalyFiltersByAnomalyIdUrl
+  getAnomalyFiltersByAnomalyIdUrl,
+  getBoundsAndAnomaliesUrl
 } from 'thirdeye-frontend/utils/api/anomaly';
 
 /**
@@ -110,6 +112,19 @@ export function getYamlPreviewAnomalies(yamlString, startTime, endTime, alertId)
 }
 
 /**
+ * Get bounds and anomalies for a given detection
+ * @method getBoundsAndAnomalies
+ * @param {String} detectionId - the id of the detection
+ * @param {Number} startTime - start time of analysis range
+ * @param {Number} endTime - end time of analysis range
+ * @return {Ember.RSVP.Promise}
+ */
+export function getBoundsAndAnomalies(detectionId, startTime, endTime) {
+  const url = getBoundsAndAnomaliesUrl(detectionId, startTime, endTime);
+  return fetch(url, getProps()).then((res) => checkStatus(res));
+}
+
+/**
  * Get anomalies for a given detection id over a specified time range
  * @method getAnomaliesByAlertId
  * @param {Number} alertId - the alert id aka detection config id
diff --git a/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js b/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js
index 5d4d077..d6e6ded 100644
--- a/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js
+++ b/thirdeye/thirdeye-frontend/app/utils/api/anomaly.js
@@ -13,14 +13,27 @@ export function getAnomalyDataUrl(anomalyId) {
  * Returns url for getting the Anomalies for a given YAML configuration so user can preview
  * @param {Number} startTime - the anomaly start time
  * @param {Number} endTime - the anomaly end time
+ * @param {String} alertId - optional alert id that will call /yaml/preview/{id} if provided
  * @returns {String} the complete yaml/preview url
- * @example getAnomaliesForYamlPreview(1508472700000, 1508472800000) // yields => /yaml/preview?start=1508472700000&end=1508472800000&tuningStart=0&tuningEnd=0
+ * @example getAnomaliesForYamlPreviewUrl(1508472700000, 1508472800000) // yields => /yaml/preview?start=1508472700000&end=1508472800000&tuningStart=0&tuningEnd=0
  */
 export function getAnomaliesForYamlPreviewUrl(startTime, endTime, alertId) {
   return `/yaml/preview${alertId ? `/${alertId}` : ''}?start=${startTime}&end=${endTime}&tuningStart=0&tuningEnd=0`;
 }
 
 /**
+ * Returns url for getting the time series and Anomalies for a given detection id
+ * @param {String} detectionId - the detection id
+ * @param {Number} startTime - the anomaly start time
+ * @param {Number} endTime - the anomaly end time
+ * @returns {String} the complete yaml/preview url
+ * @example getBoundsAndAnomalies(111111, 1508472700000, 1508472800000) // yields => /detection/preview/111111?start=1508472700000&end=1508472800000&diagnostics=true
+ */
+export function getBoundsAndAnomaliesUrl(detectionId, startTime, endTime) {
+  return `/detection/preview/${detectionId}?start=${startTime}&end=${endTime}&diagnostics=true`;
+}
+
+/**
  * Returns the url for getting Anomalies for a given detection id over the specified time range
  * @param {Number} alertId - the alert id aka detection config id
  * @param {Number} startTime - the anomaly start time
@@ -57,7 +70,8 @@ export const anomalyApiUrls = {
   getAnomaliesForYamlPreviewUrl,
   getAnomaliesByAlertIdUrl,
   getAnomalyFiltersByTimeRangeUrl,
-  getAnomalyFiltersByAnomalyIdUrl
+  getAnomalyFiltersByAnomalyIdUrl,
+  getBoundsAndAnomaliesUrl
 };
 
 export default {
diff --git a/thirdeye/thirdeye-frontend/app/utils/utils.js b/thirdeye/thirdeye-frontend/app/utils/utils.js
index 6c4a5d1..6515ebe 100644
--- a/thirdeye/thirdeye-frontend/app/utils/utils.js
+++ b/thirdeye/thirdeye-frontend/app/utils/utils.js
@@ -156,6 +156,17 @@ export function postProps(postData) {
 }
 
 /**
+ * Preps get object
+ * @returns {Object}
+ */
+export function getProps() {
+  return {
+    method: 'get',
+    headers: { 'content-type': 'Application/Json' }
+  };
+}
+
+/**
  * Preps post object for Yaml payload
  * @param {string} text to post
  * @returns {Object}
@@ -231,5 +242,6 @@ export default {
   toIso,
   stripNonFiniteValues,
   postYamlProps,
-  formatYamlFilter
+  formatYamlFilter,
+  getProps
 };
diff --git a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionResource.java b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionResource.java
index c6598a4..53609df 100644
--- a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionResource.java
+++ b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/DetectionResource.java
@@ -148,6 +148,14 @@ public class DetectionResource {
     return Response.ok(config).build();
   }
 
+  @Path("/dataset")
+  @GET
+  @ApiOperation("get a dataset config by name")
+  public Response getDetectionAlertConfig(@ApiParam("the dataset name") @QueryParam("name") String name){
+    DatasetConfigDTO dataset = this.datasetDAO.findByDataset(name);
+    return Response.ok(dataset).build();
+  }
+
   @Path("/subscription-groups/{id}")
   @GET
   @ApiOperation("get a list of detection alert configs for a given detection config id")
@@ -242,7 +250,7 @@ public class DetectionResource {
     return Response.ok(gridSearch.bestDetectionConfig().getProperties()).build();
   }
 
-  @POST
+  @GET
   @Path("/preview/{id}")
   @ApiOperation("preview a detection with a existing detection config")
   public Response detectionPreview(


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org