You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by im...@apache.org on 2015/08/25 18:44:16 UTC
[28/51] [partial] incubator-asterixdb git commit: Change folder
structure for Java repackage
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SweepIllegalNonfunctionalFunctions.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SweepIllegalNonfunctionalFunctions.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SweepIllegalNonfunctionalFunctions.java
new file mode 100644
index 0000000..e2f2f4f
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SweepIllegalNonfunctionalFunctions.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.asterix.optimizer.rules;
+
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataLookupOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.PartitioningSplitOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SinkOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.WriteOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+import edu.uci.ics.hyracks.algebricks.rewriter.rules.AbstractExtractExprRule;
+
+public class SweepIllegalNonfunctionalFunctions extends AbstractExtractExprRule implements IAlgebraicRewriteRule {
+
+ private final IllegalNonfunctionalFunctionSweeperOperatorVisitor visitor;
+
+ public SweepIllegalNonfunctionalFunctions() {
+ visitor = new IllegalNonfunctionalFunctionSweeperOperatorVisitor();
+ }
+
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+ return false;
+ }
+
+ @Override
+ public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+ ILogicalOperator op = opRef.getValue();
+ if (context.checkIfInDontApplySet(this, op)) {
+ return false;
+ }
+
+ op.accept(visitor, null);
+ context.computeAndSetTypeEnvironmentForOperator(op);
+ context.addToDontApplySet(this, op);
+ return false;
+ }
+
+ private class IllegalNonfunctionalFunctionSweeperOperatorVisitor implements ILogicalOperatorVisitor<Void, Void> {
+
+ private void sweepExpression(ILogicalExpression expr, ILogicalOperator op) throws AlgebricksException {
+ if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ if (!expr.isFunctional()) {
+ AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expr;
+ throw new AlgebricksException("Found non-functional function " + fce.getFunctionIdentifier()
+ + " in op " + op);
+ }
+ }
+ }
+
+ @Override
+ public Void visitAggregateOperator(AggregateOperator op, Void arg) throws AlgebricksException {
+ for (Mutable<ILogicalExpression> me : op.getExpressions()) {
+ sweepExpression(me.getValue(), op);
+ }
+ List<Mutable<ILogicalExpression>> mergeExprs = op.getMergeExpressions();
+ if (mergeExprs != null) {
+ for (Mutable<ILogicalExpression> me : mergeExprs) {
+ sweepExpression(me.getValue(), op);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitRunningAggregateOperator(RunningAggregateOperator op, Void arg) throws AlgebricksException {
+ for (Mutable<ILogicalExpression> me : op.getExpressions()) {
+ sweepExpression(me.getValue(), op);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitGroupByOperator(GroupByOperator op, Void arg) throws AlgebricksException {
+ for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : op.getGroupByList()) {
+ sweepExpression(p.second.getValue(), op);
+ }
+ for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : op.getDecorList()) {
+ sweepExpression(p.second.getValue(), op);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitLimitOperator(LimitOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitInnerJoinOperator(InnerJoinOperator op, Void arg) throws AlgebricksException {
+ sweepExpression(op.getCondition().getValue(), op);
+ return null;
+ }
+
+ @Override
+ public Void visitLeftOuterJoinOperator(LeftOuterJoinOperator op, Void arg) throws AlgebricksException {
+ sweepExpression(op.getCondition().getValue(), op);
+ return null;
+ }
+
+ @Override
+ public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitOrderOperator(OrderOperator op, Void arg) throws AlgebricksException {
+ for (Pair<IOrder, Mutable<ILogicalExpression>> p : op.getOrderExpressions()) {
+ sweepExpression(p.second.getValue(), op);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitAssignOperator(AssignOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitSelectOperator(SelectOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitExtensionOperator(ExtensionOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitProjectOperator(ProjectOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitPartitioningSplitOperator(PartitioningSplitOperator op, Void arg) throws AlgebricksException {
+ for (Mutable<ILogicalExpression> expr : op.getExpressions()) {
+ sweepExpression(expr.getValue(), op);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitReplicateOperator(ReplicateOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitMaterializeOperator(MaterializeOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitScriptOperator(ScriptOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitSubplanOperator(SubplanOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitSinkOperator(SinkOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitUnionOperator(UnionAllOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitUnnestOperator(UnnestOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitUnnestMapOperator(UnnestMapOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitDataScanOperator(DataSourceScanOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitDistinctOperator(DistinctOperator op, Void arg) throws AlgebricksException {
+ for (Mutable<ILogicalExpression> expr : op.getExpressions()) {
+ sweepExpression(expr.getValue(), op);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitExchangeOperator(ExchangeOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitWriteOperator(WriteOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitDistributeResultOperator(DistributeResultOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitWriteResultOperator(WriteResultOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitInsertDeleteOperator(InsertDeleteOperator op, Void tag) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, Void tag) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitTokenizeOperator(TokenizeOperator op, Void tag) throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitExternalDataLookupOperator(ExternalDataLookupOperator op, Void arg) throws AlgebricksException {
+ return null;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/UnnestToDataScanRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/UnnestToDataScanRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/UnnestToDataScanRule.java
new file mode 100644
index 0000000..6defc07
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/UnnestToDataScanRule.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.asterix.optimizer.rules;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.asterix.common.config.DatasetConfig.DatasetType;
+import edu.uci.ics.asterix.common.feeds.FeedActivity.FeedActivityDetails;
+import edu.uci.ics.asterix.common.feeds.api.IFeedLifecycleListener.ConnectionLocation;
+import edu.uci.ics.asterix.metadata.declared.AqlDataSource;
+import edu.uci.ics.asterix.metadata.declared.AqlMetadataProvider;
+import edu.uci.ics.asterix.metadata.declared.AqlSourceId;
+import edu.uci.ics.asterix.metadata.declared.FeedDataSource;
+import edu.uci.ics.asterix.metadata.entities.Dataset;
+import edu.uci.ics.asterix.metadata.entities.Dataverse;
+import edu.uci.ics.asterix.metadata.entities.Feed;
+import edu.uci.ics.asterix.metadata.entities.FeedPolicy;
+import edu.uci.ics.asterix.metadata.feeds.BuiltinFeedPolicies;
+import edu.uci.ics.asterix.metadata.utils.DatasetUtils;
+import edu.uci.ics.asterix.om.base.AString;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.optimizer.rules.util.EquivalenceClassUtils;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IAlgebricksConstantValue;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.properties.FunctionalDependency;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class UnnestToDataScanRule implements IAlgebraicRewriteRule {
+
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+ return false;
+ }
+
+ @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) {
+ AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) unnestExpr;
+ FunctionIdentifier fid = f.getFunctionIdentifier();
+
+ if (fid.equals(AsterixBuiltinFunctions.DATASET)) {
+ if (unnest.getPositionalVariable() != null) {
+ // TODO remove this after enabling the support of positional variables in data scan
+ throw new AlgebricksException("No positional variables are allowed over datasets.");
+ }
+ ILogicalExpression expr = f.getArguments().get(0).getValue();
+ if (expr.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+ return false;
+ }
+ ConstantExpression ce = (ConstantExpression) expr;
+ IAlgebricksConstantValue acv = ce.getValue();
+ if (!(acv instanceof AsterixConstantValue)) {
+ return false;
+ }
+ AsterixConstantValue acv2 = (AsterixConstantValue) acv;
+ if (acv2.getObject().getType().getTypeTag() != ATypeTag.STRING) {
+ return false;
+ }
+ String datasetArg = ((AString) acv2.getObject()).getStringValue();
+
+ AqlMetadataProvider metadataProvider = (AqlMetadataProvider) context.getMetadataProvider();
+ Pair<String, String> datasetReference = parseDatasetReference(metadataProvider, datasetArg);
+ String dataverseName = datasetReference.first;
+ String datasetName = datasetReference.second;
+ Dataset dataset = metadataProvider.findDataset(dataverseName, datasetName);
+ if (dataset == null) {
+ throw new AlgebricksException("Could not find dataset " + datasetName + " in dataverse "
+ + dataverseName);
+ }
+
+ AqlSourceId asid = new AqlSourceId(dataverseName, datasetName);
+
+ ArrayList<LogicalVariable> v = new ArrayList<LogicalVariable>();
+
+ if (dataset.getDatasetType() == DatasetType.INTERNAL) {
+ int numPrimaryKeys = DatasetUtils.getPartitioningKeys(dataset).size();
+ for (int i = 0; i < numPrimaryKeys; i++) {
+ v.add(context.newVar());
+ }
+ }
+ v.add(unnest.getVariable());
+ AqlDataSource dataSource = metadataProvider.findDataSource(asid);
+ DataSourceScanOperator scan = new DataSourceScanOperator(v, dataSource);
+ List<Mutable<ILogicalOperator>> scanInpList = scan.getInputs();
+ scanInpList.addAll(unnest.getInputs());
+ opRef.setValue(scan);
+ addPrimaryKey(v, context);
+ context.computeAndSetTypeEnvironmentForOperator(scan);
+
+ // Adds equivalence classes --- one equivalent class between a primary key
+ // variable and a record field-access expression.
+ IAType[] schemaTypes = dataSource.getSchemaTypes();
+ ARecordType recordType = (ARecordType) schemaTypes[schemaTypes.length - 1];
+ EquivalenceClassUtils.addEquivalenceClassesForPrimaryIndexAccess(scan, v, recordType, dataset, context);
+ return true;
+ }
+
+ if (fid.equals(AsterixBuiltinFunctions.FEED_COLLECT)) {
+ if (unnest.getPositionalVariable() != null) {
+ throw new AlgebricksException("No positional variables are allowed over datasets.");
+ }
+
+ String dataverse = getStringArgument(f, 0);
+ String sourceFeedName = getStringArgument(f, 1);
+ String getTargetFeed = getStringArgument(f, 2);
+ String subscriptionLocation = getStringArgument(f, 3);
+ String targetDataset = getStringArgument(f, 4);
+ String outputType = getStringArgument(f, 5);
+
+ AqlMetadataProvider metadataProvider = (AqlMetadataProvider) context.getMetadataProvider();
+
+ AqlSourceId asid = new AqlSourceId(dataverse, getTargetFeed);
+ String policyName = metadataProvider.getConfig().get(FeedActivityDetails.FEED_POLICY_NAME);
+ FeedPolicy policy = metadataProvider.findFeedPolicy(dataverse, policyName);
+ if (policy == null) {
+ policy = BuiltinFeedPolicies.getFeedPolicy(policyName);
+ if (policy == null) {
+ throw new AlgebricksException("Unknown feed policy:" + policyName);
+ }
+ }
+
+ ArrayList<LogicalVariable> v = new ArrayList<LogicalVariable>();
+ v.add(unnest.getVariable());
+
+ String csLocations = metadataProvider.getConfig().get(FeedActivityDetails.COLLECT_LOCATIONS);
+ DataSourceScanOperator scan = new DataSourceScanOperator(v, createFeedDataSource(asid, targetDataset,
+ sourceFeedName, subscriptionLocation, metadataProvider, policy, outputType, csLocations));
+
+ List<Mutable<ILogicalOperator>> scanInpList = scan.getInputs();
+ scanInpList.addAll(unnest.getInputs());
+ opRef.setValue(scan);
+ addPrimaryKey(v, context);
+ context.computeAndSetTypeEnvironmentForOperator(scan);
+
+ return true;
+ }
+
+ }
+
+ return false;
+ }
+
+ public void addPrimaryKey(List<LogicalVariable> scanVariables, IOptimizationContext context) {
+ int n = scanVariables.size();
+ List<LogicalVariable> head = new ArrayList<LogicalVariable>(scanVariables.subList(0, n - 1));
+ List<LogicalVariable> tail = new ArrayList<LogicalVariable>(1);
+ tail.add(scanVariables.get(n - 1));
+ FunctionalDependency pk = new FunctionalDependency(head, tail);
+ context.addPrimaryKey(pk);
+ }
+
+ private AqlDataSource createFeedDataSource(AqlSourceId aqlId, String targetDataset, String sourceFeedName,
+ String subscriptionLocation, AqlMetadataProvider metadataProvider, FeedPolicy feedPolicy,
+ String outputType, String locations) throws AlgebricksException {
+ if (!aqlId.getDataverseName().equals(
+ metadataProvider.getDefaultDataverse() == null ? null : metadataProvider.getDefaultDataverse()
+ .getDataverseName())) {
+ return null;
+ }
+ IAType feedOutputType = metadataProvider.findType(aqlId.getDataverseName(), outputType);
+ Feed sourceFeed = metadataProvider.findFeed(aqlId.getDataverseName(), sourceFeedName);
+
+ FeedDataSource feedDataSource = new FeedDataSource(aqlId, targetDataset, feedOutputType,
+ AqlDataSource.AqlDataSourceType.FEED, sourceFeed.getFeedId(), sourceFeed.getFeedType(),
+ ConnectionLocation.valueOf(subscriptionLocation), locations.split(","));
+ feedDataSource.getProperties().put(BuiltinFeedPolicies.CONFIG_FEED_POLICY_KEY, feedPolicy);
+ return feedDataSource;
+ }
+
+ private Pair<String, String> parseDatasetReference(AqlMetadataProvider metadataProvider, String datasetArg)
+ throws AlgebricksException {
+ String[] datasetNameComponents = datasetArg.split("\\.");
+ String dataverseName;
+ String datasetName;
+ if (datasetNameComponents.length == 1) {
+ Dataverse defaultDataverse = metadataProvider.getDefaultDataverse();
+ if (defaultDataverse == null) {
+ throw new AlgebricksException("Unresolved dataset " + datasetArg + " Dataverse not specified.");
+ }
+ dataverseName = defaultDataverse.getDataverseName();
+ datasetName = datasetNameComponents[0];
+ } else {
+ dataverseName = datasetNameComponents[0];
+ datasetName = datasetNameComponents[1];
+ }
+ return new Pair<String, String>(dataverseName, datasetName);
+ }
+
+ private String getStringArgument(AbstractFunctionCallExpression f, int index) {
+
+ ILogicalExpression expr = f.getArguments().get(index).getValue();
+ if (expr.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+ return null;
+ }
+ ConstantExpression ce = (ConstantExpression) expr;
+ IAlgebricksConstantValue acv = ce.getValue();
+ if (!(acv instanceof AsterixConstantValue)) {
+ return null;
+ }
+ AsterixConstantValue acv2 = (AsterixConstantValue) acv;
+ if (acv2.getObject().getType().getTypeTag() != ATypeTag.STRING) {
+ return null;
+ }
+ String argument = ((AString) acv2.getObject()).getStringValue();
+ return argument;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
new file mode 100644
index 0000000..b6d07a3
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.asterix.optimizer.rules.am;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.asterix.common.config.DatasetConfig.IndexType;
+import edu.uci.ics.asterix.dataflow.data.common.AqlExpressionTypeComputer;
+import edu.uci.ics.asterix.metadata.api.IMetadataEntity;
+import edu.uci.ics.asterix.metadata.bootstrap.MetadataConstants;
+import edu.uci.ics.asterix.metadata.declared.AqlMetadataProvider;
+import edu.uci.ics.asterix.metadata.entities.Index;
+import edu.uci.ics.asterix.metadata.utils.DatasetUtils;
+import edu.uci.ics.asterix.om.base.AInt32;
+import edu.uci.ics.asterix.om.base.AOrderedList;
+import edu.uci.ics.asterix.om.base.AString;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.om.types.hierachy.ATypeHierarchy;
+import edu.uci.ics.asterix.optimizer.rules.am.OptimizableOperatorSubTree.DataSourceType;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractLogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * Class that embodies the commonalities between rewrite rules for access
+ * methods.
+ */
+public abstract class AbstractIntroduceAccessMethodRule implements IAlgebraicRewriteRule {
+
+ private AqlMetadataProvider metadataProvider;
+
+ public abstract Map<FunctionIdentifier, List<IAccessMethod>> getAccessMethods();
+
+ protected static void registerAccessMethod(IAccessMethod accessMethod,
+ Map<FunctionIdentifier, List<IAccessMethod>> accessMethods) {
+ List<FunctionIdentifier> funcs = accessMethod.getOptimizableFunctions();
+ for (FunctionIdentifier funcIdent : funcs) {
+ List<IAccessMethod> l = accessMethods.get(funcIdent);
+ if (l == null) {
+ l = new ArrayList<IAccessMethod>();
+ accessMethods.put(funcIdent, l);
+ }
+ l.add(accessMethod);
+ }
+ }
+
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+ return false;
+ }
+
+ protected void setMetadataDeclarations(IOptimizationContext context) {
+ metadataProvider = (AqlMetadataProvider) context.getMetadataProvider();
+ }
+
+ protected void fillSubTreeIndexExprs(OptimizableOperatorSubTree subTree,
+ Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs, IOptimizationContext context)
+ throws AlgebricksException {
+ Iterator<Map.Entry<IAccessMethod, AccessMethodAnalysisContext>> amIt = analyzedAMs.entrySet().iterator();
+ // Check applicability of indexes by access method type.
+ while (amIt.hasNext()) {
+ Map.Entry<IAccessMethod, AccessMethodAnalysisContext> entry = amIt.next();
+ AccessMethodAnalysisContext amCtx = entry.getValue();
+ // For the current access method type, map variables to applicable
+ // indexes.
+ fillAllIndexExprs(subTree, amCtx, context);
+ }
+ }
+
+ protected void pruneIndexCandidates(Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs)
+ throws AlgebricksException {
+ Iterator<Map.Entry<IAccessMethod, AccessMethodAnalysisContext>> amIt = analyzedAMs.entrySet().iterator();
+ // Check applicability of indexes by access method type.
+ while (amIt.hasNext()) {
+ Map.Entry<IAccessMethod, AccessMethodAnalysisContext> entry = amIt.next();
+ AccessMethodAnalysisContext amCtx = entry.getValue();
+ pruneIndexCandidates(entry.getKey(), amCtx);
+ // Remove access methods for which there are definitely no
+ // applicable indexes.
+ if (amCtx.indexExprsAndVars.isEmpty()) {
+ amIt.remove();
+ }
+ }
+ }
+
+ /**
+ * Simply picks the first index that it finds. TODO: Improve this decision
+ * process by making it more systematic.
+ */
+ protected Pair<IAccessMethod, Index> chooseIndex(Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs) {
+ Iterator<Map.Entry<IAccessMethod, AccessMethodAnalysisContext>> amIt = analyzedAMs.entrySet().iterator();
+ while (amIt.hasNext()) {
+ Map.Entry<IAccessMethod, AccessMethodAnalysisContext> amEntry = amIt.next();
+ AccessMethodAnalysisContext analysisCtx = amEntry.getValue();
+ Iterator<Map.Entry<Index, List<Pair<Integer, Integer>>>> indexIt = analysisCtx.indexExprsAndVars.entrySet()
+ .iterator();
+ if (indexIt.hasNext()) {
+ Map.Entry<Index, List<Pair<Integer, Integer>>> indexEntry = indexIt.next();
+ // To avoid a case where the chosen access method and a chosen
+ // index type is different.
+ // Allowed Case: [BTreeAccessMethod , IndexType.BTREE],
+ // [RTreeAccessMethod , IndexType.RTREE],
+ // [InvertedIndexAccessMethod,
+ // IndexType.SINGLE_PARTITION_WORD_INVIX ||
+ // SINGLE_PARTITION_NGRAM_INVIX ||
+ // LENGTH_PARTITIONED_WORD_INVIX ||
+ // LENGTH_PARTITIONED_NGRAM_INVIX]
+ IAccessMethod chosenAccessMethod = amEntry.getKey();
+ Index chosenIndex = indexEntry.getKey();
+ boolean isKeywordOrNgramIndexChosen = false;
+ if (chosenIndex.getIndexType() == IndexType.LENGTH_PARTITIONED_WORD_INVIX
+ || chosenIndex.getIndexType() == IndexType.LENGTH_PARTITIONED_NGRAM_INVIX
+ || chosenIndex.getIndexType() == IndexType.SINGLE_PARTITION_WORD_INVIX
+ || chosenIndex.getIndexType() == IndexType.SINGLE_PARTITION_NGRAM_INVIX)
+ isKeywordOrNgramIndexChosen = true;
+ if ((chosenAccessMethod == BTreeAccessMethod.INSTANCE && chosenIndex.getIndexType() != IndexType.BTREE)
+ || (chosenAccessMethod == RTreeAccessMethod.INSTANCE && chosenIndex.getIndexType() != IndexType.RTREE)
+ || (chosenAccessMethod == InvertedIndexAccessMethod.INSTANCE && !isKeywordOrNgramIndexChosen)) {
+ continue;
+ }
+ return new Pair<IAccessMethod, Index>(chosenAccessMethod, chosenIndex);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes irrelevant access methods candidates, based on whether the
+ * expressions in the query match those in the index. For example, some
+ * index may require all its expressions to be matched, and some indexes may
+ * only require a match on a prefix of fields to be applicable. This methods
+ * removes all index candidates indexExprs that are definitely not
+ * applicable according to the expressions involved.
+ *
+ * @throws AlgebricksException
+ */
+ public void pruneIndexCandidates(IAccessMethod accessMethod, AccessMethodAnalysisContext analysisCtx)
+ throws AlgebricksException {
+ Iterator<Map.Entry<Index, List<Pair<Integer, Integer>>>> indexExprAndVarIt = analysisCtx.indexExprsAndVars
+ .entrySet().iterator();
+ // Used to keep track of matched expressions (added for prefix search)
+ int numMatchedKeys = 0;
+ ArrayList<Integer> matchedExpressions = new ArrayList<Integer>();
+ while (indexExprAndVarIt.hasNext()) {
+ Map.Entry<Index, List<Pair<Integer, Integer>>> indexExprAndVarEntry = indexExprAndVarIt.next();
+ Index index = indexExprAndVarEntry.getKey();
+ boolean allUsed = true;
+ int lastFieldMatched = -1;
+ boolean foundKeyField = false;
+ matchedExpressions.clear();
+ numMatchedKeys = 0;
+
+ // Remove the candidate if the dataset is a metadata dataset and the index is secondary
+ // TODO: fix the way secondary metadata indexes are implemented and remove this check
+ if (accessMethod.matchPrefixIndexExprs()) {
+ if (index.getDataverseName().equals(MetadataConstants.METADATA_DATAVERSE_NAME)
+ && !index.isPrimaryIndex()) {
+ indexExprAndVarIt.remove();
+ continue;
+ }
+ }
+ for (int i = 0; i < index.getKeyFieldNames().size(); i++) {
+ List<String> keyField = index.getKeyFieldNames().get(i);
+ final IAType keyType = index.getKeyFieldTypes().get(i);
+ Iterator<Pair<Integer, Integer>> exprsAndVarIter = indexExprAndVarEntry.getValue().iterator();
+ while (exprsAndVarIter.hasNext()) {
+ final Pair<Integer, Integer> exprAndVarIdx = exprsAndVarIter.next();
+ final IOptimizableFuncExpr optFuncExpr = analysisCtx.matchedFuncExprs.get(exprAndVarIdx.first);
+ // If expr is not optimizable by concrete index then remove
+ // expr and continue.
+ if (!accessMethod.exprIsOptimizable(index, optFuncExpr)) {
+ exprsAndVarIter.remove();
+ continue;
+ }
+ boolean typeMatch = true;
+ //Prune indexes based on field types
+ List<IAType> indexedTypes = new ArrayList<IAType>();
+ //retrieve types of expressions joined/selected with an indexed field
+ for (int j = 0; j < optFuncExpr.getNumLogicalVars(); j++)
+ if (j != exprAndVarIdx.second)
+ indexedTypes.add(optFuncExpr.getFieldType(j));
+ //add constants in case of select
+ if (indexedTypes.size() < 2 && optFuncExpr.getNumLogicalVars() == 1) {
+ indexedTypes.add((IAType) AqlExpressionTypeComputer.INSTANCE.getType(new ConstantExpression(
+ optFuncExpr.getConstantVal(0)), null, null));
+ }
+ //infer type of logicalExpr based on index keyType
+ indexedTypes.add((IAType) AqlExpressionTypeComputer.INSTANCE.getType(
+ optFuncExpr.getLogicalExpr(exprAndVarIdx.second), null, new IVariableTypeEnvironment() {
+
+ @Override
+ public Object getVarType(LogicalVariable var) throws AlgebricksException {
+ if (var.equals(optFuncExpr.getSourceVar(exprAndVarIdx.second)))
+ return keyType;
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public Object getVarType(LogicalVariable var, List<LogicalVariable> nonNullVariables,
+ List<List<LogicalVariable>> correlatedNullableVariableLists)
+ throws AlgebricksException {
+ if (var.equals(optFuncExpr.getSourceVar(exprAndVarIdx.second)))
+ return keyType;
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public void setVarType(LogicalVariable var, Object type) {
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public Object getType(ILogicalExpression expr) throws AlgebricksException {
+ return AqlExpressionTypeComputer.INSTANCE.getType(expr, null, this);
+ }
+
+ @Override
+ public boolean substituteProducedVariable(LogicalVariable v1, LogicalVariable v2)
+ throws AlgebricksException {
+ throw new IllegalArgumentException();
+ }
+ }));
+
+ //for the case when jaccard similarity is measured between ordered & unordered lists
+ boolean jaccardSimilarity = optFuncExpr.getFuncExpr().getFunctionIdentifier().getName()
+ .startsWith("similarity-jaccard-check");
+
+ for (int j = 0; j < indexedTypes.size(); j++)
+ for (int k = j + 1; k < indexedTypes.size(); k++)
+ typeMatch &= isMatched(indexedTypes.get(j), indexedTypes.get(k), jaccardSimilarity);
+
+ // Check if any field name in the optFuncExpr matches.
+ if (optFuncExpr.findFieldName(keyField) != -1) {
+ foundKeyField = typeMatch
+ && optFuncExpr.getOperatorSubTree(exprAndVarIdx.second).hasDataSourceScan();
+ if (foundKeyField) {
+ matchedExpressions.add(exprAndVarIdx.first);
+ numMatchedKeys++;
+ if (lastFieldMatched == i - 1) {
+ lastFieldMatched = i;
+ }
+ break;
+ }
+ }
+ }
+ if (!foundKeyField) {
+ allUsed = false;
+ // if any expression was matched, remove the non-matched expressions, otherwise the index is unusable
+ if (lastFieldMatched >= 0) {
+ exprsAndVarIter = indexExprAndVarEntry.getValue().iterator();
+ while (exprsAndVarIter.hasNext()) {
+ if (!matchedExpressions.contains(exprsAndVarIter.next().first)) {
+ exprsAndVarIter.remove();
+ }
+ }
+ }
+ break;
+ }
+ }
+ // If the access method requires all exprs to be matched but they
+ // are not, remove this candidate.
+ if (!allUsed && accessMethod.matchAllIndexExprs()) {
+ indexExprAndVarIt.remove();
+ continue;
+ }
+ // A prefix of the index exprs may have been matched.
+ if (accessMethod.matchPrefixIndexExprs()) {
+ if (lastFieldMatched < 0) {
+ indexExprAndVarIt.remove();
+ continue;
+ }
+ }
+ analysisCtx.indexNumMatchedKeys.put(index, new Integer(numMatchedKeys));
+ }
+ }
+
+ private boolean isMatched(IAType type1, IAType type2, boolean useListDomain) throws AlgebricksException {
+ if (ATypeHierarchy.isSameTypeDomain(Index.getNonNullableType(type1).first.getTypeTag(),
+ Index.getNonNullableType(type2).first.getTypeTag(), useListDomain))
+ return true;
+ return ATypeHierarchy.canPromote(Index.getNonNullableType(type1).first.getTypeTag(),
+ Index.getNonNullableType(type2).first.getTypeTag());
+ }
+
+ /**
+ * Analyzes the given selection condition, filling analyzedAMs with
+ * applicable access method types. At this point we are not yet consulting
+ * the metadata whether an actual index exists or not.
+ */
+ protected boolean analyzeCondition(ILogicalExpression cond, List<AbstractLogicalOperator> assignsAndUnnests,
+ Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs) {
+ AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) cond;
+ FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier();
+ // Don't consider optimizing a disjunctive condition with an index (too
+ // complicated for now).
+ if (funcIdent == AlgebricksBuiltinFunctions.OR) {
+ return false;
+ }
+ boolean found = analyzeFunctionExpr(funcExpr, assignsAndUnnests, analyzedAMs);
+ for (Mutable<ILogicalExpression> arg : funcExpr.getArguments()) {
+ ILogicalExpression argExpr = arg.getValue();
+ if (argExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+ continue;
+ }
+ AbstractFunctionCallExpression argFuncExpr = (AbstractFunctionCallExpression) argExpr;
+ boolean matchFound = analyzeFunctionExpr(argFuncExpr, assignsAndUnnests, analyzedAMs);
+ found = found || matchFound;
+ }
+ return found;
+ }
+
+ /**
+ * Finds applicable access methods for the given function expression based
+ * on the function identifier, and an analysis of the function's arguments.
+ * Updates the analyzedAMs accordingly.
+ */
+ protected boolean analyzeFunctionExpr(AbstractFunctionCallExpression funcExpr,
+ List<AbstractLogicalOperator> assignsAndUnnests, Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs) {
+ FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier();
+ if (funcIdent == AlgebricksBuiltinFunctions.AND) {
+ return false;
+ }
+ // Retrieves the list of access methods that are relevant based on the
+ // funcIdent.
+ List<IAccessMethod> relevantAMs = getAccessMethods().get(funcIdent);
+ if (relevantAMs == null) {
+ return false;
+ }
+ boolean atLeastOneMatchFound = false;
+ // Place holder for a new analysis context in case we need one.
+ AccessMethodAnalysisContext newAnalysisCtx = new AccessMethodAnalysisContext();
+ for (IAccessMethod accessMethod : relevantAMs) {
+ AccessMethodAnalysisContext analysisCtx = analyzedAMs.get(accessMethod);
+ // Use the current place holder.
+ if (analysisCtx == null) {
+ analysisCtx = newAnalysisCtx;
+ }
+ // Analyzes the funcExpr's arguments to see if the accessMethod is
+ // truly applicable.
+ boolean matchFound = accessMethod.analyzeFuncExprArgs(funcExpr, assignsAndUnnests, analysisCtx);
+ if (matchFound) {
+ // If we've used the current new context placeholder, replace it
+ // with a new one.
+ if (analysisCtx == newAnalysisCtx) {
+ analyzedAMs.put(accessMethod, analysisCtx);
+ newAnalysisCtx = new AccessMethodAnalysisContext();
+ }
+ atLeastOneMatchFound = true;
+ }
+ }
+ return atLeastOneMatchFound;
+ }
+
+ /**
+ * Finds secondary indexes whose keys include fieldName, and adds a mapping
+ * in analysisCtx.indexEsprs from that index to the a corresponding
+ * optimizable function expression.
+ *
+ * @return true if a candidate index was added to foundIndexExprs, false
+ * otherwise
+ * @throws AlgebricksException
+ */
+ protected boolean fillIndexExprs(List<Index> datasetIndexes, List<String> fieldName, IAType fieldType,
+ IOptimizableFuncExpr optFuncExpr, int matchedFuncExprIndex, int varIdx,
+ OptimizableOperatorSubTree matchedSubTree, AccessMethodAnalysisContext analysisCtx)
+ throws AlgebricksException {
+ List<Index> indexCandidates = new ArrayList<Index>();
+ // Add an index to the candidates if one of the indexed fields is
+ // fieldName
+ for (Index index : datasetIndexes) {
+ // Need to also verify the index is pending no op
+ if (index.getKeyFieldNames().contains(fieldName) && index.getPendingOp() == IMetadataEntity.PENDING_NO_OP) {
+ indexCandidates.add(index);
+ if (optFuncExpr.getFieldType(varIdx) == BuiltinType.ANULL
+ || optFuncExpr.getFieldType(varIdx) == BuiltinType.ANY)
+ optFuncExpr.setFieldType(varIdx,
+ index.getKeyFieldTypes().get(index.getKeyFieldNames().indexOf(fieldName)));
+ analysisCtx.addIndexExpr(matchedSubTree.dataset, index, matchedFuncExprIndex, varIdx);
+ }
+ }
+ // No index candidates for fieldName.
+ if (indexCandidates.isEmpty()) {
+ return false;
+ }
+ return true;
+ }
+
+ protected void fillAllIndexExprs(OptimizableOperatorSubTree subTree, AccessMethodAnalysisContext analysisCtx,
+ IOptimizationContext context) throws AlgebricksException {
+ int optFuncExprIndex = 0;
+ List<Index> datasetIndexes = new ArrayList<Index>();
+ if (subTree.dataSourceType != DataSourceType.COLLECTION_SCAN)
+ datasetIndexes = metadataProvider.getDatasetIndexes(subTree.dataset.getDataverseName(),
+ subTree.dataset.getDatasetName());
+ for (IOptimizableFuncExpr optFuncExpr : analysisCtx.matchedFuncExprs) {
+ // Try to match variables from optFuncExpr to assigns or unnests.
+ for (int assignOrUnnestIndex = 0; assignOrUnnestIndex < subTree.assignsAndUnnests.size(); assignOrUnnestIndex++) {
+ AbstractLogicalOperator op = subTree.assignsAndUnnests.get(assignOrUnnestIndex);
+ if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
+ AssignOperator assignOp = (AssignOperator) op;
+ List<LogicalVariable> varList = assignOp.getVariables();
+ for (int varIndex = 0; varIndex < varList.size(); varIndex++) {
+ LogicalVariable var = varList.get(varIndex);
+ int optVarIndex = optFuncExpr.findLogicalVar(var);
+ // No matching var in optFuncExpr.
+ if (optVarIndex == -1) {
+ continue;
+ }
+ // At this point we have matched the optimizable func
+ // expr at optFuncExprIndex to an assigned variable.
+ // Remember matching subtree.
+ optFuncExpr.setOptimizableSubTree(optVarIndex, subTree);
+ List<String> fieldName = getFieldNameFromSubTree(optFuncExpr, subTree, assignOrUnnestIndex,
+ varIndex, subTree.recordType, optVarIndex, optFuncExpr.getFuncExpr().getArguments()
+ .get(optVarIndex).getValue());
+ if (fieldName == null) {
+ continue;
+ }
+ IAType fieldType = (IAType) context.getOutputTypeEnvironment(assignOp).getType(
+ optFuncExpr.getLogicalExpr(optVarIndex));
+ // Set the fieldName in the corresponding matched
+ // function expression.
+ optFuncExpr.setFieldName(optVarIndex, fieldName);
+ optFuncExpr.setFieldType(optVarIndex, fieldType);
+
+ setTypeTag(context, subTree, optFuncExpr, optVarIndex);
+ if (subTree.hasDataSource()) {
+ fillIndexExprs(datasetIndexes, fieldName, fieldType, optFuncExpr, optFuncExprIndex,
+ optVarIndex, subTree, analysisCtx);
+ }
+ }
+ } else {
+ UnnestOperator unnestOp = (UnnestOperator) op;
+ LogicalVariable var = unnestOp.getVariable();
+ int funcVarIndex = optFuncExpr.findLogicalVar(var);
+ // No matching var in optFuncExpr.
+ if (funcVarIndex == -1) {
+ continue;
+ }
+ // At this point we have matched the optimizable func expr
+ // at optFuncExprIndex to an unnest variable.
+ // Remember matching subtree.
+ optFuncExpr.setOptimizableSubTree(funcVarIndex, subTree);
+ List<String> fieldName = null;
+ if (subTree.dataSourceType == DataSourceType.COLLECTION_SCAN) {
+ optFuncExpr.setLogicalExpr(funcVarIndex, new VariableReferenceExpression(var));
+ } else {
+ fieldName = getFieldNameFromSubTree(optFuncExpr, subTree, assignOrUnnestIndex, 0,
+ subTree.recordType, funcVarIndex,
+ optFuncExpr.getFuncExpr().getArguments().get(funcVarIndex).getValue());
+ if (fieldName == null) {
+ continue;
+ }
+ }
+ IAType fieldType = (IAType) context.getOutputTypeEnvironment(unnestOp).getType(
+ optFuncExpr.getLogicalExpr(funcVarIndex));
+ // Set the fieldName in the corresponding matched function
+ // expression.
+ optFuncExpr.setFieldName(funcVarIndex, fieldName);
+ optFuncExpr.setFieldType(funcVarIndex, fieldType);
+
+ setTypeTag(context, subTree, optFuncExpr, funcVarIndex);
+ if (subTree.hasDataSource()) {
+ fillIndexExprs(datasetIndexes, fieldName, fieldType, optFuncExpr, optFuncExprIndex,
+ funcVarIndex, subTree, analysisCtx);
+ }
+ }
+ }
+
+ // Try to match variables from optFuncExpr to datasourcescan if not
+ // already matched in assigns.
+ List<LogicalVariable> dsVarList = subTree.getDataSourceVariables();
+ for (int varIndex = 0; varIndex < dsVarList.size(); varIndex++) {
+ LogicalVariable var = dsVarList.get(varIndex);
+ int funcVarIndex = optFuncExpr.findLogicalVar(var);
+ // No matching var in optFuncExpr.
+ if (funcVarIndex == -1) {
+ continue;
+ }
+ // The variable value is one of the partitioning fields.
+ List<String> fieldName = DatasetUtils.getPartitioningKeys(subTree.dataset).get(varIndex);
+ IAType fieldType = (IAType) context.getOutputTypeEnvironment(subTree.dataSourceRef.getValue())
+ .getVarType(var);
+ // Set the fieldName in the corresponding matched function
+ // expression, and remember matching subtree.
+ optFuncExpr.setFieldName(funcVarIndex, fieldName);
+ optFuncExpr.setOptimizableSubTree(funcVarIndex, subTree);
+ optFuncExpr.setSourceVar(funcVarIndex, var);
+ optFuncExpr.setLogicalExpr(funcVarIndex, new VariableReferenceExpression(var));
+ setTypeTag(context, subTree, optFuncExpr, funcVarIndex);
+ if (subTree.hasDataSourceScan()) {
+ fillIndexExprs(datasetIndexes, fieldName, fieldType, optFuncExpr, optFuncExprIndex, funcVarIndex,
+ subTree, analysisCtx);
+ }
+ }
+ optFuncExprIndex++;
+ }
+ }
+
+ private void setTypeTag(IOptimizationContext context, OptimizableOperatorSubTree subTree,
+ IOptimizableFuncExpr optFuncExpr, int funcVarIndex) throws AlgebricksException {
+ // Set the typeTag if the type is not null
+ IAType type = (IAType) context.getOutputTypeEnvironment(subTree.root).getVarType(
+ optFuncExpr.getLogicalVar(funcVarIndex));
+ optFuncExpr.setFieldType(funcVarIndex, type);
+ }
+
+ /**
+ * 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) throws AlgebricksException {
+ // Get expression corresponding to opVar at varIndex.
+ AbstractLogicalExpression expr = null;
+ AbstractFunctionCallExpression childFuncExpr = null;
+ AbstractLogicalOperator op = subTree.assignsAndUnnests.get(opIndex);
+ if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
+ AssignOperator assignOp = (AssignOperator) op;
+ expr = (AbstractLogicalExpression) assignOp.getExpressions().get(assignVarIndex).getValue();
+ childFuncExpr = (AbstractFunctionCallExpression) expr;
+ } else {
+ UnnestOperator unnestOp = (UnnestOperator) op;
+ expr = (AbstractLogicalExpression) unnestOp.getExpressionRef().getValue();
+ if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+ return null;
+ }
+ childFuncExpr = (AbstractFunctionCallExpression) expr;
+ if (childFuncExpr.getFunctionIdentifier() != AsterixBuiltinFunctions.SCAN_COLLECTION) {
+ return null;
+ }
+ expr = (AbstractLogicalExpression) childFuncExpr.getArguments().get(0).getValue();
+ }
+ if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+ return null;
+ }
+ 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 == AsterixBuiltinFunctions.FIELD_ACCESS_BY_NAME) {
+ ILogicalExpression nameArg = funcExpr.getArguments().get(1).getValue();
+ if (nameArg.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+ return null;
+ }
+ ConstantExpression constExpr = (ConstantExpression) nameArg;
+ fieldName = ((AString) ((AsterixConstantValue) constExpr.getValue()).getObject()).getStringValue();
+ isFieldAccess = true;
+ isByName = true;
+ } else if (funcIdent == AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX) {
+ ILogicalExpression idxArg = funcExpr.getArguments().get(1).getValue();
+ if (idxArg.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+ return null;
+ }
+ ConstantExpression constExpr = (ConstantExpression) idxArg;
+ fieldIndex = ((AInt32) ((AsterixConstantValue) constExpr.getValue()).getObject()).getIntegerValue();
+ isFieldAccess = true;
+ } else if (funcIdent == AsterixBuiltinFunctions.FIELD_ACCESS_NESTED) {
+ ILogicalExpression nameArg = funcExpr.getArguments().get(1).getValue();
+ if (nameArg.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+ return null;
+ }
+ ConstantExpression constExpr = (ConstantExpression) nameArg;
+ AOrderedList orderedNestedFieldName = (AOrderedList) ((AsterixConstantValue) constExpr.getValue())
+ .getObject();
+ nestedAccessFieldName = new ArrayList<String>();
+ for (int i = 0; i < orderedNestedFieldName.size(); i++) {
+ nestedAccessFieldName.add(((AString) orderedNestedFieldName.getItem(i)).getStringValue());
+ }
+ isFieldAccess = true;
+ isByName = true;
+ }
+ if (isFieldAccess) {
+ 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.assignsAndUnnests.size(); i++) {
+ AbstractLogicalOperator subOp = subTree.assignsAndUnnests.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<LogicalVariable>();
+ 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);
+
+ if (parentFieldNames == null) {
+ //Nested assign was not a field access.
+ //We will not use index
+ return null;
+ }
+
+ if (!isByName) {
+ try {
+ fieldName = ((ARecordType) recordType.getSubFieldType(parentFieldNames)).getFieldNames()[fieldIndex];
+ } catch (IOException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+ 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<String>(Arrays.asList(fieldName));
+ }
+ return new ArrayList<String>(Arrays.asList(recordType.getFieldNames()[fieldIndex]));
+
+ }
+
+ if (funcIdent != AsterixBuiltinFunctions.WORD_TOKENS && funcIdent != AsterixBuiltinFunctions.GRAM_TOKENS
+ && funcIdent != AsterixBuiltinFunctions.SUBSTRING
+ && funcIdent != AsterixBuiltinFunctions.SUBSTRING_BEFORE
+ && funcIdent != AsterixBuiltinFunctions.SUBSTRING_AFTER
+ && funcIdent != AsterixBuiltinFunctions.CREATE_POLYGON
+ && funcIdent != AsterixBuiltinFunctions.CREATE_MBR
+ && funcIdent != AsterixBuiltinFunctions.CREATE_RECTANGLE
+ && funcIdent != AsterixBuiltinFunctions.CREATE_CIRCLE
+ && funcIdent != AsterixBuiltinFunctions.CREATE_LINE
+ && funcIdent != AsterixBuiltinFunctions.CREATE_POINT) {
+ return null;
+ }
+ // We use a part of the field in edit distance computation
+ if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == AsterixBuiltinFunctions.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 null;
+ }
+ LogicalVariable curVar = ((VariableReferenceExpression) argExpr).getVariableReference();
+ // We look for the assign or unnest operator that produces curVar below
+ // the current operator
+ for (int assignOrUnnestIndex = opIndex + 1; assignOrUnnestIndex < subTree.assignsAndUnnests.size(); assignOrUnnestIndex++) {
+ AbstractLogicalOperator curOp = subTree.assignsAndUnnests.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);
+ }
+ }
+ } else {
+ UnnestOperator unnestOp = (UnnestOperator) curOp;
+ LogicalVariable var = unnestOp.getVariable();
+ if (var.equals(curVar)) {
+ getFieldNameFromSubTree(optFuncExpr, subTree, assignOrUnnestIndex, 0, recordType, funcVarIndex,
+ childFuncExpr);
+ }
+ }
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodAnalysisContext.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodAnalysisContext.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodAnalysisContext.java
new file mode 100644
index 0000000..cc24912
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodAnalysisContext.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.asterix.optimizer.rules.am;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.asterix.metadata.entities.Dataset;
+import edu.uci.ics.asterix.metadata.entities.Index;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+
+/**
+ * Context for analyzing the applicability of a single access method.
+ */
+public class AccessMethodAnalysisContext {
+
+ public List<IOptimizableFuncExpr> matchedFuncExprs = new ArrayList<IOptimizableFuncExpr>();
+
+ // Contains candidate indexes and a list of (integer,integer) tuples that index into matchedFuncExprs and matched variable inside this expr.
+ // We are mapping from candidate indexes to a list of function expressions
+ // that match one of the index's expressions.
+ public Map<Index, List<Pair<Integer, Integer>>> indexExprsAndVars = new TreeMap<Index, List<Pair<Integer, Integer>>>();
+
+ // Maps from index to the dataset it is indexing.
+ public Map<Index, Dataset> indexDatasetMap = new TreeMap<Index, Dataset>();
+
+ // Maps from an index to the number of matched fields in the query plan (for performing prefix search)
+ public Map<Index, Integer> indexNumMatchedKeys = new TreeMap<Index, Integer>();
+
+ // variables for resetting null placeholder for left-outer-join
+ private Mutable<ILogicalOperator> lojGroupbyOpRef = null;
+ private ScalarFunctionCallExpression lojIsNullFuncInGroupBy = null;
+
+ public void addIndexExpr(Dataset dataset, Index index, Integer exprIndex, Integer varIndex) {
+ List<Pair<Integer, Integer>> exprs = indexExprsAndVars.get(index);
+ if (exprs == null) {
+ exprs = new ArrayList<Pair<Integer, Integer>>();
+ indexExprsAndVars.put(index, exprs);
+ }
+ exprs.add(new Pair<Integer, Integer>(exprIndex, varIndex));
+ indexDatasetMap.put(index, dataset);
+ }
+
+ public List<Pair<Integer, Integer>> getIndexExprs(Index index) {
+ return indexExprsAndVars.get(index);
+ }
+
+ public void setLOJGroupbyOpRef(Mutable<ILogicalOperator> opRef) {
+ lojGroupbyOpRef = opRef;
+ }
+
+ public Mutable<ILogicalOperator> getLOJGroupbyOpRef() {
+ return lojGroupbyOpRef;
+ }
+
+ public void setLOJIsNullFuncInGroupBy(ScalarFunctionCallExpression isNullFunc) {
+ lojIsNullFuncInGroupBy = isNullFunc;
+ }
+
+ public ScalarFunctionCallExpression getLOJIsNullFuncInGroupBy() {
+ return lojIsNullFuncInGroupBy;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodJobGenParams.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodJobGenParams.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodJobGenParams.java
new file mode 100644
index 0000000..31943e4
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodJobGenParams.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.asterix.optimizer.rules.am;
+
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.common.config.DatasetConfig.IndexType;
+import edu.uci.ics.asterix.om.base.AInt32;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+
+/**
+ * Helper class for reading and writing job-gen parameters for access methods to
+ * and from a list of function arguments, typically of an unnest-map.
+ */
+public class AccessMethodJobGenParams {
+ protected String indexName;
+ protected IndexType indexType;
+ protected String dataverseName;
+ protected String datasetName;
+ protected boolean retainInput;
+ protected boolean retainNull;
+ protected boolean requiresBroadcast;
+ protected boolean isPrimaryIndex;
+
+ private final int NUM_PARAMS = 7;
+
+ public AccessMethodJobGenParams() {
+ }
+
+ public AccessMethodJobGenParams(String indexName, IndexType indexType, String dataverseName, String datasetName,
+ boolean retainInput, boolean retainNull, boolean requiresBroadcast) {
+ this.indexName = indexName;
+ this.indexType = indexType;
+ this.dataverseName = dataverseName;
+ this.datasetName = datasetName;
+ this.retainInput = retainInput;
+ this.retainNull = retainNull;
+ this.requiresBroadcast = requiresBroadcast;
+ this.isPrimaryIndex = datasetName.equals(indexName);
+ }
+
+ public void writeToFuncArgs(List<Mutable<ILogicalExpression>> funcArgs) {
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createStringConstant(indexName)));
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createInt32Constant(indexType.ordinal())));
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createStringConstant(dataverseName)));
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createStringConstant(datasetName)));
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createBooleanConstant(retainInput)));
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createBooleanConstant(retainNull)));
+ funcArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils.createBooleanConstant(requiresBroadcast)));
+ }
+
+ public void readFromFuncArgs(List<Mutable<ILogicalExpression>> funcArgs) {
+ indexName = AccessMethodUtils.getStringConstant(funcArgs.get(0));
+ indexType = IndexType.values()[AccessMethodUtils.getInt32Constant(funcArgs.get(1))];
+ dataverseName = AccessMethodUtils.getStringConstant(funcArgs.get(2));
+ datasetName = AccessMethodUtils.getStringConstant(funcArgs.get(3));
+ retainInput = AccessMethodUtils.getBooleanConstant(funcArgs.get(4));
+ retainNull = AccessMethodUtils.getBooleanConstant(funcArgs.get(5));
+ requiresBroadcast = AccessMethodUtils.getBooleanConstant(funcArgs.get(6));
+ isPrimaryIndex = datasetName.equals(indexName);
+ }
+
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public IndexType getIndexType() {
+ return indexType;
+ }
+
+ public String getDataverseName() {
+ return dataverseName;
+ }
+
+ public String getDatasetName() {
+ return datasetName;
+ }
+
+ public boolean getRetainInput() {
+ return retainInput;
+ }
+
+ public boolean getRetainNull() {
+ return retainNull;
+ }
+
+ public boolean getRequiresBroadcast() {
+ return requiresBroadcast;
+ }
+
+ protected void writeVarList(List<LogicalVariable> varList, List<Mutable<ILogicalExpression>> funcArgs) {
+ Mutable<ILogicalExpression> numKeysRef = new MutableObject<ILogicalExpression>(new ConstantExpression(
+ new AsterixConstantValue(new AInt32(varList.size()))));
+ funcArgs.add(numKeysRef);
+ for (LogicalVariable keyVar : varList) {
+ Mutable<ILogicalExpression> keyVarRef = new MutableObject<ILogicalExpression>(
+ new VariableReferenceExpression(keyVar));
+ funcArgs.add(keyVarRef);
+ }
+ }
+
+ protected int readVarList(List<Mutable<ILogicalExpression>> funcArgs, int index, List<LogicalVariable> varList) {
+ int numLowKeys = AccessMethodUtils.getInt32Constant(funcArgs.get(index));
+ if (numLowKeys > 0) {
+ for (int i = 0; i < numLowKeys; i++) {
+ LogicalVariable var = ((VariableReferenceExpression) funcArgs.get(index + 1 + i).getValue())
+ .getVariableReference();
+ varList.add(var);
+ }
+ }
+ return index + numLowKeys + 1;
+ }
+
+ protected int getNumParams() {
+ return NUM_PARAMS;
+ }
+
+ public boolean isPrimaryIndex() {
+ return isPrimaryIndex;
+ }
+}