asterixdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ima...@apache.org
Subject [33/51] [partial] incubator-asterixdb git commit: Change folder structure for Java repackage
Date Tue, 25 Aug 2015 16:44:21 GMT
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
new file mode 100644
index 0000000..be1653d
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
@@ -0,0 +1,264 @@
+/*
+ * 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.io.DataInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.asterix.common.config.GlobalConfig;
+import edu.uci.ics.asterix.dataflow.data.common.AqlExpressionTypeComputer;
+import edu.uci.ics.asterix.dataflow.data.common.AqlNullableTypeComputer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.AqlNullWriterFactory;
+import edu.uci.ics.asterix.formats.nontagged.AqlBinaryBooleanInspectorImpl;
+import edu.uci.ics.asterix.formats.nontagged.AqlBinaryComparatorFactoryProvider;
+import edu.uci.ics.asterix.formats.nontagged.AqlBinaryHashFunctionFactoryProvider;
+import edu.uci.ics.asterix.formats.nontagged.AqlBinaryHashFunctionFamilyProvider;
+import edu.uci.ics.asterix.formats.nontagged.AqlBinaryIntegerInspector;
+import edu.uci.ics.asterix.formats.nontagged.AqlPrinterFactoryProvider;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.formats.nontagged.AqlTypeTraitProvider;
+import edu.uci.ics.asterix.jobgen.AqlLogicalExpressionJobGen;
+import edu.uci.ics.asterix.om.base.AString;
+import edu.uci.ics.asterix.om.base.IAObject;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.typecomputer.base.TypeComputerUtilities;
+import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
+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.expressions.AbstractLogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
+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.LogicalExpressionJobGenToExpressionRuntimeProviderAdapter;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.StatefulFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IOperatorSchema;
+import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionReferenceTransform;
+import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionVisitor;
+import edu.uci.ics.hyracks.algebricks.core.jobgen.impl.JobGenContext;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+import edu.uci.ics.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import edu.uci.ics.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.data.std.api.IPointable;
+import edu.uci.ics.hyracks.data.std.primitive.VoidPointable;
+import edu.uci.ics.hyracks.dataflow.common.comm.util.ByteBufferInputStream;
+
+public class ConstantFoldingRule implements IAlgebraicRewriteRule {
+
+    private final ConstantFoldingVisitor cfv = new ConstantFoldingVisitor();
+
+    /** Throws exceptions in substituiteProducedVariable, setVarType, and one getVarType method. */
+    private static final IVariableTypeEnvironment _emptyTypeEnv = new IVariableTypeEnvironment() {
+
+        @Override
+        public boolean substituteProducedVariable(LogicalVariable v1, LogicalVariable v2) throws AlgebricksException {
+            throw new IllegalStateException();
+        }
+
+        @Override
+        public void setVarType(LogicalVariable var, Object type) {
+            throw new IllegalStateException();
+        }
+
+        @Override
+        public Object getVarType(LogicalVariable var, List<LogicalVariable> nonNullVariables,
+                List<List<LogicalVariable>> correlatedNullableVariableLists) throws AlgebricksException {
+            throw new IllegalStateException();
+        }
+
+        @Override
+        public Object getVarType(LogicalVariable var) throws AlgebricksException {
+            throw new IllegalStateException();
+        }
+
+        @Override
+        public Object getType(ILogicalExpression expr) throws AlgebricksException {
+            return AqlExpressionTypeComputer.INSTANCE.getType(expr, null, this);
+        }
+    };
+
+    private static final JobGenContext _jobGenCtx = new JobGenContext(null, null, null,
+            AqlSerializerDeserializerProvider.INSTANCE, AqlBinaryHashFunctionFactoryProvider.INSTANCE,
+            AqlBinaryHashFunctionFamilyProvider.INSTANCE, AqlBinaryComparatorFactoryProvider.INSTANCE,
+            AqlTypeTraitProvider.INSTANCE, AqlBinaryBooleanInspectorImpl.FACTORY, AqlBinaryIntegerInspector.FACTORY,
+            AqlPrinterFactoryProvider.INSTANCE, AqlNullWriterFactory.INSTANCE, null,
+            new LogicalExpressionJobGenToExpressionRuntimeProviderAdapter(AqlLogicalExpressionJobGen.INSTANCE),
+            AqlExpressionTypeComputer.INSTANCE, AqlNullableTypeComputer.INSTANCE, null, null, null, null,
+            GlobalConfig.DEFAULT_FRAME_SIZE, null);
+
+    private static final IOperatorSchema[] _emptySchemas = new IOperatorSchema[] {};
+
+    @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;
+        }
+        return op.acceptExpressionTransform(cfv);
+    }
+
+    private class ConstantFoldingVisitor implements ILogicalExpressionVisitor<Pair<Boolean, ILogicalExpression>, Void>,
+            ILogicalExpressionReferenceTransform {
+
+        private final IPointable p = VoidPointable.FACTORY.createPointable();
+        private final ByteBufferInputStream bbis = new ByteBufferInputStream();
+        private final DataInputStream dis = new DataInputStream(bbis);
+
+        @Override
+        public boolean transform(Mutable<ILogicalExpression> exprRef) throws AlgebricksException {
+            AbstractLogicalExpression expr = (AbstractLogicalExpression) exprRef.getValue();
+            Pair<Boolean, ILogicalExpression> p = expr.accept(this, null);
+            if (p.first) {
+                exprRef.setValue(p.second);
+            }
+            return p.first;
+        }
+
+        @Override
+        public Pair<Boolean, ILogicalExpression> visitConstantExpression(ConstantExpression expr, Void arg)
+                throws AlgebricksException {
+            return new Pair<Boolean, ILogicalExpression>(false, expr);
+        }
+
+        @Override
+        public Pair<Boolean, ILogicalExpression> visitVariableReferenceExpression(VariableReferenceExpression expr,
+                Void arg) throws AlgebricksException {
+            return new Pair<Boolean, ILogicalExpression>(false, expr);
+        }
+
+        @Override
+        public Pair<Boolean, ILogicalExpression> visitScalarFunctionCallExpression(ScalarFunctionCallExpression expr,
+                Void arg) throws AlgebricksException {
+            boolean changed = changeRec(expr, arg);
+            if (!checkArgs(expr) || !expr.isFunctional()) {
+                return new Pair<Boolean, ILogicalExpression>(changed, expr);
+            }
+            //Current ARecord SerDe assumes a closed record, so we do not constant fold open record constructors
+            if (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR)
+                    || expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.CAST_RECORD)) {
+                return new Pair<Boolean, ILogicalExpression>(false, null);
+            }
+            //Current List SerDe assumes a strongly typed list, so we do not constant fold the list constructors if they are not strongly typed
+            if (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR)
+                    || expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.ORDERED_LIST_CONSTRUCTOR)) {
+                AbstractCollectionType listType = (AbstractCollectionType) TypeComputerUtilities.getRequiredType(expr);
+                if (listType != null
+                        && (listType.getItemType().getTypeTag() == ATypeTag.ANY || listType.getItemType() instanceof AbstractCollectionType)) {
+                    //case1: listType == null,  could be a nested list inside a list<ANY>
+                    //case2: itemType = ANY
+                    //case3: itemType = a nested list
+                    return new Pair<Boolean, ILogicalExpression>(false, null);
+                }
+            }
+            if (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.FIELD_ACCESS_BY_NAME)) {
+                ARecordType rt = (ARecordType) _emptyTypeEnv.getType(expr.getArguments().get(0).getValue());
+                String str = ((AString) ((AsterixConstantValue) ((ConstantExpression) expr.getArguments().get(1)
+                        .getValue()).getValue()).getObject()).getStringValue();
+                int k;
+                try {
+                    k = rt.findFieldPosition(str);
+                } catch (IOException e) {
+                    throw new AlgebricksException(e);
+                }
+                if (k >= 0) {
+                    // wait for the ByNameToByIndex rule to apply
+                    return new Pair<Boolean, ILogicalExpression>(changed, expr);
+                }
+            }
+            IScalarEvaluatorFactory fact = _jobGenCtx.getExpressionRuntimeProvider().createEvaluatorFactory(expr,
+                    _emptyTypeEnv, _emptySchemas, _jobGenCtx);
+            IScalarEvaluator eval = fact.createScalarEvaluator(null);
+            eval.evaluate(null, p);
+            Object t = _emptyTypeEnv.getType(expr);
+
+            @SuppressWarnings("rawtypes")
+            ISerializerDeserializer serde = _jobGenCtx.getSerializerDeserializerProvider().getSerializerDeserializer(t);
+            bbis.setByteBuffer(ByteBuffer.wrap(p.getByteArray(), p.getStartOffset(), p.getLength()), 0);
+            IAObject o;
+            try {
+                o = (IAObject) serde.deserialize(dis);
+            } catch (HyracksDataException e) {
+                throw new AlgebricksException(e);
+            }
+            return new Pair<Boolean, ILogicalExpression>(true, new ConstantExpression(new AsterixConstantValue(o)));
+        }
+
+        @Override
+        public Pair<Boolean, ILogicalExpression> visitAggregateFunctionCallExpression(
+                AggregateFunctionCallExpression expr, Void arg) throws AlgebricksException {
+            boolean changed = changeRec(expr, arg);
+            return new Pair<Boolean, ILogicalExpression>(changed, expr);
+        }
+
+        @Override
+        public Pair<Boolean, ILogicalExpression> visitStatefulFunctionCallExpression(
+                StatefulFunctionCallExpression expr, Void arg) throws AlgebricksException {
+            boolean changed = changeRec(expr, arg);
+            return new Pair<Boolean, ILogicalExpression>(changed, expr);
+        }
+
+        @Override
+        public Pair<Boolean, ILogicalExpression> visitUnnestingFunctionCallExpression(
+                UnnestingFunctionCallExpression expr, Void arg) throws AlgebricksException {
+            boolean changed = changeRec(expr, arg);
+            return new Pair<Boolean, ILogicalExpression>(changed, expr);
+        }
+
+        private boolean changeRec(AbstractFunctionCallExpression expr, Void arg) throws AlgebricksException {
+            boolean changed = false;
+            for (Mutable<ILogicalExpression> r : expr.getArguments()) {
+                Pair<Boolean, ILogicalExpression> p2 = r.getValue().accept(this, arg);
+                if (p2.first) {
+                    r.setValue(p2.second);
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        private boolean checkArgs(AbstractFunctionCallExpression expr) throws AlgebricksException {
+            for (Mutable<ILogicalExpression> r : expr.getArguments()) {
+                if (r.getValue().getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CountVarToCountOneRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CountVarToCountOneRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CountVarToCountOneRule.java
new file mode 100644
index 0000000..218cd4b
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CountVarToCountOneRule.java
@@ -0,0 +1,86 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.asterix.om.base.AInt64;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.ILogicalPlan;
+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.expressions.AbstractFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class CountVarToCountOneRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+        return false;
+    }
+
+    // It is only for a group-by having just one aggregate which is a count.
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
+        if (op1.getOperatorTag() != LogicalOperatorTag.GROUP) {
+            return false;
+        }
+        GroupByOperator g = (GroupByOperator) op1;
+        if (g.getNestedPlans().size() != 1) {
+            return false;
+        }
+        ILogicalPlan p = g.getNestedPlans().get(0);
+        if (p.getRoots().size() != 1) {
+            return false;
+        }
+        AbstractLogicalOperator op2 = (AbstractLogicalOperator) p.getRoots().get(0).getValue();
+        if (op2.getOperatorTag() != LogicalOperatorTag.AGGREGATE) {
+            return false;
+        }
+        AggregateOperator agg = (AggregateOperator) op2;
+        if (agg.getExpressions().size() != 1) {
+            return false;
+        }
+        ILogicalExpression exp2 = agg.getExpressions().get(0).getValue();
+        if (exp2.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return false;
+        }
+        AbstractFunctionCallExpression fun = (AbstractFunctionCallExpression) exp2;
+        if (fun.getFunctionIdentifier() != AsterixBuiltinFunctions.COUNT) {
+            return false;
+        }
+        ILogicalExpression exp3 = fun.getArguments().get(0).getValue();
+        if (exp3.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
+            return false;
+        }
+        if (((AbstractLogicalOperator) agg.getInputs().get(0).getValue()).getOperatorTag() != LogicalOperatorTag.NESTEDTUPLESOURCE) {
+            return false;
+        }
+        fun.getArguments().get(0).setValue(new ConstantExpression(new AsterixConstantValue(new AInt64(1L))));
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
new file mode 100644
index 0000000..0fb205d
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2014 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.HashSet;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.om.base.AOrderedList;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.AOrderedListType;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.IndexedNLJoinExpressionAnnotation;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+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.functions.IFunctionInfo;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class DisjunctivePredicateToJoinRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+
+        SelectOperator select;
+        if ((select = asSelectOperator(opRef)) == null) {
+            return false;
+        }
+
+        AbstractFunctionCallExpression condEx;
+        if ((condEx = asFunctionCallExpression(select.getCondition(), AlgebricksBuiltinFunctions.OR)) == null) {
+            return false;
+        }
+
+        List<Mutable<ILogicalExpression>> args = condEx.getArguments();
+
+        VariableReferenceExpression varEx = null;
+        IAType valType = null;
+        HashSet<AsterixConstantValue> values = new HashSet<AsterixConstantValue>();
+
+        for (Mutable<ILogicalExpression> arg : args) {
+            AbstractFunctionCallExpression fctCall;
+            if ((fctCall = asFunctionCallExpression(arg, AlgebricksBuiltinFunctions.EQ)) == null) {
+                return false;
+            }
+
+            boolean haveConst = false;
+            boolean haveVar = false;
+            List<Mutable<ILogicalExpression>> fctArgs = fctCall.getArguments();
+            for (Mutable<ILogicalExpression> fctArg : fctArgs) {
+                final ILogicalExpression argExpr = fctArg.getValue();
+                switch (argExpr.getExpressionTag()) {
+                    case CONSTANT:
+                        haveConst = true;
+                        AsterixConstantValue value = (AsterixConstantValue) ((ConstantExpression) argExpr).getValue();
+                        if (valType == null) {
+                            valType = value.getObject().getType();
+                        } else if (!isCompatible(valType, value.getObject().getType())) {
+                            return false;
+                        }
+                        values.add(value);
+                        break;
+                    case VARIABLE:
+                        haveVar = true;
+                        final VariableReferenceExpression varArg = (VariableReferenceExpression) argExpr;
+                        if (varEx == null) {
+                            varEx = varArg;
+                        } else if (!varEx.getVariableReference().equals(varArg.getVariableReference())) {
+                            return false;
+                        }
+                        break;
+                    default:
+                        return false;
+                }
+            }
+            if (!(haveVar && haveConst)) {
+                return false;
+            }
+        }
+
+        AOrderedList list = new AOrderedList(new AOrderedListType(valType, "orderedlist"));
+        for (AsterixConstantValue value : values) {
+            list.add(value.getObject());
+        }
+
+        EmptyTupleSourceOperator ets = new EmptyTupleSourceOperator();
+        context.computeAndSetTypeEnvironmentForOperator(ets);
+
+        ILogicalExpression cExp = new ConstantExpression(new AsterixConstantValue(list));
+        Mutable<ILogicalExpression> mutCExp = new MutableObject<ILogicalExpression>(cExp);
+        IFunctionInfo scanFctInfo = AsterixBuiltinFunctions
+                .getAsterixFunctionInfo(AsterixBuiltinFunctions.SCAN_COLLECTION);
+        UnnestingFunctionCallExpression scanExp = new UnnestingFunctionCallExpression(scanFctInfo, mutCExp);
+        LogicalVariable scanVar = context.newVar();
+        UnnestOperator unn = new UnnestOperator(scanVar, new MutableObject<ILogicalExpression>(scanExp));
+        unn.getInputs().add(new MutableObject<ILogicalOperator>(ets));
+        context.computeAndSetTypeEnvironmentForOperator(unn);
+
+        IFunctionInfo eqFctInfo = AsterixBuiltinFunctions.getAsterixFunctionInfo(AlgebricksBuiltinFunctions.EQ);
+        AbstractFunctionCallExpression eqExp = new ScalarFunctionCallExpression(eqFctInfo);
+        eqExp.getArguments().add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(scanVar)));
+        eqExp.getArguments().add(new MutableObject<ILogicalExpression>(varEx.cloneExpression()));
+        eqExp.getAnnotations().put(IndexedNLJoinExpressionAnnotation.INSTANCE,
+                IndexedNLJoinExpressionAnnotation.INSTANCE);
+
+        InnerJoinOperator jOp = new InnerJoinOperator(new MutableObject<ILogicalExpression>(eqExp));
+        jOp.getInputs().add(new MutableObject<ILogicalOperator>(unn));
+        jOp.getInputs().add(select.getInputs().get(0));
+
+        opRef.setValue(jOp);
+        context.computeAndSetTypeEnvironmentForOperator(jOp);
+
+        return true;
+    }
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+        return false;
+    }
+
+    /**
+     * This checks the compatibility the types of the constants to ensure that the comparison behaves as expected
+     * when joining. Right now this compatibility is defined as type equality, but it could we relaxed.
+     * Once type promotion works correctly in all parts of the system, this check should not be needed anymore.
+     * (see https://code.google.com/p/asterixdb/issues/detail?id=716)
+     * 
+     * @param t1
+     *            one type
+     * @param t2
+     *            another type
+     * @return true, if types are equal
+     */
+    private static boolean isCompatible(IAType t1, IAType t2) {
+        return t1.equals(t2);
+    }
+
+    // some helpers
+
+    private static SelectOperator asSelectOperator(ILogicalOperator op) {
+        return op.getOperatorTag() == LogicalOperatorTag.SELECT ? (SelectOperator) op : null;
+    }
+
+    private static SelectOperator asSelectOperator(Mutable<ILogicalOperator> op) {
+        return asSelectOperator(op.getValue());
+    }
+
+    private static AbstractFunctionCallExpression asFunctionCallExpression(ILogicalExpression ex, FunctionIdentifier fi) {
+        AbstractFunctionCallExpression fctCall = (ex.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL ? (AbstractFunctionCallExpression) ex
+                : null);
+        if (fctCall != null && (fi == null || fctCall.getFunctionIdentifier().equals(fi)))
+            return fctCall;
+        return null;
+    }
+
+    private static AbstractFunctionCallExpression asFunctionCallExpression(Mutable<ILogicalExpression> ex,
+            FunctionIdentifier fi) {
+        return asFunctionCallExpression(ex.getValue(), fi);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractDistinctByExpressionsRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractDistinctByExpressionsRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractDistinctByExpressionsRule.java
new file mode 100644
index 0000000..7c36cb7
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractDistinctByExpressionsRule.java
@@ -0,0 +1,80 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
+import edu.uci.ics.hyracks.algebricks.rewriter.rules.AbstractExtractExprRule;
+
+/**
+ * Needed only bc. current Hyracks operators require keys to be fields.
+ */
+public class ExtractDistinctByExpressionsRule extends AbstractExtractExprRule {
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+        return false;
+    }
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
+        if (op1.getOperatorTag() != LogicalOperatorTag.DISTINCT) {
+            return false;
+        }
+
+        if (context.checkIfInDontApplySet(this, op1)) {
+            return false;
+        }
+        context.addToDontApplySet(this, op1);
+        DistinctOperator d = (DistinctOperator) op1;
+        boolean changed = false;
+        Mutable<ILogicalOperator> opRef2 = d.getInputs().get(0);
+        List<Mutable<ILogicalExpression>> newExprList = new ArrayList<Mutable<ILogicalExpression>>();
+        for (Mutable<ILogicalExpression> expr : d.getExpressions()) {
+            LogicalExpressionTag tag = expr.getValue().getExpressionTag();
+            if (tag == LogicalExpressionTag.VARIABLE || tag == LogicalExpressionTag.CONSTANT) {
+                newExprList.add(expr);
+                continue;
+            }
+            LogicalVariable v = extractExprIntoAssignOpRef(expr.getValue(), opRef2, context);
+            ILogicalExpression newExpr = new VariableReferenceExpression(v);
+            newExprList.add(new MutableObject<ILogicalExpression>(newExpr));
+            changed = true;
+        }
+        if (changed) {
+            d.getExpressions().clear();
+            d.getExpressions().addAll(newExprList);
+            context.computeAndSetTypeEnvironmentForOperator(d);
+        }
+        return changed;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractOrderExpressionsRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractOrderExpressionsRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractOrderExpressionsRule.java
new file mode 100644
index 0000000..b53c0cc
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ExtractOrderExpressionsRule.java
@@ -0,0 +1,80 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.asterix.optimizer.base.AnalysisUtil;
+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.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+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.rewriter.rules.AbstractExtractExprRule;
+
+public class ExtractOrderExpressionsRule extends AbstractExtractExprRule {
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+        return false;
+    }
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+
+        AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
+        if (op1.getOperatorTag() != LogicalOperatorTag.ORDER) {
+            return false;
+        }
+
+        if (context.checkIfInDontApplySet(this, op1)) {
+            return false;
+        }
+        context.addToDontApplySet(this, op1);
+        OrderOperator oo = (OrderOperator) op1;
+
+        if (!orderHasComplexExpr(oo)) {
+            return false;
+        }
+        Mutable<ILogicalOperator> opRef2 = oo.getInputs().get(0);
+        for (Pair<IOrder, Mutable<ILogicalExpression>> orderPair : oo.getOrderExpressions()) {
+            ILogicalExpression expr = orderPair.second.getValue();
+            if (expr.getExpressionTag() != LogicalExpressionTag.VARIABLE && !AnalysisUtil.isAccessToFieldRecord(expr)) {
+                LogicalVariable v = extractExprIntoAssignOpRef(expr, opRef2, context);
+                orderPair.second.setValue(new VariableReferenceExpression(v));
+            }
+        }
+        context.computeAndSetTypeEnvironmentForOperator(oo);
+        return true;
+    }
+
+    private boolean orderHasComplexExpr(OrderOperator oo) {
+        for (Pair<IOrder, Mutable<ILogicalExpression>> orderPair : oo.getOrderExpressions()) {
+            if (orderPair.second.getValue().getExpressionTag() != LogicalExpressionTag.VARIABLE) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FeedScanCollectionToUnnest.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FeedScanCollectionToUnnest.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FeedScanCollectionToUnnest.java
new file mode 100644
index 0000000..fa7c7f4
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FeedScanCollectionToUnnest.java
@@ -0,0 +1,135 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.aql.util.FunctionUtils;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.AbstractFunctionCallExpression.FunctionKind;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractAssignOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class FeedScanCollectionToUnnest implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+        return false;
+    }
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+        if (context.checkIfInDontApplySet(this, op)) {
+            return false;
+        }
+        if (op.getOperatorTag() != LogicalOperatorTag.UNNEST) {
+            context.addToDontApplySet(this, op);
+            return false;
+        }
+        UnnestOperator unnest = (UnnestOperator) op;
+        ILogicalExpression unnestExpr = unnest.getExpressionRef().getValue();
+        if (needsScanCollection(unnestExpr, op)) {
+            ILogicalExpression newExpr = new UnnestingFunctionCallExpression(
+                    FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.SCAN_COLLECTION),
+                    new MutableObject<ILogicalExpression>(unnestExpr));
+            unnest.getExpressionRef().setValue(newExpr);
+            context.addToDontApplySet(this, op);
+            return true;
+        }
+        context.addToDontApplySet(this, op);
+        return false;
+    }
+
+    private ILogicalExpression findVarOriginExpression(LogicalVariable v, ILogicalOperator op)
+            throws AlgebricksException {
+        boolean searchInputs = false;
+        if (!(op instanceof AbstractAssignOperator)) {
+            searchInputs = true;
+        } else {
+            AbstractAssignOperator aao = (AbstractAssignOperator) op;
+            List<LogicalVariable> producedVars = new ArrayList<>();
+            VariableUtilities.getProducedVariables(op, producedVars);
+            int exprIndex = producedVars.indexOf(v);
+            if (exprIndex == -1) {
+                searchInputs = true;
+            } else {
+                ILogicalExpression originalCandidate = aao.getExpressions().get(exprIndex).getValue();
+                if (originalCandidate.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+                    searchInputs = true;
+                } else {
+                    return originalCandidate;
+                }
+            }
+        }
+
+        if (searchInputs) {
+            for (Mutable<ILogicalOperator> childOp : op.getInputs()) {
+                ILogicalExpression ret = findVarOriginExpression(v, childOp.getValue());
+                if (ret != null) {
+                    return ret;
+                }
+            }
+        }
+
+        throw new IllegalStateException("Unable to find the original expression that produced variable " + v);
+    }
+
+    private boolean needsScanCollection(ILogicalExpression unnestExpr, ILogicalOperator op) throws AlgebricksException {
+        switch (unnestExpr.getExpressionTag()) {
+            case VARIABLE: {
+                LogicalVariable v = ((VariableReferenceExpression) unnestExpr).getVariableReference();
+                ILogicalExpression originalExpr = findVarOriginExpression(v, op);
+                if (originalExpr.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+                    return false;
+                } else {
+                    return !isUnnestingFunction(originalExpr);
+                }
+            }
+            case FUNCTION_CALL: {
+                return !isUnnestingFunction(unnestExpr);
+            }
+            default: {
+                return false;
+            }
+        }
+    }
+
+    private boolean isUnnestingFunction(ILogicalExpression expr) {
+        if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+            AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expr;
+            return fce.getKind() == FunctionKind.UNNEST;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyEqRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyEqRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyEqRule.java
new file mode 100644
index 0000000..3a06168
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyEqRule.java
@@ -0,0 +1,124 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.aql.util.FunctionUtils;
+import edu.uci.ics.asterix.metadata.declared.AqlMetadataProvider;
+import edu.uci.ics.asterix.om.base.IAObject;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.optimizer.base.FuzzyUtils;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.expressions.AbstractFunctionCallExpression;
+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.ScalarFunctionCallExpression;
+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.AbstractBinaryJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class FuzzyEqRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+
+        // current operator is INNERJOIN or LEFTOUTERJOIN or SELECT
+        Mutable<ILogicalExpression> expRef;
+        if (op.getOperatorTag() == LogicalOperatorTag.INNERJOIN
+                || op.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
+            AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) op;
+            expRef = joinOp.getCondition();
+        } else if (op.getOperatorTag() == LogicalOperatorTag.SELECT) {
+            SelectOperator selectOp = (SelectOperator) op;
+            expRef = selectOp.getCondition();
+        } else {
+            return false;
+        }
+
+        AqlMetadataProvider metadataProvider = ((AqlMetadataProvider) context.getMetadataProvider());
+
+        IVariableTypeEnvironment env = context.getOutputTypeEnvironment(op);
+        if (expandFuzzyEq(expRef, context, env, metadataProvider)) {
+            context.computeAndSetTypeEnvironmentForOperator(op);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean expandFuzzyEq(Mutable<ILogicalExpression> expRef, IOptimizationContext context,
+            IVariableTypeEnvironment env, AqlMetadataProvider metadataProvider) throws AlgebricksException {
+        ILogicalExpression exp = expRef.getValue();
+
+        if (exp.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return false;
+        }
+
+        boolean expanded = false;
+        AbstractFunctionCallExpression funcExp = (AbstractFunctionCallExpression) exp;
+        FunctionIdentifier fi = funcExp.getFunctionIdentifier();
+        if (fi.equals(AsterixBuiltinFunctions.FUZZY_EQ)) {
+            List<Mutable<ILogicalExpression>> inputExps = funcExp.getArguments();
+
+            String simFuncName = FuzzyUtils.getSimFunction(metadataProvider);
+            ArrayList<Mutable<ILogicalExpression>> similarityArgs = new ArrayList<Mutable<ILogicalExpression>>();
+            for (int i = 0; i < inputExps.size(); ++i) {
+                Mutable<ILogicalExpression> inputExpRef = inputExps.get(i);
+                similarityArgs.add(inputExpRef);
+            }
+
+            FunctionIdentifier simFunctionIdentifier = FuzzyUtils.getFunctionIdentifier(simFuncName);
+            ScalarFunctionCallExpression similarityExp = new ScalarFunctionCallExpression(
+                    FunctionUtils.getFunctionInfo(simFunctionIdentifier), similarityArgs);
+            // Add annotations from the original fuzzy-eq function.
+            similarityExp.getAnnotations().putAll(funcExp.getAnnotations());
+            ArrayList<Mutable<ILogicalExpression>> cmpArgs = new ArrayList<Mutable<ILogicalExpression>>();
+            cmpArgs.add(new MutableObject<ILogicalExpression>(similarityExp));
+            IAObject simThreshold = FuzzyUtils.getSimThreshold(metadataProvider, simFuncName);
+            cmpArgs.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(
+                    simThreshold))));
+            ScalarFunctionCallExpression cmpExpr = FuzzyUtils.getComparisonExpr(simFuncName, cmpArgs);
+            expRef.setValue(cmpExpr);
+            return true;
+        } else if (fi.equals(AlgebricksBuiltinFunctions.AND) || fi.equals(AlgebricksBuiltinFunctions.OR)) {
+            for (int i = 0; i < 2; i++) {
+                if (expandFuzzyEq(funcExp.getArguments().get(i), context, env, metadataProvider)) {
+                    expanded = true;
+                }
+            }
+        }
+        return expanded;
+    }
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java
new file mode 100644
index 0000000..9bcfafa
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FuzzyJoinRule.java
@@ -0,0 +1,404 @@
+/*
+ * 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.io.StringReader;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.algebra.base.LogicalOperatorDeepCopyVisitor;
+import edu.uci.ics.asterix.aql.base.Clause;
+import edu.uci.ics.asterix.aql.expression.Identifier;
+import edu.uci.ics.asterix.aqlplus.parser.AQLPlusParser;
+import edu.uci.ics.asterix.aqlplus.parser.ParseException;
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.metadata.declared.AqlMetadataProvider;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.om.types.TypeHelper;
+import edu.uci.ics.asterix.optimizer.base.FuzzyUtils;
+import edu.uci.ics.asterix.translator.AqlPlusExpressionToPlanTranslator;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.Counter;
+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.ILogicalPlan;
+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.IndexedNLJoinExpressionAnnotation;
+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.AbstractBinaryJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import edu.uci.ics.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class FuzzyJoinRule implements IAlgebraicRewriteRule {
+
+    private static HashSet<FunctionIdentifier> simFuncs = new HashSet<FunctionIdentifier>();
+    static {
+        simFuncs.add(AsterixBuiltinFunctions.SIMILARITY_JACCARD_CHECK);
+    }
+
+    private static final String AQLPLUS = ""
+            //
+            // -- - Stage 3 - --
+            //
+            + "((#RIGHT), "
+            + "  (join((#LEFT), "
+            //
+            // -- -- - Stage 2 - --
+            //
+            + "    ("
+            + "    join( "
+            + "      ( "
+            + "      #LEFT_1 "
+            + "      let $tokensUnrankedLeft := %s($$LEFT_1) "
+            + "      let $lenLeft := len($tokensUnrankedLeft) "
+            + "      let $tokensLeft := "
+            + "        for $token in $tokensUnrankedLeft "
+            + "        for $tokenRanked at $i in "
+            //
+            // -- -- -- - Stage 1 - --
+            //
+            // + "          #LEFT_2 "
+            // + "          let $id := $$LEFTPK_2 "
+            // + "          for $token in %s($$LEFT_2) "
+            + "          #RIGHT_2 "
+            + "          let $id := $$RIGHTPK_2 "
+            + "          for $token in %s($$RIGHT_2) "
+            + "          /*+ hash */ "
+            + "          group by $tokenGroupped := $token with $id "
+            + "          /*+ inmem 34 198608 */ "
+            + "          order by count($id), $tokenGroupped "
+            + "          return $tokenGroupped "
+            //
+            // -- -- -- -
+            //
+            + "        where $token = /*+ bcast */ $tokenRanked "
+            + "        order by $i "
+            + "        return $i "
+            + "      for $prefixTokenLeft in subset-collection($tokensLeft, 0, prefix-len-%s(len($tokensLeft), %ff)) "
+            + "      ),( "
+            + "      #RIGHT_1 "
+            + "      let $tokensUnrankedRight := %s($$RIGHT_1) "
+            + "      let $lenRight := len($tokensUnrankedRight) "
+            + "      let $tokensRight := "
+            + "        for $token in $tokensUnrankedRight "
+            + "        for $tokenRanked at $i in "
+            //
+            // -- -- -- - Stage 1 - --
+            //
+            // + "          #LEFT_3 "
+            // + "          let $id := $$LEFTPK_3 "
+            // + "          for $token in %s($$LEFT_3) "
+            + "          #RIGHT_3 "
+            + "          let $id := $$RIGHTPK_3 "
+            + "          for $token in %s($$RIGHT_3) "
+            + "          /*+ hash */ "
+            + "          group by $tokenGroupped := $token with $id "
+            + "          /*+ inmem 34 198608 */ "
+            + "          order by count($id), $tokenGroupped "
+            + "          return $tokenGroupped "
+            //
+            // -- -- -- -
+            //
+            + "        where $token = /*+ bcast */ $tokenRanked "
+            + "        order by $i "
+            + "        return $i "
+            + "      for $prefixTokenRight in subset-collection($tokensRight, 0, prefix-len-%s(len($tokensRight), %ff)) "
+            + "      ), $prefixTokenLeft = $prefixTokenRight) "
+            + "    let $sim := similarity-%s-prefix($lenLeft, $tokensLeft, $lenRight, $tokensRight, $prefixTokenLeft, %ff) "
+            + "    where $sim >= %ff " + "    /*+ hash*/ "
+            + "    group by $idLeft := $$LEFTPK_1, $idRight := $$RIGHTPK_1 with $sim "
+            //
+            // -- -- -
+            //
+            + "    ), $$LEFTPK = $idLeft)),  $$RIGHTPK = $idRight)";
+
+    private Collection<LogicalVariable> liveVars = new HashSet<LogicalVariable>();
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+        // current opperator is join
+        if (op.getOperatorTag() != LogicalOperatorTag.INNERJOIN
+                && op.getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN) {
+            return false;
+        }
+
+        // Find GET_ITEM function.
+        AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) op;
+        Mutable<ILogicalExpression> expRef = joinOp.getCondition();
+        Mutable<ILogicalExpression> getItemExprRef = getSimilarityExpression(expRef);
+        if (getItemExprRef == null) {
+            return false;
+        }
+        // Check if the GET_ITEM function is on one of the supported similarity-check functions.
+        AbstractFunctionCallExpression getItemFuncExpr = (AbstractFunctionCallExpression) getItemExprRef.getValue();
+        Mutable<ILogicalExpression> argRef = getItemFuncExpr.getArguments().get(0);
+        AbstractFunctionCallExpression simFuncExpr = (AbstractFunctionCallExpression) argRef.getValue();
+        if (!simFuncs.contains(simFuncExpr.getFunctionIdentifier())) {
+            return false;
+        }
+        // Skip this rule based on annotations.
+        if (simFuncExpr.getAnnotations().containsKey(IndexedNLJoinExpressionAnnotation.INSTANCE)) {
+            return false;
+        }
+
+        List<Mutable<ILogicalOperator>> inputOps = joinOp.getInputs();
+        ILogicalOperator leftInputOp = inputOps.get(0).getValue();
+        ILogicalOperator rightInputOp = inputOps.get(1).getValue();
+
+        List<Mutable<ILogicalExpression>> inputExps = simFuncExpr.getArguments();
+
+        ILogicalExpression inputExp0 = inputExps.get(0).getValue();
+        ILogicalExpression inputExp1 = inputExps.get(1).getValue();
+
+        // left and right expressions are variables
+        if (inputExp0.getExpressionTag() != LogicalExpressionTag.VARIABLE
+                || inputExp1.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
+            return false;
+        }
+
+        LogicalVariable inputVar0 = ((VariableReferenceExpression) inputExp0).getVariableReference();
+        LogicalVariable inputVar1 = ((VariableReferenceExpression) inputExp1).getVariableReference();
+
+        LogicalVariable leftInputVar;
+        LogicalVariable rightInputVar;
+
+        liveVars.clear();
+        VariableUtilities.getLiveVariables(leftInputOp, liveVars);
+        if (liveVars.contains(inputVar0)) {
+            leftInputVar = inputVar0;
+            rightInputVar = inputVar1;
+        } else {
+            leftInputVar = inputVar1;
+            rightInputVar = inputVar0;
+        }
+
+        List<LogicalVariable> leftInputPKs = context.findPrimaryKey(leftInputVar);
+        List<LogicalVariable> rightInputPKs = context.findPrimaryKey(rightInputVar);
+        // Bail if primary keys could not be inferred.
+        if (leftInputPKs == null || rightInputPKs == null) {
+            return false;
+        }
+        // primary key has only one variable
+        if (leftInputPKs.size() != 1 || rightInputPKs.size() != 1) {
+            return false;
+        }
+        IAType leftType = (IAType) context.getOutputTypeEnvironment(leftInputOp).getVarType(leftInputVar);
+        IAType rightType = (IAType) context.getOutputTypeEnvironment(rightInputOp).getVarType(rightInputVar);
+        // left-hand side and right-hand side of "~=" has the same type
+        IAType left2 = TypeHelper.getNonOptionalType(leftType);
+        IAType right2 = TypeHelper.getNonOptionalType(rightType);
+        if (!left2.deepEqual(right2)) {
+            return false;
+        }
+        //
+        // -- - FIRE - --
+        //
+        AqlMetadataProvider metadataProvider = ((AqlMetadataProvider) context.getMetadataProvider());
+        FunctionIdentifier funcId = FuzzyUtils.getTokenizer(leftType.getTypeTag());
+        String tokenizer;
+        if (funcId == null) {
+            tokenizer = "";
+        } else {
+            tokenizer = funcId.getName();
+        }
+
+        float simThreshold = FuzzyUtils.getSimThreshold(metadataProvider);
+        String simFunction = FuzzyUtils.getSimFunction(metadataProvider);
+
+        // finalize AQL+ query
+        String prepareJoin;
+        switch (joinOp.getJoinKind()) {
+            case INNER: {
+                prepareJoin = "join" + AQLPLUS;
+                break;
+            }
+            case LEFT_OUTER: {
+                // TODO To make it work for Left Outer Joins, we should permute
+                // the #LEFT and #RIGHT at the top of the AQL+ query. But, when
+                // doing this, the
+                // fuzzyjoin/user-vis-int-vis-user-lot-aqlplus_1.aql (the one
+                // doing 3-way fuzzy joins) gives a different result. But even
+                // if we don't change the FuzzyJoinRule, permuting the for
+                // clauses in fuzzyjoin/user-vis-int-vis-user-lot-aqlplus_1.aql
+                // leads to different results, which suggests there is some
+                // other sort of bug.
+                return false;
+                // prepareJoin = "loj" + AQLPLUS;
+                // break;
+            }
+            default: {
+                throw new IllegalStateException();
+            }
+        }
+        String aqlPlus = String.format(Locale.US, prepareJoin, tokenizer, tokenizer, simFunction, simThreshold,
+                tokenizer, tokenizer, simFunction, simThreshold, simFunction, simThreshold, simThreshold);
+
+        LogicalVariable leftPKVar = leftInputPKs.get(0);
+        LogicalVariable rightPKVar = rightInputPKs.get(0);
+
+        Counter counter = new Counter(context.getVarCounter());
+
+        AQLPlusParser parser = new AQLPlusParser(new StringReader(aqlPlus));
+        parser.initScope();
+        parser.setVarCounter(counter);
+        List<Clause> clauses;
+        try {
+            clauses = parser.Clauses();
+        } catch (ParseException e) {
+            throw new AlgebricksException(e);
+        }
+        // The translator will compile metadata internally. Run this compilation
+        // under the same transaction id as the "outer" compilation.
+        AqlPlusExpressionToPlanTranslator translator = new AqlPlusExpressionToPlanTranslator(
+                metadataProvider.getJobId(), metadataProvider, counter, null, null);
+
+        LogicalOperatorDeepCopyVisitor deepCopyVisitor = new LogicalOperatorDeepCopyVisitor(counter);
+
+        translator.addOperatorToMetaScope(new Identifier("#LEFT"), leftInputOp);
+        translator.addVariableToMetaScope(new Identifier("$$LEFT"), leftInputVar);
+        translator.addVariableToMetaScope(new Identifier("$$LEFTPK"), leftPKVar);
+
+        translator.addOperatorToMetaScope(new Identifier("#RIGHT"), rightInputOp);
+        translator.addVariableToMetaScope(new Identifier("$$RIGHT"), rightInputVar);
+        translator.addVariableToMetaScope(new Identifier("$$RIGHTPK"), rightPKVar);
+
+        translator.addOperatorToMetaScope(new Identifier("#LEFT_1"), deepCopyVisitor.deepCopy(leftInputOp, null));
+        translator.addVariableToMetaScope(new Identifier("$$LEFT_1"), deepCopyVisitor.varCopy(leftInputVar));
+        translator.addVariableToMetaScope(new Identifier("$$LEFTPK_1"), deepCopyVisitor.varCopy(leftPKVar));
+        deepCopyVisitor.updatePrimaryKeys(context);
+        deepCopyVisitor.reset();
+
+        // translator.addOperatorToMetaScope(new Identifier("#LEFT_2"),
+        // deepCopyVisitor.deepCopy(leftInputOp, null));
+        // translator.addVariableToMetaScope(new Identifier("$$LEFT_2"),
+        // deepCopyVisitor.varCopy(leftInputVar));
+        // translator.addVariableToMetaScope(new Identifier("$$LEFTPK_2"),
+        // deepCopyVisitor.varCopy(leftPKVar));
+        // deepCopyVisitor.updatePrimaryKeys(context);
+        // deepCopyVisitor.reset();
+        //
+        // translator.addOperatorToMetaScope(new Identifier("#LEFT_3"),
+        // deepCopyVisitor.deepCopy(leftInputOp, null));
+        // translator.addVariableToMetaScope(new Identifier("$$LEFT_3"),
+        // deepCopyVisitor.varCopy(leftInputVar));
+        // translator.addVariableToMetaScope(new Identifier("$$LEFTPK_3"),
+        // deepCopyVisitor.varCopy(leftPKVar));
+        // deepCopyVisitor.updatePrimaryKeys(context);
+        // deepCopyVisitor.reset();
+
+        translator.addOperatorToMetaScope(new Identifier("#RIGHT_1"), deepCopyVisitor.deepCopy(rightInputOp, null));
+        translator.addVariableToMetaScope(new Identifier("$$RIGHT_1"), deepCopyVisitor.varCopy(rightInputVar));
+        translator.addVariableToMetaScope(new Identifier("$$RIGHTPK_1"), deepCopyVisitor.varCopy(rightPKVar));
+        deepCopyVisitor.updatePrimaryKeys(context);
+        deepCopyVisitor.reset();
+
+        // TODO pick side to run Stage 1, currently always picks RIGHT side
+        translator.addOperatorToMetaScope(new Identifier("#RIGHT_2"), deepCopyVisitor.deepCopy(rightInputOp, null));
+        translator.addVariableToMetaScope(new Identifier("$$RIGHT_2"), deepCopyVisitor.varCopy(rightInputVar));
+        translator.addVariableToMetaScope(new Identifier("$$RIGHTPK_2"), deepCopyVisitor.varCopy(rightPKVar));
+        deepCopyVisitor.updatePrimaryKeys(context);
+        deepCopyVisitor.reset();
+
+        translator.addOperatorToMetaScope(new Identifier("#RIGHT_3"), deepCopyVisitor.deepCopy(rightInputOp, null));
+        translator.addVariableToMetaScope(new Identifier("$$RIGHT_3"), deepCopyVisitor.varCopy(rightInputVar));
+        translator.addVariableToMetaScope(new Identifier("$$RIGHTPK_3"), deepCopyVisitor.varCopy(rightPKVar));
+        deepCopyVisitor.updatePrimaryKeys(context);
+        deepCopyVisitor.reset();
+
+        ILogicalPlan plan;
+        try {
+            plan = translator.translate(clauses);
+        } catch (AsterixException e) {
+            throw new AlgebricksException(e);
+        }
+        context.setVarCounter(counter.get());
+
+        ILogicalOperator outputOp = plan.getRoots().get(0).getValue();
+
+        SelectOperator extraSelect = null;
+        if (getItemExprRef != expRef) {
+            // more than one join condition
+            getItemExprRef.setValue(ConstantExpression.TRUE);
+            switch (joinOp.getJoinKind()) {
+                case INNER: {
+                    extraSelect = new SelectOperator(expRef, false, null);
+                    extraSelect.getInputs().add(new MutableObject<ILogicalOperator>(outputOp));
+                    outputOp = extraSelect;
+                    break;
+                }
+                case LEFT_OUTER: {
+                    if (((AbstractLogicalOperator) outputOp).getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN) {
+                        throw new IllegalStateException();
+                    }
+                    LeftOuterJoinOperator topJoin = (LeftOuterJoinOperator) outputOp;
+                    topJoin.getCondition().setValue(expRef.getValue());
+                    break;
+                }
+                default: {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        opRef.setValue(outputOp);
+        OperatorPropertiesUtil.typeOpRec(opRef, context);
+        return true;
+    }
+
+    /**
+     * Look for GET_ITEM function call.
+     */
+    private Mutable<ILogicalExpression> getSimilarityExpression(Mutable<ILogicalExpression> expRef) {
+        ILogicalExpression exp = expRef.getValue();
+        if (exp.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+            AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) exp;
+            if (funcExpr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.GET_ITEM)) {
+                return expRef;
+            }
+            if (funcExpr.getFunctionIdentifier().equals(AlgebricksBuiltinFunctions.AND)) {
+                for (int i = 0; i < 2; i++) {
+                    Mutable<ILogicalExpression> expRefRet = getSimilarityExpression(funcExpr.getArguments().get(i));
+                    if (expRefRet != null) {
+                        return expRefRet;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/34d81630/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java
new file mode 100644
index 0000000..cd18517
--- /dev/null
+++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java
@@ -0,0 +1,126 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.aql.util.FunctionUtils;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.ILogicalPlan;
+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.ScalarFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+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.SelectOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class IfElseToSwitchCaseFunctionRule 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 op1 = (AbstractLogicalOperator) opRef.getValue();
+        if (op1.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+            return false;
+
+        AssignOperator assignOp = (AssignOperator) op1;
+        List<Mutable<ILogicalExpression>> assignExprs = assignOp.getExpressions();
+        if (assignExprs.size() > 1)
+            return false;
+        ILogicalExpression expr = assignExprs.get(0).getValue();
+        if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+            AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
+            if (!funcExpr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.CONCAT_NON_NULL))
+                return false;
+        }
+
+        AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
+        if (op2.getOperatorTag() != LogicalOperatorTag.SUBPLAN)
+            return false;
+
+        SubplanOperator subplan = (SubplanOperator) op2;
+        List<ILogicalPlan> subPlans = subplan.getNestedPlans();
+        List<Mutable<ILogicalExpression>> arguments = new ArrayList<Mutable<ILogicalExpression>>();
+        for (ILogicalPlan plan : subPlans) {
+            List<Mutable<ILogicalOperator>> roots = plan.getRoots();
+
+            AbstractLogicalOperator nestedRoot = (AbstractLogicalOperator) roots.get(0).getValue();
+            if (nestedRoot.getOperatorTag() != LogicalOperatorTag.SELECT)
+                return false;
+            SelectOperator selectOp = (SelectOperator) nestedRoot;
+
+            AbstractLogicalOperator nestedNextOp = (AbstractLogicalOperator) nestedRoot.getInputs().get(0).getValue();
+            if (nestedNextOp.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+                return false;
+            AssignOperator assignRoot = (AssignOperator) nestedNextOp;
+            Mutable<ILogicalExpression> actionExprRef = assignRoot.getExpressions().get(0);
+
+            arguments.add(selectOp.getCondition());
+            arguments.add(actionExprRef);
+            AbstractLogicalOperator nestedBottomOp = (AbstractLogicalOperator) assignRoot.getInputs().get(0).getValue();
+
+            if (nestedBottomOp.getOperatorTag() != LogicalOperatorTag.NESTEDTUPLESOURCE)
+                return false;
+        }
+
+        AbstractLogicalOperator op3 = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
+        if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+            return false;
+
+        AssignOperator bottomAssign = (AssignOperator) op3;
+        LogicalVariable conditionVar = bottomAssign.getVariables().get(0);
+        Mutable<ILogicalExpression> switchCondition = new MutableObject<ILogicalExpression>(
+                new VariableReferenceExpression(conditionVar));
+        List<Mutable<ILogicalExpression>> argumentRefs = new ArrayList<Mutable<ILogicalExpression>>();
+        argumentRefs.add(switchCondition);
+        argumentRefs.addAll(arguments);
+
+        /** replace the branch conditions */
+        for (int i = 0; i < arguments.size(); i += 2) {
+            if (arguments.get(i).getValue().equals(switchCondition.getValue())) {
+                arguments.get(i).setValue(ConstantExpression.TRUE);
+            } else {
+                arguments.get(i).setValue(ConstantExpression.FALSE);
+            }
+        }
+
+        ILogicalExpression callExpr = new ScalarFunctionCallExpression(
+                FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.SWITCH_CASE), argumentRefs);
+
+        assignOp.getInputs().get(0).setValue(op3);
+        assignOp.getExpressions().get(0).setValue(callExpr);
+        context.computeAndSetTypeEnvironmentForOperator(assignOp);
+        return true;
+    }
+}


Mime
View raw message