/*
Calculation Script name - WhizCalContribution
Description - Contribution is the portion of the total value that belongs to any dimension.
TRx contribution for product P1 =(TRx for product P1 / Total TRx)*100
Product Version - v66
Script Version - 1.0
***Disclaimer - This is proprietary code of Whiz.AI. If you want to build on top of this computation script please make a copy/clone of this script and then alter the script which is copied or cloned. When version upgrade happens there are chances that this script may get modified hence any customization done by customer/partner developer may be overwritten.
Key Functions - 1.Function name : compute
purpose : perform the computation without creating join on dataSource
input parameters : metaDataQuery
output parameters : dataFrame
2.Function name : computeWithJoins
purpose : perform the computation by creating join on dataSource
input parameters : metaDataQuery
output parameters : dataFrame
Key variables - query : implicit variable
outputMetricName : implicit variable
WhizCalPaginationLib : The name of the object present in WhizCalPaginationLib.js(library script).
execution scripts can call WhizCalPaginationLib scripts functions using given object.
dataAccessManager: This class is exposed to scripts by Framework through implicit variable dataAccessManager.
this acts as gateway to data exposed by the framework. A query can be fired through this instance to get the data.
*/
//**Start of Function code
(() => {
log.info("******************** WhizCalContribution **********************");
function compute(query) {
//calling the function from library script
const infoObj = WhizCalPaginationLib.modifyQueryAndGetInfo(query);
// get list of dimensions from entity-configuration
//dimensions and dim filters are set by application service
const exceptDims = addonProps?.["defaultFilter"]?.["dynamicArgs"]?.["dimensions"];
const dimsToRemove = new Set(exceptDims);
//names of dimensions configured.
const dimNames = query.dimNames();
dimNames.forEach(item => dimsToRemove.add(item));
//copy()- creates deep copy from existing query
//name(String name)- name for metadata query, this helps logging and identification of query
const denomQuery = query.copy().name("WhizCalContribution_DenominatorQuery");
//removes all contents referring to each column present in the array from all places applicable
denomQuery.removeColumns(Array.from(dimsToRemove));
//copy(String copyPrefix, MetadataQuery query)- creates deep copy of this aggregation,name of each aggregation is set as (copyPrefix+current name)
const totalAggr = primaryAggr.copy("totalAggr", denomQuery);
//clears the aggregations set on this query
denomQuery.clearAggrs();
//adds given aggregation/post-aggregation to the query
denomQuery.aggr(totalAggr);
const joinOnCols = [];
if (dimNames.length > 1) {
//adds given dimension into the query
denomQuery.dim(dimNames[1]);
joinOnCols.push(dimNames[1]);
}
//name(String name)- name for metadata query, this helps logging and identification of query
query.name("WhizCalContribution_NumeratorQuery");
//fires the MetadataQuery passed, returns DataFrame representing the response of the query
const numeratorDf = dataAccessManager.fireQuery(query);
//replaceOrderingColumn(String currentOrderingColum,String replacementColum)-Replaces any ordering clauses in the query with given column with ordering on new column
denomQuery.replaceOrderingColumn(primaryAggr.column(), totalAggr.name());
//fires the MetadataQuery passed, returns DataFrame representing the response of the query
const denominatorDf = dataAccessManager.fireQuery(denomQuery);
//granularity()- returns effective granularity. So even when not set, returns granularity of type 'all'
//type()- returns type of granularity like 'all', 'period', 'duration'.
if (Granularity.TYPE_ALL == (denomQuery.granularity().type())) {
//removes the given column from the DataFrame
denominatorDf.removeColumn(TIMESTAMP_RESPONSE_COLUMN);
} else if (joinOnCols.length > 0) {
joinOnCols.push(TIMESTAMP_RESPONSE_COLUMN);
}
let finalDf;
if (joinOnCols.length > 0) {
//innerJoin(DataFrame otherDF, List<String> joinColumns, Map<String, Object> defaults) - creates response DF with inner join of this DF with other DF being passed
finalDf = numeratorDf.innerJoin(denominatorDf, joinOnCols, {});
} else {
//innerJoin(DataFrame otherDF)- creates response DF with inner join of this DF with other DF being passed. All common columns are assumed as join columns
finalDf = numeratorDf.innerJoin(denominatorDf);
}
/* percent(String aggrName, Object value, Object outOf, double divByZeroResponse)- returns the Aggregation object, whose arithmetically result is 100*(value/base)
aggrName: Name of the post aggregation for output results
value: The value whose percentage is to be calculated against total (outOf)
outOf: Total part of the percentage out of which 'value' is specified
divByZeroResponse: The value that should be returned back when base value (outOf) is zero
*/
const aggr = Aggregation.percent(outputMetricName, primaryAggr.name(), totalAggr.name(), 0.0);
//adds column with given aggregation, with name same as name of aggregation passed. The aggregation passed defines how would value of column to be added is derived
finalDf.addColumn(aggr);
//calling the function from library script
return WhizCalPaginationLib.getFinalResponse(finalDf, infoObj);
}
function computeWithJoins(query) {
//replaceOrderingColumn(String currentOrderingColum,String replacementColum)-Replaces any ordering clauses in the query with given column with ordering on new column
query.replaceOrderingColumn(primaryAggr.column(), outputMetricName);
//copy()- creates deep copy from existing query
//name(String name)- name for metadata query, this helps logging and identification of query
const numQuery = query.copy().name("WhizCalContribution_NumeratorQuery");
//returns offset set in metadataQuery
const offset = numQuery.offset();
//returns limit set in metadataQuery
const limit = numQuery.limit();
//returns shallow Copy of sort orders configured
const order = numQuery.orderBy();
//limit(Integer limit)- sets limit on number of records that would be sent back by query
//offset(Integer offset)- the number of first records with specified offset would be skipped
//clearOrderBy()- clears the order by clauses set on this query
numQuery.limit(null).offset(null).clearOrderBy();
//copy()- creates deep copy from existing query
//name(String name)- name for metadata query, this helps logging and identification of query
const denomQuery = numQuery.copy().name("WhizCalContribution_DenominatorQuery");
// get list of dimensions from entity-configuration
const exceptDims = addonProps?.["defaultFilter"]?.["dynamicArgs"]?.["dimensions"];
const dimsToRemove = new Set(exceptDims);
//names of dimensions configured.
const dimNames = query.dimNames();
dimNames.forEach(item => dimsToRemove.add(item));
//removes all contents referring to each column present in the array from all places applicable
denomQuery.removeColumns(Array.from(dimsToRemove));
//copy(String copyPrefix, MetadataQuery query)- creates deep copy of this aggregation,name of each aggregation is set as (copyPrefix+current name)
const totalAggr = primaryAggr.copy("totalAggr", denomQuery);
//clears the aggregations set on this query
denomQuery.clearAggrs();
//adds given aggregation/post-aggregation to the query
denomQuery.aggr(totalAggr);
const joinOnCols = [];
if (dimNames.length > 1) {
//adds given dimension into the query
denomQuery.dim(dimNames[1]);
joinOnCols.push(dimNames[1]);
}
//granularity()- returns effective granularity. So even when not set, returns granularity of type 'all'
//type()- returns type of granularity like 'all', 'period', 'duration'.
if (Granularity.TYPE_ALL !== (denomQuery.granularity().type())) {
joinOnCols.push(TIMESTAMP_RESPONSE_COLUMN);
}
const numDataSource = DataSource.innerQuery("numrDS", numQuery);
const denDataSource = DataSource.innerQuery("denDS", denomQuery);
let selectColumns = [];
let aggregations = [];
//adds given aggregation/post-aggregation to the query
denomQuery.aggr(totalAggr);
const numColumn = numDataSource.column(primaryAggr.name());
const denColumn = denDataSource.column(totalAggr.name());
selectColumns = [numColumn, denColumn];
aggregations.push(Aggregation.percent(outputMetricName, numColumn, denColumn, 0));
const joinOnColsMap = new Map();
joinOnCols.forEach(col => joinOnColsMap.set(col, col));
//creates a query with specified details
const joinQuery = MetadataQuery.create()
//Sets the model on which this query is to be run, model + dataSource combination decides the DB Table or Druid data source to be used to run the query
.model(numQuery.model())
//name for metadata query, this helps logging and identification of query
.name("WhizCalContribution_JoinQuery")
//columns to be fetch from database
.select(numQuery.dimNames())
.select(selectColumns.concat(aggregations))
//from(DBDataSource ds) -returns reference name of primary data source associated with this query
.from(numDataSource)
//leftJoinOn(DBDataSource dataSource, Map<String, String> joinColumnsLeftToRightMap)- create left join on datasource with given map of column
.leftJoinOn(denDataSource, joinOnColsMap)
//offset(Integer offset)- the number of first records with specified offset would be skipped
.offset(offset)
//limit(Integer limit)- sets limit on number of records that would be sent back by query
.limit(limit)
//orderBy(List sortData)- convenience method calling orderBy(String) or orderBy(SortData) depending on type of each element
.orderBy(order)
//granularity(Granularity granularity)- sets given granularity into the query
.addonProperties(query.addonProperties());
//fires the MetadataQuery passed, returns DataFrame representing the response of the query
return dataAccessManager.fireQuery(joinQuery);
}
// get value of apply_join_query variable from entity-configuration
const applyJoin = addonProps?.["defaultFilter"]?.["dynamicArgs"]?.["apply_join_query"];
if (applyJoin) {
return computeWithJoins(query);
} else {
return compute(query)
}
})();/*
** configuration to be set in Computation metric **
default_filter:In this section's dynamicArgs sub-section, we have added,
"apply_join_query" - flag to switch between two calculation approaches
true - if join query needs to enable
**The configuration below should be copied and pasted to calculate the contribution.*
*/
"default_filter": {
"dynamicArgs": {
"apply_join_query": true
}
}Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article