KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > agg > AggregationManager


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/rolap/agg/AggregationManager.java#50 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2001-2002 Kana Software, Inc.
7 // Copyright (C) 2001-2007 Julian Hyde and others
8 // All Rights Reserved.
9 // You must accept the terms of that agreement to use this software.
10 //
11 // jhyde, 30 August, 2001
12 */

13
14 package mondrian.rolap.agg;
15
16 import mondrian.olap.MondrianProperties;
17 import mondrian.olap.Util;
18 import mondrian.rolap.*;
19 import mondrian.rolap.aggmatcher.AggStar;
20
21 import org.apache.log4j.Logger;
22
23 import java.util.*;
24
25 /**
26  * <code>RolapAggregationManager</code> manages all {@link Aggregation}s
27  * in the system. It is a singleton class.
28  *
29  * @author jhyde
30  * @since 30 August, 2001
31  * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/AggregationManager.java#50 $
32  */

33 public class AggregationManager extends RolapAggregationManager {
34     private static final Logger LOGGER =
35             Logger.getLogger(AggregationManager.class);
36
37     private static AggregationManager instance;
38
39     /** Returns or creates the singleton. */
40     public static synchronized AggregationManager instance() {
41         if (instance == null) {
42             instance = new AggregationManager();
43         }
44         return instance;
45     }
46
47     AggregationManager() {
48         super();
49     }
50
51     public Logger getLogger() {
52         return LOGGER;
53     }
54
55     /**
56      * Called by FastBatchingCellReader.loadAggregation where the
57      * RolapStar creates an Aggregation if needed.
58      *
59      * @param measures Measures to load
60      * @param columns this is the CellRequest's constrained columns
61      * @param constrainedColumnsBitKey this is the CellRequest's constrained column BitKey
62      * @param predicates Array of constraints on each column
63      * @param pinnedSegments Set of pinned segments
64      */

65     public void loadAggregation(
66             RolapStar.Measure[] measures,
67             RolapStar.Column[] columns,
68             BitKey constrainedColumnsBitKey,
69             StarColumnPredicate[] predicates,
70             PinSet pinnedSegments) {
71         RolapStar star = measures[0].getStar();
72         Aggregation aggregation =
73                 star.lookupOrCreateAggregation(constrainedColumnsBitKey);
74
75         // synchronized access
76
synchronized (aggregation) {
77             // try to eliminate unneccessary constraints
78
// for Oracle: prevent an IN-clause with more than 1000 elements
79
predicates = aggregation.optimizePredicates(columns, predicates);
80
81             aggregation.load(columns, measures, predicates, pinnedSegments);
82         }
83     }
84
85     public Object JavaDoc getCellFromCache(CellRequest request) {
86         RolapStar.Measure measure = request.getMeasure();
87         Aggregation aggregation = measure.getStar().lookupAggregation(
88             request.getConstrainedColumnsBitKey());
89
90         if (aggregation == null) {
91             // cell is not in any aggregation
92
return null;
93         }
94         // synchronized access
95
synchronized (aggregation) {
96             Object JavaDoc o = aggregation.getCellValue(
97                     measure, request.getSingleValues(), null);
98             if (o != null) {
99                 return o;
100             }
101         }
102         throw Util.newInternal("not found");
103     }
104
105     public Object JavaDoc getCellFromCache(CellRequest request, PinSet pinSet) {
106         Util.assertPrecondition(pinSet != null);
107
108         RolapStar.Measure measure = request.getMeasure();
109         Aggregation aggregation = measure.getStar().lookupAggregation(
110             request.getConstrainedColumnsBitKey());
111
112         if (aggregation == null) {
113             // cell is not in any aggregation
114
return null;
115         } else {
116             // synchronized access
117
synchronized (aggregation) {
118                 return aggregation.getCellValue(measure,
119                             request.getSingleValues(), pinSet);
120             }
121         }
122     }
123
124     public String JavaDoc getDrillThroughSql(
125         final CellRequest request,
126         boolean countOnly)
127     {
128         DrillThroughQuerySpec spec =
129             new DrillThroughQuerySpec(
130                 request,
131                 countOnly);
132         String JavaDoc sql = spec.generateSqlQuery();
133
134         if (getLogger().isDebugEnabled()) {
135             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(256);
136             buf.append("DrillThroughSQL: ");
137             buf.append(sql);
138             buf.append(Util.nl);
139             getLogger().debug(buf.toString());
140         }
141
142         return sql;
143     }
144
145     /**
146      * Generates the query to retrieve the cells for a list of segments.
147      * Called by Segment.load
148      */

149     public String JavaDoc generateSql(
150             final Segment[] segments,
151             final BitKey levelBitKey,
152             final BitKey measureBitKey) {
153         // Check if using aggregates is enabled.
154
if (MondrianProperties.instance().UseAggregates.get()) {
155             RolapStar star = segments[0].aggregation.getStar();
156
157             final boolean[] rollup = {false};
158             AggStar aggStar = findAgg(star, levelBitKey, measureBitKey, rollup);
159
160             if (aggStar != null) {
161                 // Got a match, hot damn
162

163                 if (getLogger().isDebugEnabled()) {
164                     StringBuilder JavaDoc buf = new StringBuilder JavaDoc(256);
165                     buf.append("MATCH: ");
166                     buf.append(star.getFactTable().getAlias());
167                     buf.append(" foreign=");
168                     buf.append(levelBitKey);
169                     buf.append(Util.nl);
170                     buf.append(" measure=");
171                     buf.append(measureBitKey);
172                     buf.append(Util.nl);
173                     buf.append(" aggstar=");
174                     buf.append(aggStar.getBitKey());
175                     buf.append(Util.nl);
176                     buf.append("AggStar=");
177                     buf.append(aggStar.getFactTable().getName());
178                     buf.append(Util.nl);
179                     for (AggStar.Table.Column column : aggStar.getFactTable()
180                         .getColumns()) {
181                         buf.append(" ");
182                         buf.append(column);
183                         buf.append(Util.nl);
184                     }
185                     getLogger().debug(buf.toString());
186                 }
187
188                 AggQuerySpec aggQuerySpec =
189                         new AggQuerySpec(aggStar, segments, rollup[0]);
190                 String JavaDoc sql = aggQuerySpec.generateSqlQuery();
191                 return sql;
192             }
193
194             // No match, fall through and use fact table.
195
}
196
197         if (getLogger().isDebugEnabled()) {
198             RolapStar star = segments[0].aggregation.getStar();
199
200             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(256);
201             buf.append("NO MATCH: ");
202             buf.append(star.getFactTable().getAlias());
203             buf.append(Util.nl);
204             buf.append(" foreign=");
205             buf.append(levelBitKey);
206             buf.append(Util.nl);
207             buf.append(" measure=");
208             buf.append(measureBitKey);
209             buf.append(Util.nl);
210
211             getLogger().debug(buf.toString());
212         }
213
214
215         // Fact table query
216
SegmentArrayQuerySpec spec =
217             new SegmentArrayQuerySpec(segments);
218         String JavaDoc sql = spec.generateSqlQuery();
219         return sql;
220     }
221
222     /**
223      * Finds an aggregate table in the given star which has the desired levels
224      * and measures. Returns null if no aggregate table is suitable.
225      *
226      * <p>If there no aggregate is an exact match, returns a more
227      * granular aggregate which can be rolled up, and sets rollup to true.
228      * If one or more of the measures are distinct-count measures
229      * rollup is possible only in limited circumstances.
230      *
231      * @param star Star
232      * @param levelBitKey Set of levels
233      * @param measureBitKey Set of measures
234      * @param rollup Out parameter, is set to true if the aggregate is not
235      * an exact match
236      * @return An aggregate, or null if none is suitable.
237      */

238     public AggStar findAgg(
239             RolapStar star,
240             final BitKey levelBitKey,
241             final BitKey measureBitKey,
242             boolean[] rollup) {
243         // If there is no distinct count measure, isDistinct == false,
244
// then all we want is an AggStar whose BitKey is a superset
245
// of the combined measure BitKey and foreign-key/level BitKey.
246
//
247
// On the other hand, if there is at least one distinct count
248
// measure, isDistinct == true, then what is wanted is an AggStar
249
// whose measure BitKey is a superset of the measure BitKey,
250
// whose level BitKey is an exact match and the aggregate table
251
// can NOT have any foreign keys.
252
assert rollup != null;
253         BitKey fullBitKey = levelBitKey.or(measureBitKey);
254
255         // The AggStars are already ordered from smallest to largest so
256
// we need only find the first one and return it.
257
for (AggStar aggStar : star.getAggStars()) {
258             // superset match
259
if (!aggStar.superSetMatch(fullBitKey)) {
260                 continue;
261             }
262
263             boolean isDistinct = measureBitKey.intersects(
264                 aggStar.getDistinctMeasureBitKey());
265
266             // The AggStar has no "distinct count" measures so
267
// we can use it without looking any further.
268
if (!isDistinct) {
269                 rollup[0] = !aggStar.getLevelBitKey().equals(levelBitKey);
270                 return aggStar;
271             }
272
273             // If there are distinct measures, we can only rollup in limited
274
// circumstances.
275

276             // No foreign keys (except when its used as a distinct count
277
// measure).
278
// Level key exact match.
279
// Measure superset match.
280

281             // Compute the core levels -- those which can be safely
282
// rolled up to. For example,
283
// if the measure is 'distinct customer count',
284
// and the agg table has levels customer_id,
285
// then gender is a core level.
286
final BitKey distinctMeasuresBitKey =
287                 measureBitKey.and(aggStar.getDistinctMeasureBitKey());
288             final BitSet distinctMeasures = distinctMeasuresBitKey.toBitSet();
289             BitKey combinedLevelBitKey = null;
290             for (int k = distinctMeasures.nextSetBit(0); k >= 0;
291                 k = distinctMeasures.nextSetBit(k + 1)) {
292                 final AggStar.FactTable.Measure distinctMeasure =
293                     aggStar.lookupMeasure(k);
294                 BitKey rollableLevelBitKey =
295                     distinctMeasure.getRollableLevelBitKey();
296                 if (combinedLevelBitKey == null) {
297                     combinedLevelBitKey = rollableLevelBitKey;
298                 } else {
299                     // TODO use '&=' to remove unnecessary copy
300
combinedLevelBitKey =
301                         combinedLevelBitKey.and(rollableLevelBitKey);
302                 }
303             }
304
305             if (aggStar.hasForeignKeys()) {
306 /*
307                     StringBuilder buf = new StringBuilder(256);
308                     buf.append("");
309                     buf.append(star.getFactTable().getAlias());
310                     buf.append(Util.nl);
311                     buf.append("foreign =");
312                     buf.append(levelBitKey);
313                     buf.append(Util.nl);
314                     buf.append("measure =");
315                     buf.append(measureBitKey);
316                     buf.append(Util.nl);
317                     buf.append("aggstar =");
318                     buf.append(aggStar.getBitKey());
319                     buf.append(Util.nl);
320                     buf.append("distinct=");
321                     buf.append(aggStar.getDistinctMeasureBitKey());
322                     buf.append(Util.nl);
323                     buf.append("AggStar=");
324                     buf.append(aggStar.getFactTable().getName());
325                     buf.append(Util.nl);
326                     for (Iterator columnIter =
327                             aggStar.getFactTable().getColumns().iterator();
328                          columnIter.hasNext(); ) {
329                         AggStar.Table.Column column =
330                                 (AggStar.Table.Column) columnIter.next();
331                         buf.append(" ");
332                         buf.append(column);
333                         buf.append(Util.nl);
334                     }
335 System.out.println(buf.toString());
336 */

337                 // This is a little pessimistic. If the measure is
338
// 'count(distinct customer_id)' and one of the foreign keys is
339
// 'customer_id' then it is OK to roll up.
340

341                 // Some of the measures in this query are distinct count.
342
// Get all of the foreign key columns.
343
// For each such measure, is it based upon a foreign key.
344
// Are there any foreign keys left over. No, can use AggStar.
345
BitKey fkBitKey = aggStar.getForeignKeyBitKey().copy();
346                 Iterator mit = aggStar.getFactTable().getMeasures().iterator();
347                 for (AggStar.FactTable.Measure measure : aggStar.getFactTable()
348                     .getMeasures()) {
349                     if (measure.isDistinct()) {
350                         if (measureBitKey.get(measure.getBitPosition())) {
351                             fkBitKey.clear(measure.getBitPosition());
352                         }
353                     }
354                 }
355                 if (!fkBitKey.isEmpty()) {
356                     // there are foreign keys left so we can not use this
357
// AggStar.
358
continue;
359                 }
360             }
361
362             if (!aggStar.select(
363                 levelBitKey, combinedLevelBitKey, measureBitKey)) {
364                 continue;
365             }
366
367             rollup[0] = !aggStar.getLevelBitKey().equals(levelBitKey);
368             return aggStar;
369         }
370         return null;
371     }
372
373     public PinSet createPinSet() {
374         return new PinSetImpl();
375     }
376
377     /**
378      * Implementation of {@link RolapAggregationManager.PinSet}
379      * using a {@link HashSet}.
380      */

381     public static class PinSetImpl extends HashSet<Segment>
382                 implements RolapAggregationManager.PinSet {
383     }
384 }
385
386 // End AggregationManager.java
387
Popular Tags