use of mondrian.olap.fun.VisualTotalsFunDef.VisualTotalMember in project mondrian by pentaho.
the class RolapResult method processDistinctMeasureExpr.
/**
* Distinct counts are aggregated separately from other measures. We need to apply filters to each level in the query.
*
* <p>
* Replace VisualTotalMember expressions with new expressions where all leaf level members are included.
* </p>
*
* <p>
* Example. For MDX query:
*
* <blockquote>
*
* <pre>
* WITH SET [XL_Row_Dim_0] AS
* VisualTotals(
* Distinct(
* Hierarchize(
* {Ascendants([Store].[All Stores].[USA].[CA]),
* Descendants([Store].[All Stores].[USA].[CA])})))
* select NON EMPTY
* Hierarchize(
* Intersect(
* {DrilldownLevel({[Store].[All Stores]})},
* [XL_Row_Dim_0])) ON COLUMNS
* from [HR]
* where [Measures].[Number of Employees]
* </pre>
*
* </blockquote>
*
* <p>
* For member [Store].[All Stores], we replace aggregate expression
*
* <blockquote>
*
* <pre>
* Aggregate({[Store].[All Stores].[USA]})
* </pre>
*
* </blockquote>
* <p>
* with
*
* <blockquote>
*
* <pre>
* Aggregate({[Store].[All Stores].[USA].[CA].[Alameda].[HQ],
* [Store].[All Stores].[USA].[CA].[Beverly Hills].[Store 6],
* [Store].[All Stores].[USA].[CA].[Los Angeles].[Store 7],
* [Store].[All Stores].[USA].[CA].[San Diego].[Store 24],
* [Store].[All Stores].[USA].[CA].[San Francisco].[Store 14]
* })
* </pre>
*
* </blockquote>
*
* <p>
* TODO: Can be optimized. For that particular query we don't need to go to the lowest level. We can simply replace it
* with:
*
* <pre>
* Aggregate({[Store].[All Stores].[USA].[CA]})
* </pre>
*
* Because all children of [Store].[All Stores].[USA].[CA] are included.
* </p>
*/
private List<Member> processDistinctMeasureExpr(List<Member> tuple, RolapBaseCubeMeasure measure) {
for (Member member : tuple) {
if (!(member instanceof VisualTotalMember)) {
continue;
}
evaluator.setContext(measure);
List<Member> exprMembers = new ArrayList<Member>();
processMemberExpr(member, exprMembers);
((VisualTotalMember) member).setExpression(evaluator, exprMembers);
}
return tuple;
}
use of mondrian.olap.fun.VisualTotalsFunDef.VisualTotalMember in project mondrian by pentaho.
the class RolapResult method processMemberExpr.
private static void processMemberExpr(Object o, List<Member> exprMembers) {
if (o instanceof Member && o instanceof RolapCubeMember) {
exprMembers.add((Member) o);
} else if (o instanceof VisualTotalMember) {
VisualTotalMember member = (VisualTotalMember) o;
Exp exp = member.getExpression();
processMemberExpr(exp, exprMembers);
} else if (o instanceof Exp && !(o instanceof MemberExpr)) {
Exp exp = (Exp) o;
ResolvedFunCall funCall = (ResolvedFunCall) exp;
Exp[] exps = funCall.getArgs();
processMemberExpr(exps, exprMembers);
} else if (o instanceof Exp[]) {
Exp[] exps = (Exp[]) o;
for (Exp exp : exps) {
processMemberExpr(exp, exprMembers);
}
} else if (o instanceof MemberExpr) {
MemberExpr memberExp = (MemberExpr) o;
Member member = memberExp.getMember();
processMemberExpr(member, exprMembers);
}
}
use of mondrian.olap.fun.VisualTotalsFunDef.VisualTotalMember in project mondrian by pentaho.
the class RolapAggregationManager method makeCompoundGroup.
/**
* Groups members (or tuples) from the same compound (i.e. hierarchy) into
* groups that are constrained by the same set of columns.
*
* <p>E.g.
*
* <pre>Members
* [USA].[CA],
* [Canada].[BC],
* [USA].[CA].[San Francisco],
* [USA].[OR].[Portland]</pre>
*
* will be grouped into
*
* <pre>Group 1:
* {[USA].[CA], [Canada].[BC]}
* Group 2:
* {[USA].[CA].[San Francisco], [USA].[OR].[Portland]}</pre>
*
* <p>This helps with generating optimal form of sql.
*
* <p>In case of aggregating over a list of tuples, similar logic also
* applies.
*
* <p>For example:
*
* <pre>Tuples:
* ([Gender].[M], [Store].[USA].[CA])
* ([Gender].[F], [Store].[USA].[CA])
* ([Gender].[M], [Store].[USA])
* ([Gender].[F], [Store].[Canada])</pre>
*
* will be grouped into
*
* <pre>Group 1:
* {([Gender].[M], [Store].[USA].[CA]),
* ([Gender].[F], [Store].[USA].[CA])}
* Group 2:
* {([Gender].[M], [Store].[USA]),
* ([Gender].[F], [Store].[Canada])}</pre>
*
* <p>This function returns a boolean value indicating if any constraint
* can be created from the aggregationList. It is possible that only part
* of the aggregationList can be applied, which still leads to a (partial)
* constraint that is represented by the compoundGroupMap.
*/
private static boolean makeCompoundGroup(int starColumnCount, RolapCube baseCube, List<List<RolapMember>> aggregationList, Map<BitKey, List<RolapCubeMember[]>> compoundGroupMap) {
// The more generalized aggregation as aggregating over tuples.
// The special case is a tuple defined by only one member.
int unsatisfiableTupleCount = 0;
for (List<RolapMember> aggregation : aggregationList) {
boolean isTuple;
if (aggregation.size() > 0 && (aggregation.get(0) instanceof RolapCubeMember || aggregation.get(0) instanceof VisualTotalMember)) {
isTuple = true;
} else {
++unsatisfiableTupleCount;
continue;
}
BitKey bitKey = BitKey.Factory.makeBitKey(starColumnCount);
RolapCubeMember[] tuple;
tuple = new RolapCubeMember[aggregation.size()];
int i = 0;
for (Member member : aggregation) {
if (member instanceof VisualTotalMember) {
tuple[i] = (RolapCubeMember) ((VisualTotalMember) member).getMember();
} else {
tuple[i] = (RolapCubeMember) member;
}
i++;
}
boolean tupleUnsatisfiable = false;
for (RolapCubeMember member : tuple) {
// Tuple cannot be constrained if any of the member cannot be.
tupleUnsatisfiable = makeCompoundGroupForMember(member, baseCube, bitKey);
if (tupleUnsatisfiable) {
// If this tuple is unsatisfiable, skip it and try to
// constrain the next tuple.
unsatisfiableTupleCount++;
break;
}
}
if (!tupleUnsatisfiable && !bitKey.isEmpty()) {
// Found tuple(columns) to constrain,
// now add it to the compoundGroupMap
addTupleToCompoundGroupMap(tuple, bitKey, compoundGroupMap);
}
}
return (unsatisfiableTupleCount == aggregationList.size());
}
Aggregations