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);
}
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);
}
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);
}
}
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;
}
Aggregations