The command processor is designed to cover certain specific features, and is limited in that sense. The underlying query model is much more powerful and therefore more complex in its configuration. BTW, I am not sure if I have mentioned it already, but the BI Java SDK is incredibly powerful and flexible and can help solve problems in myriads of ways.
A simple Top N query based on one dimension can be easily created using the command processor. The steps and source code depicted below show one way to configure such a query.
IBIQuery query = olap.createQuery(sampleMetaData.cube); IBICommandProcessor commandProcessor = query.getCommandProcessor(); commandProcessor.addMember(sampleMetaData.measuresQuantityMember); commandProcessor.addMember(sampleMetaData.measuresCostMember); commandProcessor.moveDimensionToRows( sampleMetaData.soldToPartyDimension); commandProcessor.addLevelMembers(soldToParty2ndLevel); commandProcessor.createTopCountFilter( sampleMetaData.soldToPartyDimension, 10, sampleMetaData.measuresQuantityMember);
Now, if you want to create a Top N query based on a crossjoin of two dimensions on the rows, you have to go beyond the command processor. The command processor only offers commands to create ranking filters for a single dimension, which is the first parameter of the method. Next we look at how to work around that and explore some of the myriads of solutions to it.
We'll start by configuring the query differently. We specify a crossjoin of two dimensions for the rows axis. Everything else is done as in our first example. The question now is how to create the top count filter based on the crossjoin of the two dimensions. See the sample code up to that point below:
... commandProcessor.moveDimensionToRows( sampleMetaData.soldToPartyDimension); commandProcessor.addLevelMembers(soldToParty2ndLevel); commandProcessor.moveDimensionToRows( sampleMetaData.distributionChannelDimension); commandProcessor.addLevelMembers(distributionChannel2ndLevel); commandProcessor.createTopCountFilter ???
One way to create the filter is to manually create all the objects necessary to specify such a ranking filter. This is shown in the steps and code below:
IBIQueryFactory queryFactory = olap.getQueryFactory(); IBILiteralReference literalReference = queryFactory.getInputFactory().createLiteralReference( new Integer(10)); IBIMemberReference numericExpression = queryFactory.getInputFactory().createMemberReference( sampleMetaData.measuresQuantityMember); IBIRankingFilter rankingFilter = queryFactory.getMemberSetFactory().createRankingFilter( IBIRankTypeEnum.TOPCOUNT, literalReference, numericExpression, IBIJoinTypeEnum.INITIAL); ((IBIAxis) query.getAxis().get(IBICommandProcessor.ROWS_AXIS_INDEX)) .getTupleSet().getTupleSetExpression().add(rankingFilter);
An alternative for creating the ranking filter is to use the command processor. Now, you might be confused, because I told you that there is no support for doing this. But the point is that there is no difference in the ranking filter based on an axis dimension compared to one based on an axis. Consider the call to create and add a top count filter for the soldToParty dimension at the very beginning of this weblog. It creates and adds a ranking filter to the dimension's member set. That's the only reason the call takes the dimension as a parameter.
What we can do to make use of the command processor is to create a ranking filter based on one dimension, remove it from the dimension's member set, and place it on the axis tuple set.
We'll show how to do this below, but first note two interesting points:
IBIRankingFilter rankingFilter = commandProcessor.createTopCountFilter( sampleMetaData.soldToPartyDimension, 10, sampleMetaData.measuresQuantityMember); rankingFilter.getMemberSet().getMemberSetExpression().remove(rankingFilter); ((IBIAxis) query.getAxis().get(IBICommandProcessor.ROWS_AXIS_INDEX)) .getTupleSet().getTupleSetExpression().add(rankingFilter);
Finally, let's look at a larger piece of code that creates Top N and Bottom N count and percent queries in general and could be considered a template for these types of business questions.
The method to create these queries has several parameters, that I'd like to explain a bit:
olap
is the olap interface previously retrieved from the connectioncube
is the cube upon which to base the queryrankingMeasure
is used as the ranking criteriadisplayMeasures
are the measures to select on the columns axislevels
specify the levels of the dimensions of which members are selected and crossjoined on the rows axis. The order of the levels in the list is important for the crossjointopTrueBottomFalse
determines wether a top or bottom query is createdcountTruePercentFalse
determines wether a top/bottom-count or -percent query is createdvalue
specifies N for top or bottom query, which is either an integer type in the case of count, or a float type in the case of percent.public static IBIQuery createTopBottomQuery( IBIOlap olap, Cube cube, IBIMember rankingMeasure, List displayMeasures, List levels, boolean topTrueBottomFalse, boolean countTruePercentFalse, double value) throws BIOlapQueryException { IBIQueryFactory queryFactory = olap.getQueryFactory(); IBIQuery query = olap.createQuery(cube); IBICommandProcessor commandProcessor = query.getCommandProcessor(); IBILiteralReference literalReference = null; IBIRankType rankType = null; for (Iterator i = displayMeasures.iterator(); i.hasNext();) { IBIMember measure = (IBIMember) i.next(); commandProcessor.addMember(measure); } for (Iterator i = levels.iterator(); i.hasNext();) { Level level = (Level) i.next(); Dimension dimension = level.getDimension(); commandProcessor.moveDimensionToRows(dimension); commandProcessor.addLevelMembers(level); } if (countTruePercentFalse == true) { literalReference = queryFactory.getInputFactory().createLiteralReference( new Long(Math.round(value))); if (topTrueBottomFalse == true) { rankType = IBIRankTypeEnum.TOPCOUNT; } else { rankType = IBIRankTypeEnum.BOTTOMCOUNT; } } else { literalReference = queryFactory.getInputFactory().createLiteralReference( new Double(value)); if (topTrueBottomFalse == true) { rankType = IBIRankTypeEnum.TOPPERCENT; } else { rankType = IBIRankTypeEnum.BOTTOMPERCENT; } } IBIMemberReference numericExpression = queryFactory.getInputFactory().createMemberReference(rankingMeasure); IBIRankingFilter rankingFilter = queryFactory.getMemberSetFactory().createRankingFilter( rankType, literalReference, numericExpression, IBIJoinTypeEnum.INITIAL); ((IBIAxis) query.getAxis().get(IBICommandProcessor.ROWS_AXIS_INDEX)) .getTupleSet().getTupleSetExpression().add(rankingFilter); return query; }
If you haven't already, download the BI Java SDK from the SDN Downloads page today and get started with your own business question!
Love, Jens.