Skip to content

Commit

Permalink
MONDRIAN: New IgnoreMeasureForNonJoiningDimension property that defin…
Browse files Browse the repository at this point in the history
…es whether to ignore measure when non joining dimension is in the aggregation context + related changes

[git-p4: depot-paths = "//open/mondrian/": change = 10320]
  • Loading branch information
Ajit Joglekar committed Dec 18, 2007
1 parent 3f06cff commit 3fadbc3
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 36 deletions.
29 changes: 29 additions & 0 deletions doc/configuration.html
Expand Up @@ -386,6 +386,35 @@ <h3>1.1 Property list<a name="Property_list">&nbsp;</a></h3>
result should be NULL when denominator is NULL or zero.
</td>
</tr>
<tr>
<td>
<code>
<a href="api/mondrian/olap/MondrianProperties.html#IgnoreMeasureForNonJoiningDimension">mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension</a></code></td>
<td>boolean</td>
<td>false</td>
<td>
If there are unrelated dimensions to a measure in context during
aggregation, the measure is ignored in the evaluation context. This
behaviour kicks in only if the cubeusage for this measure has
IgnoreUnrelatedDimensions attribute set to false

<p>For example, Gender doesn't join with [Warehouse Sales] measure

<p>With <code>mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=true</code>
<p>Warehouse Sales gets eliminated and is ignored in the aggregate value
<blockquote><code>SUM({Product.members * Gender.members})</code></blockquote>
<blockquote><code>[Store Sales] + [Warehouse Sales] = 7,913,333.82</code></blockquote>
<p>With <code>mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=false</code>
<p>Warehouse Sales is part of the aggregate value
<blockquote><code>SUM({Product.members * Gender.members})</code></blockquote>
<blockquote><code>[Store Sales] + [Warehouse Sales] = 9,290,730.03</code></blockquote>
<p>On a report where Gender M, F and All members exist a user will see a
large aggregated value compared to the aggregated value that can be
arrived at by suming up values against Gender M and F. This can be
confusing to the user. This feature can be used to eliminate such a
situation
</td>
</tr>
<tr>
<td colspan="4">

Expand Down
34 changes: 33 additions & 1 deletion mondrian.properties
Expand Up @@ -185,7 +185,7 @@ log4j.configuration=/home/rchen/open/mondrian/log4j.properties
# per the "mondrian.debug.out.file" below. This is separate from Log4j
# logging.
mondrian.trace.level=1
mondrian.debug.out.file=/home/rchen/open/mondrian/trace.out
mondrian.debug.out.file=trace.out

###############################################################################
# Property containing the name of the file to which tracing is to be
Expand Down Expand Up @@ -409,4 +409,36 @@ mondrian.rolap.iterationLimit=0
#
mondrian.test.WarnIfNoPatternForDialect=ANY

###############################################################################
# Property which defines whether to ignore measure when non joining
# dimension is in the tuple during aggregation
#
# If there are unrelated dimensions to a measure in context during
# aggregation, the measure is ignored in the evaluation context. This
# behaviour kicks in only if the cubeusage for this measure has
# IgnoreUnrelatedDimensions attribute set to false
#
# Gender doesn't join with [Warehouse Sales] measure
#
# With mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=true
# Warehouse Sales gets eliminated and is ignored in the aggregate value
# [Store Sales] + [Warehouse Sales]
# SUM({Product.members * Gender.members}) 7,913,333.82
#
# With mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=false
# Warehouse Sales with Gender All level member contributes to the aggregate
# value
# [Store Sales] + [Warehouse Sales]
# SUM({Product.members * Gender.members}) 9,290,730.03
#
# On a report where Gender M, F and All members exist a user will see a
# large aggregated value compared to the aggregated value that can be
# arrived at by suming up values against Gender M and F. This can be
# confusing to the user. This feature can be used to eliminate such a
# situation
#
#
#mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=false


# End mondrian.properties
34 changes: 34 additions & 0 deletions src/main/mondrian/olap/MondrianProperties.java
Expand Up @@ -1062,6 +1062,40 @@ public Property getPropertyDefinition(String path) {
public transient final BooleanProperty EnableGroupingSets =
new BooleanProperty(
this, "mondrian.rolap.groupingsets.enable", false);

/**
* Property which defines whether to ignore measure when non joining
* dimension is in the tuple during aggregation
*
* If there are unrelated dimensions to a measure in context during
* aggregation, the measure is ignored in the evaluation context. This
* behaviour kicks in only if the cubeusage for this measure has
* IgnoreUnrelatedDimensions attribute set to false
*
* Gender doesn't join with [Warehouse Sales] measure
*
* With mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=true
* Warehouse Sales gets eliminated and is ignored in the aggregate value
* [Store Sales] + [Warehouse Sales]
* SUM({Product.members * Gender.members}) 7,913,333.82
*
* With mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension=false
* Warehouse Sales with Gender All level member contributes to the aggregate
* value
* [Store Sales] + [Warehouse Sales]
* SUM({Product.members * Gender.members}) 9,290,730.03
*
* On a report where Gender M, F and All members exist a user will see a
* large aggregated value compared to the aggregated value that can be
* arrived at by suming up values against Gender M and F. This can be
* confusing to the user. This feature can be used to eliminate such a
* situation
*/
public transient final BooleanProperty IgnoreMeasureForNonJoiningDimension =
new BooleanProperty(
this,
"mondrian.olap.agg.IgnoreMeasureForNonJoiningDimension",
false);
}

// End MondrianProperties.java
113 changes: 78 additions & 35 deletions src/main/mondrian/olap/fun/AbstractAggregateFunDef.java
Expand Up @@ -108,9 +108,14 @@ private static void crossProd(Evaluator evaluator, int currLen) {
}

/**
* Pushes unrelated dimensions to the top level member from the given list of
* tuples if the ignoreUnrelatedDimensions property is set on the base cube
* usage in the virtual cube
* Pushes unrelated dimensions to the top level member from the given list
* of tuples if the ignoreUnrelatedDimensions property is set on the base
* cube usage in the virtual cube
*
* If IgnoreMeasureForNonJoiningDimension is set to true and
* ignoreUnrelatedDimensions on CubeUsage is set to false then if a non
* joining dimension exists in the aggregation list then return an empty
* list else return the original list
*
* @param tuplesForAggregation is a list of members or tuples used in
* computing the aggregate
Expand All @@ -130,64 +135,101 @@ private static List processUnrelatedDimensions(
RolapCube virtualCube = (RolapCube) evaluator.getCube();
RolapCube baseCube = ((RolapStoredMeasure) measure).getCube();

if (!virtualCube.shouldIgnoreUnrelatedDimensions(baseCube.getName())) {
return tuplesForAggregation;
if (virtualCube.shouldIgnoreUnrelatedDimensions(baseCube.getName())) {
return ignoreUnrelatedDimensions(tuplesForAggregation, baseCube);
} else if (shouldIgnoreMeasureForNonJoiningDimension()) {
return ignoreMeasureForNonJoiningDimension(
tuplesForAggregation, baseCube);
}
return processUnrelatedDimensions(tuplesForAggregation, baseCube);
return tuplesForAggregation;
}

/**
* pushes unrelated dimensions to the top level member from the given list of
* tuples if the ignoreUnrelatedDimensions property is set on the base cube
* usage in the virtual cube
*
* If a non joining dimension exists in the aggregation list then return
* an empty list else return the original list
* @param tuplesForAggregation is a list of members or tuples used in
* computing the aggregate
* @param baseCube base cube to which the measure for aggregation belongs
* @param baseCube
* @return list of members or tuples
*/

private static List processUnrelatedDimensions(
private static List ignoreMeasureForNonJoiningDimension(
List tuplesForAggregation,
RolapCube baseCube) {
RolapCube baseCube)
{
Set nonJoiningDimensions =
nonJoiningDimensions(baseCube, tuplesForAggregation);
if (nonJoiningDimensions.size() > 0) {
return new ArrayList();
}
return tuplesForAggregation;
}

/**
* Pushes unrelated dimensions to the top level member from the given list
* of tuples if the ignoreUnrelatedDimensions property is set on the base
* cube usage in the virtual cube
*
* @param tuplesForAggregation is a list of members or tuples used in
* computing the aggregate
* @return list of members or tuples
*/
private static List ignoreUnrelatedDimensions(
List tuplesForAggregation,
RolapCube baseCube)
{
Set nonJoiningDimensions =
nonJoiningDimensions(baseCube, tuplesForAggregation);
Set processedTuples = new LinkedHashSet(tuplesForAggregation.size());
Dimension[] baseCubeDimensions = baseCube.getDimensions();

boolean isUnrelatedDimensionPresent;

for (int i = 0; i < tuplesForAggregation.size(); i++) {
Member[] tuples = copy(getTuplesAsArray(tuplesForAggregation.get(i)));
Member[] tuples = copy(tupleAsArray(tuplesForAggregation.get(i)));
for (int j = 0; j < tuples.length; j++) {
isUnrelatedDimensionPresent = true;

for (Dimension dimension : baseCubeDimensions) {
if (dimension.getName().equals(tuples[j].getDimension().getName())) {
isUnrelatedDimensionPresent = false;
break;
}
}

if (isUnrelatedDimensionPresent) {
final Hierarchy hierarchy = tuples[j].getDimension().getHierarchy();
if (nonJoiningDimensions.contains(
tuples[j].getDimension().getUniqueName())) {
final Hierarchy hierarchy =
tuples[j].getDimension().getHierarchy();
if(hierarchy.hasAll()){
tuples[j] = hierarchy.getAllMember();
} else {
tuples[j] = hierarchy.getDefaultMember();
}
}
}

if (tuplesForAggregation.get(i) instanceof Member[]) {
processedTuples.add(new MemberArray(tuples));
} else {
processedTuples.add(tuples[0]);
}
}

}
return tuplesAsList(processedTuples);
}

private static Set nonJoiningDimensions(
RolapCube baseCube,
List tuplesForAggregation)
{
Set nonJoiningDimensions = new HashSet();
Dimension[] baseCubeDimensions = baseCube.getDimensions();
Member[] tuple = tupleAsArray(tuplesForAggregation.get(0));
for (Member member : tuple) {
nonJoiningDimensions.add(member.getHierarchy().getDimension()
.getUniqueName());
}
for (Dimension dimension : baseCubeDimensions) {
nonJoiningDimensions.remove(dimension.getUniqueName());
if (nonJoiningDimensions.size() == 0) {
break;
}
}
return nonJoiningDimensions;
}

private static boolean shouldIgnoreMeasureForNonJoiningDimension() {
return MondrianProperties.instance()
.IgnoreMeasureForNonJoiningDimension.get();
}

private static List tuplesAsList(Set tuples) {
List results = new ArrayList(tuples.size());
for (Object tuple : tuples) {
Expand All @@ -197,7 +239,6 @@ private static List tuplesAsList(Set tuples) {
results.add(tuple);
}
}

return results;
}

Expand All @@ -207,7 +248,7 @@ private static Member[] copy(Member[] members) {
return result;
}

private static Member[] getTuplesAsArray(Object tuple) {
private static Member[] tupleAsArray(Object tuple) {
Member[] result;
if (tuple instanceof Member[]) {
result = ((Member[]) tuple);
Expand All @@ -229,7 +270,9 @@ public int hashCode() {
}

public boolean equals(Object obj) {
return Arrays.deepEquals(memberArray, ((MemberArray) obj).memberArray);
return Arrays.deepEquals(
memberArray,
((MemberArray) obj).memberArray);
}
}

Expand Down

0 comments on commit 3fadbc3

Please sign in to comment.