Search in sources :

Example 1 with Dimensions

use of com.linkedin.thirdeye.client.diffsummary.Dimensions in project pinot by linkedin.

the class SummaryResource method buildSummary.

@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);
}
Also used : OLAPDataBaseClient(com.linkedin.thirdeye.client.diffsummary.OLAPDataBaseClient) Dimensions(com.linkedin.thirdeye.client.diffsummary.Dimensions) MetricExpression(com.linkedin.thirdeye.client.MetricExpression) DateTime(org.joda.time.DateTime) SummaryResponse(com.linkedin.thirdeye.dashboard.views.diffsummary.SummaryResponse) Cube(com.linkedin.thirdeye.client.diffsummary.Cube) Summary(com.linkedin.thirdeye.dashboard.views.diffsummary.Summary) PinotThirdEyeSummaryClient(com.linkedin.thirdeye.client.diffsummary.PinotThirdEyeSummaryClient) List(java.util.List) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET)

Example 2 with Dimensions

use of com.linkedin.thirdeye.client.diffsummary.Dimensions in project pinot by linkedin.

the class SummaryResource method buildSummaryManualDimensionOrder.

@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);
}
Also used : SummaryResponse(com.linkedin.thirdeye.dashboard.views.diffsummary.SummaryResponse) Cube(com.linkedin.thirdeye.client.diffsummary.Cube) OLAPDataBaseClient(com.linkedin.thirdeye.client.diffsummary.OLAPDataBaseClient) Dimensions(com.linkedin.thirdeye.client.diffsummary.Dimensions) Summary(com.linkedin.thirdeye.dashboard.views.diffsummary.Summary) PinotThirdEyeSummaryClient(com.linkedin.thirdeye.client.diffsummary.PinotThirdEyeSummaryClient) MetricExpression(com.linkedin.thirdeye.client.MetricExpression) DateTime(org.joda.time.DateTime) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET)

Example 3 with Dimensions

use of com.linkedin.thirdeye.client.diffsummary.Dimensions in project pinot by linkedin.

the class SummaryResponse method build.

public void build(List<HierarchyNode> nodes, int targetLevelCount, List<DimNameValueCostEntry> costSet) {
    // Compute the total baseline and current value
    for (HierarchyNode node : nodes) {
        totalBaselineValue += node.getBaselineValue();
        totalCurrentValue += node.getCurrentValue();
    }
    this.buildGainerLoserGroup(costSet);
    // If all nodes have a lower level count than targetLevelCount, then it is not necessary to print the summary with
    // height higher than the available level.
    int maxNodeLevelCount = 0;
    for (HierarchyNode node : nodes) {
        maxNodeLevelCount = Math.max(maxNodeLevelCount, node.getLevel());
    }
    targetLevelCount = Math.min(maxNodeLevelCount, targetLevelCount);
    // Build the header
    Dimensions dimensions = nodes.get(0).getDimensions();
    for (int i = 0; i < targetLevelCount; ++i) {
        this.dimensions.add(dimensions.get(i));
    }
    // Build the response
    nodes = SummaryResponseTree.sortResponseTree(nodes, targetLevelCount);
    //   Build name tag for each row of responses
    Map<HierarchyNode, NameTag> nameTags = new HashMap<>();
    Map<HierarchyNode, List<String>> otherDimensionValues = new HashMap<>();
    for (HierarchyNode node : nodes) {
        NameTag tag = new NameTag(targetLevelCount);
        nameTags.put(node, tag);
        tag.copyNames(node.getDimensionValues());
        otherDimensionValues.put(node, new ArrayList<>());
    }
    //   pre-condition: parent node is processed before its children nodes
    for (HierarchyNode node : nodes) {
        HierarchyNode parent = node;
        int levelDiff = 1;
        while ((parent = parent.getParent()) != null) {
            NameTag parentNameTag = nameTags.get(parent);
            if (parentNameTag != null) {
                // Set tag from ALL to NOT_ALL String.
                int notAllLevel = node.getLevel() - levelDiff;
                parentNameTag.setNotAll(notAllLevel);
                // For users' ease of understanding, we append what dimension values are excluded from NOT_ALL
                StringBuilder sb = new StringBuilder();
                String separator = "";
                for (int i = notAllLevel; i < node.getDimensionValues().size(); ++i) {
                    sb.append(separator).append(node.getDimensionValues().get(i));
                    separator = ".";
                }
                otherDimensionValues.get(parent).add(sb.toString());
                break;
            }
            ++levelDiff;
        }
    }
    //    Fill in the information of each response row
    for (HierarchyNode node : nodes) {
        SummaryResponseRow row = new SummaryResponseRow();
        row.names = nameTags.get(node).names;
        row.baselineValue = node.getBaselineValue();
        row.currentValue = node.getCurrentValue();
        row.percentageChange = computePercentageChange(row.baselineValue, row.currentValue);
        row.contributionChange = computeContributionChange(row.baselineValue, row.currentValue, totalBaselineValue, totalCurrentValue);
        row.contributionToOverallChange = computeContributionToOverallChange(row.baselineValue, row.currentValue, totalBaselineValue);
        StringBuilder sb = new StringBuilder();
        String separator = "";
        for (String s : otherDimensionValues.get(node)) {
            sb.append(separator).append(s);
            separator = ", ";
        }
        row.otherDimensionValues = sb.toString();
        this.responseRows.add(row);
    }
}
Also used : ToStringBuilder(org.apache.commons.lang3.builder.ToStringBuilder) HashMap(java.util.HashMap) Dimensions(com.linkedin.thirdeye.client.diffsummary.Dimensions) ArrayList(java.util.ArrayList) List(java.util.List) HierarchyNode(com.linkedin.thirdeye.client.diffsummary.HierarchyNode)

Example 4 with Dimensions

use of com.linkedin.thirdeye.client.diffsummary.Dimensions in project pinot by linkedin.

the class SummaryResponseTree method sortResponseTree.

public static List<HierarchyNode> sortResponseTree(List<HierarchyNode> nodes, int levelCount) {
    SummaryResponseTree responseTree = new SummaryResponseTree();
    // Build the header
    Dimensions dimensions = nodes.get(0).getDimensions();
    double totalValue = nodes.get(0).getOriginalCurrentValue() + nodes.get(0).getOriginalBaselineValue();
    for (int i = 0; i < levelCount; ++i) {
        responseTree.dimensions.add(dimensions.get(i));
    }
    List<SummaryResponseTreeNode> treeNodes = new ArrayList<>();
    // Build the response tree
    // pre-order traversal
    nodes.sort(Summary.NODE_COMPARATOR.reversed());
    for (HierarchyNode node : nodes) {
        SummaryResponseTreeNode treeNode = new SummaryResponseTreeNode();
        treeNode.hierarchyNode = node;
        treeNode.level = node.getLevel();
        treeNodes.add(treeNode);
    }
    //    Connecting child and parent response tree node. Note: response tree is not a perfect tree like the tree
    //    of HierarchyNodes, because in response tree a node's direct parent may be missing.
    //    In that case, we have to bootstrap the search until a higher level parent, which also exists in the response
    //    tree, is found.
    //    Pre-condition: treeNodes are sorted in the pre-order fashion when projecting the nodes back to the tree of
    //                   HierarchyNode.
    SummaryResponseTreeNode preTreeNode = null;
    for (SummaryResponseTreeNode treeNode : treeNodes) {
        if (preTreeNode != null) {
            SummaryResponseTreeNode parent = preTreeNode.getCommonParent(treeNode.getDimensionValues());
            treeNode.parent = parent;
            parent.children.add(treeNode);
        }
        preTreeNode = treeNode;
    }
    // Sort the children of each node by their cost
    sortChildNodes(treeNodes.get(0), totalValue);
    // Put the nodes to a flattened array
    insertChildNodes(treeNodes.get(0), responseTree.hierarchicalNodes);
    return responseTree.hierarchicalNodes;
}
Also used : ArrayList(java.util.ArrayList) Dimensions(com.linkedin.thirdeye.client.diffsummary.Dimensions) HierarchyNode(com.linkedin.thirdeye.client.diffsummary.HierarchyNode)

Aggregations

Dimensions (com.linkedin.thirdeye.client.diffsummary.Dimensions)4 MetricExpression (com.linkedin.thirdeye.client.MetricExpression)2 Cube (com.linkedin.thirdeye.client.diffsummary.Cube)2 HierarchyNode (com.linkedin.thirdeye.client.diffsummary.HierarchyNode)2 OLAPDataBaseClient (com.linkedin.thirdeye.client.diffsummary.OLAPDataBaseClient)2 PinotThirdEyeSummaryClient (com.linkedin.thirdeye.client.diffsummary.PinotThirdEyeSummaryClient)2 Summary (com.linkedin.thirdeye.dashboard.views.diffsummary.Summary)2 SummaryResponse (com.linkedin.thirdeye.dashboard.views.diffsummary.SummaryResponse)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 GET (javax.ws.rs.GET)2 Path (javax.ws.rs.Path)2 Produces (javax.ws.rs.Produces)2 DateTime (org.joda.time.DateTime)2 HashMap (java.util.HashMap)1 ToStringBuilder (org.apache.commons.lang3.builder.ToStringBuilder)1