📄 quax.java
字号:
* MDX Generation for Generate
*
* @return Exp for axis set
*/
private Object genGenerateExp(boolean genHierarchize) {
ExpGenerator expGenerator = new ExpGenerator(uti);
// Generate(GSet, FSet) to be generated
// hierarchies >= generateIndex will not be "hierarchized"
// we expect the hierarchies >= generateIndex to be excluded
// from hierarchize.
if (nDimension - generateIndex > nHierExclude)
logger.warn("unexpected values: nHierExclude=" + nHierExclude + " generateIndex="
+ generateIndex);
// assume following situation:
// 3 hierarchies
// time - customers - product
// we want top 5 customers, generated for each time member
// 1. step
// generate expression until customers (only time here), result = set1
// if neccessary, put hierarchize around
// 2. step
// Generate(set1, Topcount(Crossjoin ({Time.Currentmember}, Set for Customers),
// 5, condition))
// result = set2
// 3.step
// append the tail nodes , here Product
// Crossjoin(set2 , Product dimension nodes)
//
// 1. step left expression, potentially hierarchized
Object leftExp = null;
// if nHierExclude > nDimension - generateIndex
// and nHierExclude < nDimension
// the the left expression (inside Generate) will be partly
// hierarchized
if (genHierarchize && nHierExclude > nDimension - generateIndex && nHierExclude < nDimension) {
int nLeft = nDimension - nHierExclude;
int nRight = generateIndex - nLeft;
leftExp = genLeftRight(expGenerator, nLeft, nRight);
} else {
TreeNode leftRoot = posTreeRoot.deepCopyPrune(generateIndex);
leftRoot.setReference(null);
Hierarchy[] leftHiers = new Hierarchy[generateIndex];
for (int i = 0; i < leftHiers.length; i++) {
leftHiers[i] = hiers[i];
}
expGenerator.init(leftRoot, leftHiers);
leftExp = expGenerator.genExp();
if (genHierarchize)
leftExp = uti.createFunCall("Hierarchize", new Object[] { leftExp},
QuaxUti.FUNTYPE_FUNCTION);
}
// 2. step Generate(set1, Topcount())
TreeNode topCountNode = posTreeRoot;
// top count node can be anything like topcount, bottomcount, filter
for (int i = 0; i <= generateIndex; i++) {
// the path to the topcount node at generateIndex does not matter
List children = topCountNode.getChildren();
topCountNode = (TreeNode) children.get(0);
}
Object topcount = topCountNode.getReference();
// we have to replace the "set" of the topcount function
Object origTopcountSet = uti.funCallArg(topcount, 0);
// generate the Tuple of dimension.currentmember until generateIndex
Object currentMembersTuple = genCurrentTuple();
Object ocj = uti.createFunCall("Crossjoin",
new Object[] { currentMembersTuple, origTopcountSet}, QuaxUti.FUNTYPE_FUNCTION);
// replace the topcout original set
String fun = uti.funCallName(topcount);
int n = uti.funCallArgCount(topcount);
Object[] args = new Object[n];
for (int i = 1; i < n; i++) {
args[i] = uti.funCallArg(topcount, i);
}
args[0] = ocj;
Object newTopcount = uti.createFunCall(fun, args, QuaxUti.FUNTYPE_FUNCTION);
Object oGenerate = uti.createFunCall("Generate", new Object[] { leftExp, newTopcount},
QuaxUti.FUNTYPE_FUNCTION);
if (generateIndex + 1 == nDimension)
return oGenerate;
// 3. step append the tail nodes
// generate CrossJoin
int nRight = nDimension - generateIndex - 1;
Hierarchy[] rightHiers = new Hierarchy[nRight];
for (int i = 1; i <= nRight; i++) {
rightHiers[nRight - i] = hiers[nDimension - i];
}
TreeNode root = new TreeNode(null);
List list = topCountNode.getChildren();
for (Iterator iter = list.iterator(); iter.hasNext();) {
TreeNode node = (TreeNode) iter.next();
root.addChildNode(node.deepCopy());
}
expGenerator.init(root, rightHiers);
Object rightExp = expGenerator.genExp();
Object exp = uti.createFunCall("CrossJoin", new Object[] { oGenerate, rightExp},
QuaxUti.FUNTYPE_FUNCTION);
return exp;
}
// ==========
// private
// ==========
/**
* generate {(dim1.Currentmember, dim2.Currentmember, ... )}
*
* @return
*/
private Object genCurrentTuple() {
Object[] currentsOfDim = new Object[generateIndex];
for (int i = 0; i < currentsOfDim.length; i++) {
Dimension dim = hiers[i].getDimension();
currentsOfDim[i] = uti.createFunCall("CurrentMember", new Object[] { uti.objForDim(dim)},
QuaxUti.FUNTYPE_PROPERTY);
}
Object oTuple;
if (generateIndex > 1)
oTuple = uti.createFunCall("()", currentsOfDim, QuaxUti.FUNTYPE_TUPLE);
else
oTuple = currentsOfDim[0]; // just dimension.currentmember
// generate set braces around tuple
Object oSet = uti.createFunCall("{}", new Object[] { oTuple}, QuaxUti.FUNTYPE_BRACES);
return oSet;
}
/**
* @return true if child position can be found
*/
private boolean checkChildPosition(final Member[] mPath) {
int ret = posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback find node matching member Path exactly
*/
public int handleTreeNode(TreeNode node) {
int iDim = mPath.length - 1;
int iDimNode = node.getLevel() - 1;
Object oExp = node.getReference();
if (iDimNode < iDim) {
// node Exp must match member[iDim]
if (uti.isMember(oExp)) {
if (uti.equalMember(oExp, mPath[iDimNode]))
return TreeNodeCallback.CONTINUE;
else
return TreeNodeCallback.CONTINUE_SIBLING; // continue
// next
// sibling
} else {
// must be FunCall
if (isMemberInFunCall(oExp, mPath[iDimNode], iDimNode))
return TreeNodeCallback.CONTINUE;
else
return TreeNodeCallback.CONTINUE_SIBLING; // continue
// next
// sibling
}
}
// iDimNode == iDim
// node Exp must contain children of member[iDim]
if (uti.isMember(oExp)) {
if (uti.checkParent(mPath[iDimNode], oExp))
return TreeNodeCallback.BREAK; // found
else
return TreeNodeCallback.CONTINUE_SIBLING; // continue
// next
// sibling
} else {
// must be FunCall
if (isChildOfMemberInFunCall(oExp, mPath[iDimNode], iDimNode))
return TreeNodeCallback.BREAK; // found
else
return TreeNodeCallback.CONTINUE_SIBLING; // continue
// next
// sibling
}
}
});
if (ret == TreeNodeCallback.BREAK)
return true; // child path fund
else
return false;
} // checkChildPosition
/**
* resolve the qubon mode unions and crossjoins only used in "old" expand mode
*/
private void resolveUnions() {
final List[] setLists = new List[nDimension];
for (int i = 0; i < setLists.length; i++) {
setLists[i] = new ArrayList();
}
posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback resolve sets of any dimension
*/
public int handleTreeNode(TreeNode node) {
int iDimNode = node.getLevel() - 1;
Object oExp = node.getReference();
if (!uti.isMember(oExp)) {
// FunCall
funToList(oExp, setLists[iDimNode]);
} else {
// member
setLists[iDimNode].add(oExp);
}
return TreeNodeCallback.CONTINUE;
} // handleTreeNode
});
// unions and sets are resolved, now resolve crossjoins
posTreeRoot = new TreeNode(null);
crossJoinTree(setLists, posTreeRoot, 0);
qubonMode = false;
}
/**
* find best tree node for member path (longest match)
*/
private TreeNode findBestNode(final Member[] mPath) {
final TreeNode[] bestNode = new TreeNode[1];
bestNode[0] = posTreeRoot;
posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback find node matching member Path exactly
*/
public int handleTreeNode(TreeNode node) {
int iDim = mPath.length - 1;
int iDimNode = node.getLevel() - 1;
Object oExp = node.getReference();
if (!uti.isMember(oExp))
return TreeNodeCallback.CONTINUE_SIBLING; // continue next
// sibling
if (uti.equalMember(oExp, mPath[iDimNode])) {
// match
if (iDimNode == iDim) {
// found exactly matching node
bestNode[0] = node;
return TreeNodeCallback.BREAK;
} else {
// best match up to now
bestNode[0] = node;
return TreeNodeCallback.CONTINUE;
}
} else {
// no match
return TreeNodeCallback.CONTINUE_SIBLING; // continue next
// sibling
}
}
});
return bestNode[0];
}
/**
* collect tail nodes for all nodes matching member path
*/
private List collectTailNodes(TreeNode startNode, final Member[] mPath) {
final List tailNodes = new ArrayList();
startNode.walkChildren(new TreeNodeCallback() {
/**
* callback find node matching mPath collect tail nodes
*/
public int handleTreeNode(TreeNode node) {
int iDim = mPath.length - 1;
int iDimNode = node.getLevel() - 1;
Object oExp = node.getReference();
boolean match = false;
if (uti.isMember(oExp)) {
// exp is member
if (uti.equalMember(oExp, mPath[iDimNode]))
match = true;
} else {
// must be FunCall
if (isMemberInFunCall(oExp, mPath[iDimNode], iDimNode))
match = true;
}
if (match) {
if (iDimNode == iDim) {
// add the children to the tail list
tailNodes.addAll(node.getChildren());
return TreeNodeCallback.CONTINUE_SIBLING;
} else {
// iDimNode < iDim
return TreeNodeCallback.CONTINUE;
}
} else
return TreeNodeCallback.CONTINUE_SIBLING; // no match,
// continue next
// sibling
} // handlePositionTreeNode
});
return tailNodes;
}
private boolean findMemberChild(final Member member) {
final int iDim = this.dimIdx(uti.dimForMember(member));
int ret = posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback find child node of monMember
*/
public int handleTreeNode(TreeNode node) {
int iDimNode = node.getLevel() - 1;
if (iDimNode < iDim)
return TreeNodeCallback.CONTINUE; // we are below iDim,
// don't care
// iDimNode == iDim
// node Exp must contain children of member[iDim]
Object oExp = node.getReference();
if (uti.isMember(oExp)) {
if (uti.checkParent(member, oExp))
return TreeNodeCallback.BREAK; // found
} else {
// must be FunCall
if (isChildOfMemberInFunCall(oExp, member, iDimNode))
return TreeNodeCallback.BREAK; // found
}
return TreeNodeCallback.CONTINUE_SIBLING; // continue next
// sibling
}
});
return (ret == TreeNodeCallback.BREAK);
}
/**
* String representation (debugging)
*/
public String toString() {
final StringBuffer sbPosTree = new StringBuffer();
sbPosTree.append("number of hierarchies excluded from HIEARARCHIZE=" + nHierExclude);
sbPosTree.append('\n');
if (posTreeRoot == null) {
sbPosTree.append("Root=null");
return sbPosTree.toString();
}
posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback quax to String
*/
public int handleTreeNode(TreeNode node) {
int iDimNode = node.getLevel() - 1;
sbPosTree.append("\n");
for (int i = 0; i < iDimNode - 1; i++) {
sbPosTree.append(" ");
}
if (iDimNode > 0) {
sbPosTree.append("+--");
}
Object oExp = node.getReference();
if (!uti.isMember(oExp)) {
// FunCall
sbPosTree.append(uti.funString(oExp));
} else {
// member
sbPosTree.append(uti.getMemberUniqueName(oExp));
}
return TreeNodeCallback.CONTINUE;
} // handleTreeNode
});
return sbPosTree.toString();
}
/**
* build tree resolving crossjoin
*
* @param currentNode
* @param iDim
*/
private void crossJoinTree(List[] setLists, TreeNode currentNode, int iDim) {
for (Iterator iter = setLists[iDim].iterator(); iter.hasNext();) {
Object oExp = iter.next();
TreeNode newNode = new TreeNode(oExp);
if (iDim < nDimension - 1)
crossJoinTree(setLists, newNode, iDim + 1);
currentNode.addChildNode(newNode);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -