use of org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator in project asterixdb by apache.
the class AbstractIntroduceAccessMethodRule method getFieldNameFromSubTree.
/**
* Returns the field name corresponding to the assigned variable at
* varIndex. Returns null if the expr at varIndex does not yield to a field
* access function after following a set of allowed functions.
*
* @throws AlgebricksException
*/
protected List<String> getFieldNameFromSubTree(IOptimizableFuncExpr optFuncExpr, OptimizableOperatorSubTree subTree, int opIndex, int assignVarIndex, ARecordType recordType, int funcVarIndex, ILogicalExpression parentFuncExpr, LogicalVariable recordVar, ARecordType metaType, LogicalVariable metaVar) throws AlgebricksException {
// Get expression corresponding to opVar at varIndex.
AbstractLogicalExpression expr = null;
AbstractFunctionCallExpression childFuncExpr = null;
AbstractLogicalOperator op = subTree.getAssignsAndUnnests().get(opIndex);
if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
AssignOperator assignOp = (AssignOperator) op;
expr = (AbstractLogicalExpression) assignOp.getExpressions().get(assignVarIndex).getValue();
// Can't get a field name from a constant expression. So, return null.
if (expr.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
return Collections.emptyList();
}
childFuncExpr = (AbstractFunctionCallExpression) expr;
} else {
UnnestOperator unnestOp = (UnnestOperator) op;
expr = (AbstractLogicalExpression) unnestOp.getExpressionRef().getValue();
if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
return Collections.emptyList();
}
childFuncExpr = (AbstractFunctionCallExpression) expr;
if (childFuncExpr.getFunctionIdentifier() != BuiltinFunctions.SCAN_COLLECTION) {
return Collections.emptyList();
}
expr = (AbstractLogicalExpression) childFuncExpr.getArguments().get(0).getValue();
}
if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
return Collections.emptyList();
}
AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier();
boolean isByName = false;
boolean isFieldAccess = false;
String fieldName = null;
List<String> nestedAccessFieldName = null;
int fieldIndex = -1;
if (funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_NAME) {
fieldName = ConstantExpressionUtil.getStringArgument(funcExpr, 1);
if (fieldName == null) {
return Collections.emptyList();
}
isFieldAccess = true;
isByName = true;
} else if (funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_INDEX) {
Integer idx = ConstantExpressionUtil.getIntArgument(funcExpr, 1);
if (idx == null) {
return Collections.emptyList();
}
fieldIndex = idx;
isFieldAccess = true;
} else if (funcIdent == BuiltinFunctions.FIELD_ACCESS_NESTED) {
ILogicalExpression nameArg = funcExpr.getArguments().get(1).getValue();
if (nameArg.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
return Collections.emptyList();
}
ConstantExpression constExpr = (ConstantExpression) nameArg;
AOrderedList orderedNestedFieldName = (AOrderedList) ((AsterixConstantValue) constExpr.getValue()).getObject();
nestedAccessFieldName = new ArrayList<>();
for (int i = 0; i < orderedNestedFieldName.size(); i++) {
nestedAccessFieldName.add(((AString) orderedNestedFieldName.getItem(i)).getStringValue());
}
isFieldAccess = true;
isByName = true;
}
if (isFieldAccess) {
LogicalVariable sourceVar = ((VariableReferenceExpression) funcExpr.getArguments().get(0).getValue()).getVariableReference();
optFuncExpr.setLogicalExpr(funcVarIndex, parentFuncExpr);
int[] assignAndExpressionIndexes = null;
//go forward through nested assigns until you find the relevant one
for (int i = opIndex + 1; i < subTree.getAssignsAndUnnests().size(); i++) {
AbstractLogicalOperator subOp = subTree.getAssignsAndUnnests().get(i);
List<LogicalVariable> varList;
if (subOp.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
//Nested was an assign
varList = ((AssignOperator) subOp).getVariables();
} else if (subOp.getOperatorTag() == LogicalOperatorTag.UNNEST) {
//Nested is not an assign
varList = ((UnnestOperator) subOp).getVariables();
} else {
break;
}
//Go through variables in assign to check for match
for (int varIndex = 0; varIndex < varList.size(); varIndex++) {
LogicalVariable var = varList.get(varIndex);
ArrayList<LogicalVariable> parentVars = new ArrayList<>();
expr.getUsedVariables(parentVars);
if (parentVars.contains(var)) {
//Found the variable we are looking for.
//return assign and index of expression
int[] returnValues = { i, varIndex };
assignAndExpressionIndexes = returnValues;
}
}
}
if (assignAndExpressionIndexes != null && assignAndExpressionIndexes[0] > -1) {
//We found the nested assign
//Recursive call on nested assign
List<String> parentFieldNames = getFieldNameFromSubTree(optFuncExpr, subTree, assignAndExpressionIndexes[0], assignAndExpressionIndexes[1], recordType, funcVarIndex, parentFuncExpr, recordVar, metaType, metaVar);
if (parentFieldNames.isEmpty()) {
//We will not use index
return Collections.emptyList();
}
if (!isByName) {
fieldName = sourceVar.equals(metaVar) ? ((ARecordType) metaType.getSubFieldType(parentFieldNames)).getFieldNames()[fieldIndex] : ((ARecordType) recordType.getSubFieldType(parentFieldNames)).getFieldNames()[fieldIndex];
}
optFuncExpr.setSourceVar(funcVarIndex, ((AssignOperator) op).getVariables().get(assignVarIndex));
//add fieldName to the nested fieldName, return
if (nestedAccessFieldName != null) {
for (int i = 0; i < nestedAccessFieldName.size(); i++) {
parentFieldNames.add(nestedAccessFieldName.get(i));
}
} else {
parentFieldNames.add(fieldName);
}
return (parentFieldNames);
}
optFuncExpr.setSourceVar(funcVarIndex, ((AssignOperator) op).getVariables().get(assignVarIndex));
//no nested assign, we are at the lowest level.
if (isByName) {
if (nestedAccessFieldName != null) {
return nestedAccessFieldName;
}
return new ArrayList<>(Arrays.asList(fieldName));
}
return new ArrayList<>(Arrays.asList(sourceVar.equals(metaVar) ? metaType.getFieldNames()[fieldIndex] : recordType.getFieldNames()[fieldIndex]));
}
if (!funcIDSetThatRetainFieldName.contains(funcIdent)) {
return Collections.emptyList();
}
// We use a part of the field in edit distance computation
if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.EDIT_DISTANCE_CHECK) {
optFuncExpr.setPartialField(true);
}
// We expect the function's argument to be a variable, otherwise we
// cannot apply an index.
ILogicalExpression argExpr = funcExpr.getArguments().get(0).getValue();
if (argExpr.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
return Collections.emptyList();
}
LogicalVariable curVar = ((VariableReferenceExpression) argExpr).getVariableReference();
// the current operator
for (int assignOrUnnestIndex = opIndex + 1; assignOrUnnestIndex < subTree.getAssignsAndUnnests().size(); assignOrUnnestIndex++) {
AbstractLogicalOperator curOp = subTree.getAssignsAndUnnests().get(assignOrUnnestIndex);
if (curOp.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
AssignOperator assignOp = (AssignOperator) curOp;
List<LogicalVariable> varList = assignOp.getVariables();
for (int varIndex = 0; varIndex < varList.size(); varIndex++) {
LogicalVariable var = varList.get(varIndex);
if (var.equals(curVar)) {
optFuncExpr.setSourceVar(funcVarIndex, var);
return getFieldNameFromSubTree(optFuncExpr, subTree, assignOrUnnestIndex, varIndex, recordType, funcVarIndex, childFuncExpr, recordVar, metaType, metaVar);
}
}
} else {
UnnestOperator unnestOp = (UnnestOperator) curOp;
LogicalVariable var = unnestOp.getVariable();
if (var.equals(curVar)) {
getFieldNameFromSubTree(optFuncExpr, subTree, assignOrUnnestIndex, 0, recordType, funcVarIndex, childFuncExpr, recordVar, metaType, metaVar);
}
}
}
return Collections.emptyList();
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator in project asterixdb by apache.
the class UnnestToDataScanRule method rewritePost.
@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
if (op.getOperatorTag() != LogicalOperatorTag.UNNEST) {
return false;
}
UnnestOperator unnest = (UnnestOperator) op;
ILogicalExpression unnestExpr = unnest.getExpressionRef().getValue();
if (unnestExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
return false;
}
return handleFunction(opRef, context, unnest, (AbstractFunctionCallExpression) unnestExpr);
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator in project asterixdb by apache.
the class RemoveRedundantListifyRule method appliesForReverseCase.
private boolean appliesForReverseCase(Mutable<ILogicalOperator> opRef, Set<LogicalVariable> varUsedAbove, IOptimizationContext context) throws AlgebricksException {
AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
if (op1.getOperatorTag() != LogicalOperatorTag.AGGREGATE) {
return false;
}
AggregateOperator agg = (AggregateOperator) op1;
if (agg.getVariables().size() > 1 || agg.getVariables().size() <= 0) {
return false;
}
LogicalVariable aggVar = agg.getVariables().get(0);
ILogicalExpression aggFun = agg.getExpressions().get(0).getValue();
AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) aggFun;
if (!BuiltinFunctions.LISTIFY.equals(f.getFunctionIdentifier())) {
return false;
}
if (f.getArguments().size() != 1) {
return false;
}
ILogicalExpression arg0 = f.getArguments().get(0).getValue();
if (((AbstractLogicalExpression) arg0).getExpressionTag() != LogicalExpressionTag.VARIABLE) {
return false;
}
LogicalVariable aggInputVar = ((VariableReferenceExpression) arg0).getVariableReference();
if (varUsedAbove.contains(aggInputVar)) {
return false;
}
if (agg.getInputs().size() == 0) {
return false;
}
AbstractLogicalOperator op2 = (AbstractLogicalOperator) agg.getInputs().get(0).getValue();
if (op2.getOperatorTag() != LogicalOperatorTag.UNNEST) {
return false;
}
UnnestOperator unnest = (UnnestOperator) op2;
if (unnest.getPositionalVariable() != null) {
return false;
}
if (!unnest.getVariable().equals(aggInputVar)) {
return false;
}
ILogicalExpression unnestArg = unnest.getExpressionRef().getValue();
if (unnestArg.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
return false;
}
AbstractFunctionCallExpression scanFunc = (AbstractFunctionCallExpression) unnestArg;
if (scanFunc.getFunctionIdentifier() != BuiltinFunctions.SCAN_COLLECTION) {
return false;
}
if (scanFunc.getArguments().size() != 1) {
return false;
}
List<LogicalVariable> assgnVars = new ArrayList<>(1);
assgnVars.add(aggVar);
AssignOperator assign = new AssignOperator(assgnVars, scanFunc.getArguments());
assign.getInputs().add(unnest.getInputs().get(0));
context.computeAndSetTypeEnvironmentForOperator(assign);
opRef.setValue(assign);
return true;
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator in project asterixdb by apache.
the class LangExpressionToPlanTranslator method visit.
@Override
public Pair<ILogicalOperator, LogicalVariable> visit(QuantifiedExpression qe, Mutable<ILogicalOperator> tupSource) throws CompilationException {
Mutable<ILogicalOperator> topOp = tupSource;
ILogicalOperator firstOp = null;
Mutable<ILogicalOperator> lastOp = null;
for (QuantifiedPair qt : qe.getQuantifiedList()) {
Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo1 = langExprToAlgExpression(qt.getExpr(), topOp);
topOp = eo1.second;
LogicalVariable uVar = context.newVarFromExpression(qt.getVarExpr());
ILogicalOperator u = new UnnestOperator(uVar, new MutableObject<>(makeUnnestExpression(eo1.first)));
if (firstOp == null) {
firstOp = u;
}
if (lastOp != null) {
u.getInputs().add(lastOp);
}
lastOp = new MutableObject<>(u);
}
// We make all the unnest correspond. to quantif. vars. sit on top
// in the hope of enabling joins & other optimiz.
firstOp.getInputs().add(topOp);
topOp = lastOp;
Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo2 = langExprToAlgExpression(qe.getSatisfiesExpr(), topOp);
AggregateFunctionCallExpression fAgg;
SelectOperator s;
if (qe.getQuantifier() == Quantifier.SOME) {
s = new SelectOperator(new MutableObject<>(eo2.first), false, null);
s.getInputs().add(eo2.second);
fAgg = BuiltinFunctions.makeAggregateFunctionExpression(BuiltinFunctions.NON_EMPTY_STREAM, new ArrayList<>());
} else {
// EVERY
List<Mutable<ILogicalExpression>> satExprList = new ArrayList<>(1);
satExprList.add(new MutableObject<>(eo2.first));
s = new SelectOperator(new MutableObject<>(new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AlgebricksBuiltinFunctions.NOT), satExprList)), false, null);
s.getInputs().add(eo2.second);
fAgg = BuiltinFunctions.makeAggregateFunctionExpression(BuiltinFunctions.EMPTY_STREAM, new ArrayList<>());
}
LogicalVariable qeVar = context.newVar();
AggregateOperator a = new AggregateOperator(mkSingletonArrayList(qeVar), (List) mkSingletonArrayList(new MutableObject<>(fAgg)));
a.getInputs().add(new MutableObject<>(s));
return new Pair<>(a, qeVar);
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator in project asterixdb by apache.
the class SqlppExpressionToPlanTranslator method visit.
@Override
public Pair<ILogicalOperator, LogicalVariable> visit(CaseExpression caseExpression, Mutable<ILogicalOperator> tupSource) throws CompilationException {
//Creates a series of subplan operators, one for each branch.
Mutable<ILogicalOperator> currentOpRef = tupSource;
ILogicalOperator currentOperator = null;
List<Expression> whenExprList = caseExpression.getWhenExprs();
List<Expression> thenExprList = caseExpression.getThenExprs();
List<ILogicalExpression> branchCondVarReferences = new ArrayList<>();
List<ILogicalExpression> allVarReferences = new ArrayList<>();
for (int index = 0; index < whenExprList.size(); ++index) {
Pair<ILogicalOperator, LogicalVariable> whenExprResult = whenExprList.get(index).accept(this, currentOpRef);
currentOperator = whenExprResult.first;
// Variable whenConditionVar is corresponds to the current "WHEN" condition.
LogicalVariable whenConditionVar = whenExprResult.second;
Mutable<ILogicalExpression> branchEntraceConditionExprRef = new MutableObject<>(new VariableReferenceExpression(whenConditionVar));
// even though multiple "WHEN" conditions can be satisfied.
if (!branchCondVarReferences.isEmpty()) {
// The additional filter generated here makes sure the the tuple has not
// entered other matched "WHEN...THEN" case.
List<Mutable<ILogicalExpression>> andArgs = new ArrayList<>();
andArgs.add(generateNoMatchedPrecedingWhenBranchesFilter(branchCondVarReferences));
andArgs.add(branchEntraceConditionExprRef);
// A "THEN" branch can be entered only when the tuple has not enter any other preceding
// branches and the current "WHEN" condition is TRUE.
branchEntraceConditionExprRef = new MutableObject<>(new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.AND), andArgs));
}
// Translates the corresponding "THEN" expression.
Pair<ILogicalOperator, LogicalVariable> opAndVarForThen = constructSubplanOperatorForBranch(currentOperator, branchEntraceConditionExprRef, thenExprList.get(index));
branchCondVarReferences.add(new VariableReferenceExpression(whenConditionVar));
allVarReferences.add(new VariableReferenceExpression(whenConditionVar));
allVarReferences.add(new VariableReferenceExpression(opAndVarForThen.second));
currentOperator = opAndVarForThen.first;
currentOpRef = new MutableObject<>(currentOperator);
}
// Creates a subplan for the "ELSE" branch.
Mutable<ILogicalExpression> elseCondExprRef = generateNoMatchedPrecedingWhenBranchesFilter(branchCondVarReferences);
Pair<ILogicalOperator, LogicalVariable> opAndVarForElse = constructSubplanOperatorForBranch(currentOperator, elseCondExprRef, caseExpression.getElseExpr());
// Uses switch-case function to select the results of two branches.
LogicalVariable selectVar = context.newVar();
List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
arguments.add(new MutableObject<>(new ConstantExpression(new AsterixConstantValue(ABoolean.TRUE))));
for (ILogicalExpression argVar : allVarReferences) {
arguments.add(new MutableObject<>(argVar));
}
arguments.add(new MutableObject<>(new VariableReferenceExpression(opAndVarForElse.second)));
AbstractFunctionCallExpression swithCaseExpr = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.SWITCH_CASE), arguments);
AssignOperator assignOp = new AssignOperator(selectVar, new MutableObject<>(swithCaseExpr));
assignOp.getInputs().add(new MutableObject<>(opAndVarForElse.first));
// Unnests the selected (a "THEN" or "ELSE" branch) result.
LogicalVariable unnestVar = context.newVar();
UnnestOperator unnestOp = new UnnestOperator(unnestVar, new MutableObject<>(new UnnestingFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.SCAN_COLLECTION), Collections.singletonList(new MutableObject<>(new VariableReferenceExpression(selectVar))))));
unnestOp.getInputs().add(new MutableObject<>(assignOp));
// Produces the final assign operator.
LogicalVariable resultVar = context.newVar();
AssignOperator finalAssignOp = new AssignOperator(resultVar, new MutableObject<>(new VariableReferenceExpression(unnestVar)));
finalAssignOp.getInputs().add(new MutableObject<>(unnestOp));
return new Pair<>(finalAssignOp, resultVar);
}
Aggregations