package com.linkedin.thirdeye.dashboard.resources; import com.linkedin.thirdeye.constant.MetricAggFunction; import java.util.Arrays; import java.util.List; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.linkedin.thirdeye.client.MetricExpression; import com.linkedin.thirdeye.client.ThirdEyeCacheRegistry; import com.linkedin.thirdeye.client.diffsummary.Cube; import com.linkedin.thirdeye.client.diffsummary.Dimensions; import com.linkedin.thirdeye.client.diffsummary.OLAPDataBaseClient; import com.linkedin.thirdeye.client.diffsummary.PinotThirdEyeSummaryClient; import com.linkedin.thirdeye.dashboard.Utils; import com.linkedin.thirdeye.dashboard.views.diffsummary.Summary; import com.linkedin.thirdeye.dashboard.views.diffsummary.SummaryResponse; @Path(value = "/dashboard") public class SummaryResource { private static final ThirdEyeCacheRegistry CACHE_REGISTRY_INSTANCE = ThirdEyeCacheRegistry.getInstance(); private static final Logger LOG = LoggerFactory.getLogger(SummaryResource.class); private static final String DEFAULT_TIMEZONE_ID = "UTC"; private static final String DEFAULT_TOP_DIMENSIONS = "3"; private static final String DEFAULT_HIERARCHIES = "[]"; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final String DEFAULT_ONE_SIDE_ERROR = "false"; @GET @Path(value = "/summary/autoDimensionOrder") @Produces(MediaType.APPLICATION_JSON) public String buildSummary(@QueryParam("dataset") String collection, @QueryParam("metric") String metric, @QueryParam("currentStart") Long currentStartInclusive, @QueryParam("currentEnd") Long currentEndExclusive, @QueryParam("baselineStart") Long baselineStartInclusive, @QueryParam("baselineEnd") Long baselineEndExclusive, @QueryParam("dimensions") String groupByDimensions, @QueryParam("summarySize") int summarySize, @QueryParam("topDimensions") @DefaultValue(DEFAULT_TOP_DIMENSIONS) int topDimensions, @QueryParam("hierarchies") @DefaultValue(DEFAULT_HIERARCHIES) String hierarchiesPayload, @QueryParam("oneSideError") @DefaultValue(DEFAULT_ONE_SIDE_ERROR) boolean doOneSideError, @QueryParam("timeZone") @DefaultValue(DEFAULT_TIMEZONE_ID) String timeZone) throws Exception { if (summarySize < 1) summarySize = 1; SummaryResponse response = null; try { List<MetricExpression> metricExpressions = Utils.convertToMetricExpressions(metric, MetricAggFunction.SUM,collection); OLAPDataBaseClient olapClient = new PinotThirdEyeSummaryClient(CACHE_REGISTRY_INSTANCE.getQueryCache()); olapClient.setCollection(collection); olapClient.setMetricExpression(metricExpressions.get(0)); olapClient.setCurrentStartInclusive(new DateTime(currentStartInclusive, DateTimeZone.forID(timeZone))); olapClient.setCurrentEndExclusive(new DateTime(currentEndExclusive, DateTimeZone.forID(timeZone))); olapClient.setBaselineStartInclusive(new DateTime(baselineStartInclusive, DateTimeZone.forID(timeZone))); olapClient.setBaselineEndExclusive(new DateTime(baselineEndExclusive, DateTimeZone.forID(timeZone))); Dimensions dimensions; if (groupByDimensions == null || groupByDimensions.length() == 0 || groupByDimensions.equals("undefined")) { dimensions = new Dimensions(Utils.getSchemaDimensionNames(collection)); } else { dimensions = new Dimensions(Arrays.asList(groupByDimensions.trim().split(","))); } List<List<String>> hierarchies = OBJECT_MAPPER.readValue(hierarchiesPayload, new TypeReference<List<List<String>>>() { }); Cube cube = new Cube(); cube.buildWithAutoDimensionOrder(olapClient, dimensions, topDimensions, hierarchies); Summary summary = new Summary(cube); response = summary.computeSummary(summarySize, doOneSideError, topDimensions); response.setMetricName(metric); } catch (Exception e) { LOG.error("Exception while generating difference summary", e); response = SummaryResponse.buildNotAvailableResponse(); response.setMetricName(metric); } return OBJECT_MAPPER.writeValueAsString(response); } @GET @Path(value = "/summary/manualDimensionOrder") @Produces(MediaType.APPLICATION_JSON) public String buildSummaryManualDimensionOrder(@QueryParam("dataset") String collection, @QueryParam("metric") String metric, @QueryParam("currentStart") Long currentStartInclusive, @QueryParam("currentEnd") Long currentEndExclusive, @QueryParam("baselineStart") Long baselineStartInclusive, @QueryParam("baselineEnd") Long baselineEndExclusive, @QueryParam("dimensions") String groupByDimensions, @QueryParam("summarySize") int summarySize, @QueryParam("oneSideError") @DefaultValue(DEFAULT_ONE_SIDE_ERROR) boolean doOneSideError, @QueryParam("timeZone") @DefaultValue(DEFAULT_TIMEZONE_ID) String timeZone) throws Exception { if (summarySize < 1) summarySize = 1; SummaryResponse response = null; try { List<MetricExpression> metricExpressions = Utils.convertToMetricExpressions(metric, MetricAggFunction.SUM, collection); OLAPDataBaseClient olapClient = new PinotThirdEyeSummaryClient(CACHE_REGISTRY_INSTANCE.getQueryCache()); olapClient.setCollection(collection); olapClient.setMetricExpression(metricExpressions.get(0)); olapClient.setCurrentStartInclusive(new DateTime(currentStartInclusive, DateTimeZone.forID(timeZone))); olapClient.setCurrentEndExclusive(new DateTime(currentEndExclusive, DateTimeZone.forID(timeZone))); olapClient.setBaselineStartInclusive(new DateTime(baselineStartInclusive, DateTimeZone.forID(timeZone))); olapClient.setBaselineEndExclusive(new DateTime(baselineEndExclusive, DateTimeZone.forID(timeZone))); List<String> allDimensions; if (groupByDimensions == null || groupByDimensions.length() == 0 || groupByDimensions.equals("undefined")) { allDimensions = Utils.getSchemaDimensionNames(collection); } else { allDimensions = Arrays.asList(groupByDimensions.trim().split(",")); } if (allDimensions.size() > Integer.parseInt(DEFAULT_TOP_DIMENSIONS)) { allDimensions = allDimensions.subList(0, Integer.parseInt(DEFAULT_TOP_DIMENSIONS)); } Dimensions dimensions = new Dimensions(allDimensions); Cube cube = new Cube(); cube.buildWithManualDimensionOrder(olapClient, dimensions); Summary summary = new Summary(cube); response = summary.computeSummary(summarySize, doOneSideError); response.setMetricName(metric); } catch (Exception e) { LOG.error("Exception while generating difference summary", e); response = SummaryResponse.buildNotAvailableResponse(); } return OBJECT_MAPPER.writeValueAsString(response); } }