[ASTERIXDB-3237][RT] Add external filter evaluator

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
This patch adds the runtime part for dynamic prefixes
for external datasets.

Change-Id: Icdab84a15fe9ea71676b426c8efdac8c80c7d742
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17700
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Wail Alkowaileet <wael.y.k@gmail.com>
Reviewed-by: Hussain Towaileb <hussainht@gmail.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/PushdownProcessorsExecutor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/PushdownProcessorsExecutor.java
index 110cd29..4106337 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/PushdownProcessorsExecutor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/PushdownProcessorsExecutor.java
@@ -32,10 +32,9 @@
 import org.apache.asterix.optimizer.rules.pushdown.descriptor.ScanDefineDescriptor;
 import org.apache.asterix.optimizer.rules.pushdown.visitor.ExpectedSchemaNodeToIATypeTranslatorVisitor;
 import org.apache.asterix.runtime.projection.ColumnDatasetProjectionFiltrationInfo;
-import org.apache.asterix.runtime.projection.ExternalDatasetProjectionInfo;
+import org.apache.asterix.runtime.projection.ExternalDatasetProjectionFiltrationInfo;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.DefaultProjectionFiltrationInfo;
 import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
 import org.apache.hyracks.algebricks.core.algebra.metadata.IProjectionFiltrationInfo;
@@ -101,16 +100,19 @@
 
     private IProjectionFiltrationInfo createExternalDatasetProjectionInfo(ScanDefineDescriptor scanDefineDescriptor,
             IOptimizationContext context) {
-        if (!context.getPhysicalOptimizationConfig().isExternalFieldPushdown()) {
-            return DefaultProjectionFiltrationInfo.INSTANCE;
+        Map<String, FunctionCallInformation> pathLocations = scanDefineDescriptor.getPathLocations();
+        ARecordType recordRequestedType = ALL_FIELDS_TYPE;
+        Dataset dataset = scanDefineDescriptor.getDataset();
+        if (context.getPhysicalOptimizationConfig().isExternalFieldPushdown()
+                && DatasetUtil.isFieldAccessPushdownSupported(dataset)) {
+            ExpectedSchemaNodeToIATypeTranslatorVisitor converter =
+                    new ExpectedSchemaNodeToIATypeTranslatorVisitor(pathLocations);
+            recordRequestedType = (ARecordType) scanDefineDescriptor.getRecordNode().accept(converter,
+                    scanDefineDescriptor.getDataset().getDatasetName());
         }
 
-        Map<String, FunctionCallInformation> pathLocations = scanDefineDescriptor.getPathLocations();
-        ExpectedSchemaNodeToIATypeTranslatorVisitor converter =
-                new ExpectedSchemaNodeToIATypeTranslatorVisitor(pathLocations);
-        ARecordType recordRequestedType = (ARecordType) scanDefineDescriptor.getRecordNode().accept(converter,
-                scanDefineDescriptor.getDataset().getDatasetName());
-        return new ExternalDatasetProjectionInfo(recordRequestedType, pathLocations);
+        return new ExternalDatasetProjectionFiltrationInfo(recordRequestedType, pathLocations,
+                scanDefineDescriptor.getFilterPaths(), scanDefineDescriptor.getFilterExpression());
     }
 
     private void setInfoToDataScan(AbstractScanOperator scanOp, IProjectionFiltrationInfo info) {
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluator.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluator.java
index a169ecb..22cd20a 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluator.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluator.java
@@ -18,14 +18,14 @@
  */
 package org.apache.asterix.common.external;
 
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
 
 public interface IExternalFilterEvaluator {
     boolean isEmpty();
 
     boolean isComputedFieldUsed(int index);
 
-    void setValue(int index, String stringValue) throws AlgebricksException;
+    void setValue(int index, String stringValue) throws HyracksDataException;
 
-    boolean evaluate() throws AlgebricksException;
+    boolean evaluate() throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluatorFactory.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluatorFactory.java
index c29e554..38a38a6 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/external/IExternalFilterEvaluatorFactory.java
@@ -20,11 +20,11 @@
 
 import java.io.Serializable;
 
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.api.application.IServiceContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 
 public interface IExternalFilterEvaluatorFactory extends Serializable {
     IExternalFilterEvaluator create(IServiceContext serviceContext, IWarningCollector warningCollector)
-            throws AlgebricksException;
+            throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterEvaluator.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterEvaluator.java
new file mode 100644
index 0000000..49b6ae4
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterEvaluator.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import org.apache.asterix.common.external.IExternalFilterEvaluator;
+import org.apache.asterix.formats.nontagged.BinaryBooleanInspector;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+
+class ExternalFilterEvaluator implements IExternalFilterEvaluator {
+    private final IScalarEvaluator evaluator;
+    private final IExternalFilterValueEvaluator[] valueEvaluators;
+    private final VoidPointable booleanResult;
+
+    ExternalFilterEvaluator(IScalarEvaluator evaluator, IExternalFilterValueEvaluator[] valueEvaluators) {
+        this.evaluator = evaluator;
+        this.valueEvaluators = valueEvaluators;
+        booleanResult = new VoidPointable();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return valueEvaluators.length == 0;
+    }
+
+    @Override
+    public boolean isComputedFieldUsed(int index) {
+        return valueEvaluators[index] != NoOpExternalFilterValueEvaluator.INSTANCE;
+    }
+
+    @Override
+    public void setValue(int index, String stringValue) throws HyracksDataException {
+        valueEvaluators[index].setValue(stringValue);
+    }
+
+    @Override
+    public boolean evaluate() throws HyracksDataException {
+        evaluator.evaluate(null, booleanResult);
+        return BinaryBooleanInspector.getBooleanValue(booleanResult.getByteArray(), booleanResult.getStartOffset(),
+                booleanResult.getLength());
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterEvaluatorFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterEvaluatorFactory.java
new file mode 100644
index 0000000..0790700
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterEvaluatorFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import java.util.Arrays;
+
+import org.apache.asterix.common.external.IExternalFilterEvaluator;
+import org.apache.asterix.common.external.IExternalFilterEvaluatorFactory;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.application.IServiceContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.IWarningCollector;
+
+public class ExternalFilterEvaluatorFactory implements IExternalFilterEvaluatorFactory {
+    private static final long serialVersionUID = -309935877927008746L;
+    private final int numberOfComputedFields;
+    private final IScalarEvaluatorFactory filterEvalFactory;
+
+    public ExternalFilterEvaluatorFactory(int numberOfComputedFields, IScalarEvaluatorFactory filterEvalFactory) {
+        this.numberOfComputedFields = numberOfComputedFields;
+        this.filterEvalFactory = filterEvalFactory;
+    }
+
+    @Override
+    public IExternalFilterEvaluator create(IServiceContext serviceContext, IWarningCollector warningCollector)
+            throws HyracksDataException {
+        IExternalFilterValueEvaluator[] valueEvaluators = new IExternalFilterValueEvaluator[numberOfComputedFields];
+        Arrays.fill(valueEvaluators, NoOpExternalFilterValueEvaluator.INSTANCE);
+        FilterEvaluatorContext filterContext =
+                new FilterEvaluatorContext(serviceContext, warningCollector, valueEvaluators);
+        return new ExternalFilterEvaluator(filterEvalFactory.createScalarEvaluator(filterContext), valueEvaluators);
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterValueEvaluator.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterValueEvaluator.java
new file mode 100644
index 0000000..85da569
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterValueEvaluator.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.asterix.dataflow.data.nontagged.serde.SerializerDeserializerUtil;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import org.apache.hyracks.dataflow.common.data.marshalling.DoubleSerializerDeserializer;
+import org.apache.hyracks.dataflow.common.data.marshalling.Integer64SerializerDeserializer;
+import org.apache.hyracks.util.string.UTF8StringUtil;
+import org.apache.hyracks.util.string.UTF8StringWriter;
+
+class ExternalFilterValueEvaluator implements IExternalFilterValueEvaluator {
+    private final ATypeTag typeTag;
+    private final ArrayBackedValueStorage value;
+    private final UTF8StringWriter utf8StringWriter;
+
+    ExternalFilterValueEvaluator(ATypeTag typeTag) {
+        this.typeTag = typeTag;
+        value = new ArrayBackedValueStorage();
+        utf8StringWriter = new UTF8StringWriter();
+    }
+
+    @Override
+    public void setValue(String stringValue) throws HyracksDataException {
+        value.reset();
+        try {
+            writeValue(typeTag, stringValue);
+        } catch (IOException e) {
+            throw HyracksDataException.create(e);
+        }
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+        result.set(value);
+    }
+
+    private void writeValue(ATypeTag typeTag, String stringValue) throws IOException {
+        DataOutput output = value.getDataOutput();
+        SerializerDeserializerUtil.serializeTag(typeTag, output);
+        switch (typeTag) {
+            case TINYINT:
+            case SMALLINT:
+            case INTEGER:
+            case BIGINT:
+                Integer64SerializerDeserializer.write(Long.parseLong(stringValue), output);
+            case DOUBLE:
+                DoubleSerializerDeserializer.write(Double.parseDouble(stringValue), output);
+            case STRING:
+                UTF8StringUtil.writeUTF8(stringValue, output, utf8StringWriter);
+        }
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterValueEvaluatorFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterValueEvaluatorFactory.java
new file mode 100644
index 0000000..250f0ef
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/ExternalFilterValueEvaluatorFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.IAType;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class ExternalFilterValueEvaluatorFactory implements IScalarEvaluatorFactory {
+    private static final long serialVersionUID = 6651915525106158386L;
+    private final int index;
+    private final ATypeTag typeTag;
+
+    public ExternalFilterValueEvaluatorFactory(int index, IAType type) {
+        this.index = index;
+        this.typeTag = type.getTypeTag();
+    }
+
+    @Override
+    public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
+        FilterEvaluatorContext filterContext = (FilterEvaluatorContext) ctx;
+        return filterContext.createEvaluator(index, typeTag);
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/FilterEvaluatorContext.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/FilterEvaluatorContext.java
new file mode 100644
index 0000000..db78cae
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/FilterEvaluatorContext.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import java.util.Arrays;
+
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.evaluators.EvaluatorContext;
+import org.apache.hyracks.api.application.IServiceContext;
+import org.apache.hyracks.api.exceptions.IWarningCollector;
+
+class FilterEvaluatorContext extends EvaluatorContext {
+    private final IExternalFilterValueEvaluator[] evaluators;
+
+    public FilterEvaluatorContext(IServiceContext serviceContext, IWarningCollector warningCollector,
+            IExternalFilterValueEvaluator[] evaluators) {
+        super(serviceContext, warningCollector);
+        this.evaluators = evaluators;
+        Arrays.fill(evaluators, NoOpExternalFilterValueEvaluator.INSTANCE);
+    }
+
+    public IScalarEvaluator createEvaluator(int index, ATypeTag typeTag) {
+        IExternalFilterValueEvaluator evaluator = evaluators[index];
+        if (evaluator == NoOpExternalFilterValueEvaluator.INSTANCE) {
+            evaluator = new ExternalFilterValueEvaluator(typeTag);
+            evaluators[index] = evaluator;
+        }
+        return evaluator;
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/IExternalFilterValueEvaluator.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/IExternalFilterValueEvaluator.java
new file mode 100644
index 0000000..1ed57c1
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/IExternalFilterValueEvaluator.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+interface IExternalFilterValueEvaluator extends IScalarEvaluator {
+    void setValue(String stringValue) throws HyracksDataException;
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/NoOpExternalFilterValueEvaluator.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/NoOpExternalFilterValueEvaluator.java
new file mode 100644
index 0000000..14944d4
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/filter/NoOpExternalFilterValueEvaluator.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.external.input.filter;
+
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+class NoOpExternalFilterValueEvaluator implements IExternalFilterValueEvaluator {
+    public static final IExternalFilterValueEvaluator INSTANCE = new NoOpExternalFilterValueEvaluator();
+
+    @Override
+    public void setValue(String stringValue) throws HyracksDataException {
+        // NoOp
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+        // NoOp
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/abstracts/AbstractExternalInputStreamFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/abstracts/AbstractExternalInputStreamFactory.java
index ff6b03e..37fd910 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/abstracts/AbstractExternalInputStreamFactory.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/abstracts/AbstractExternalInputStreamFactory.java
@@ -64,7 +64,7 @@
 
     @Override
     public void configure(IServiceContext ctx, Map<String, String> configuration, IWarningCollector warningCollector,
-            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException {
+            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException, HyracksDataException {
         this.configuration = configuration;
         this.partitionConstraint =
                 ((ICcApplicationContext) ctx.getApplicationContext()).getClusterStateManager().getClusterLocations();
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/aws/AwsS3InputStreamFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/aws/AwsS3InputStreamFactory.java
index cfa1e46..881c5a3 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/aws/AwsS3InputStreamFactory.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/aws/AwsS3InputStreamFactory.java
@@ -50,7 +50,7 @@
 
     @Override
     public void configure(IServiceContext ctx, Map<String, String> configuration, IWarningCollector warningCollector,
-            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException {
+            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException, HyracksDataException {
         super.configure(ctx, configuration, warningCollector, filterEvaluatorFactory);
 
         // Ensure the validity of include/exclude
@@ -72,7 +72,7 @@
     }
 
     private List<S3Object> filterPrefixes(ExternalDataPrefix prefix, List<S3Object> filesOnly,
-            IExternalFilterEvaluator evaluator) throws AlgebricksException {
+            IExternalFilterEvaluator evaluator) throws HyracksDataException {
 
         // if no computed fields or empty files list, return the original list
         if (filesOnly.isEmpty() || !prefix.hasComputedFields()) {
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/blob/AzureBlobInputStreamFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/blob/AzureBlobInputStreamFactory.java
index b18b655..5cd396e 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/blob/AzureBlobInputStreamFactory.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/blob/AzureBlobInputStreamFactory.java
@@ -54,7 +54,7 @@
 
     @Override
     public void configure(IServiceContext ctx, Map<String, String> configuration, IWarningCollector warningCollector,
-            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException {
+            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException, HyracksDataException {
         super.configure(ctx, configuration, warningCollector, filterEvaluatorFactory);
 
         IApplicationContext appCtx = (IApplicationContext) ctx.getApplicationContext();
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/datalake/AzureDataLakeInputStreamFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/datalake/AzureDataLakeInputStreamFactory.java
index 35c3648..bd2535d 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/datalake/AzureDataLakeInputStreamFactory.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/azure/datalake/AzureDataLakeInputStreamFactory.java
@@ -54,7 +54,7 @@
 
     @Override
     public void configure(IServiceContext ctx, Map<String, String> configuration, IWarningCollector warningCollector,
-            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException {
+            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException, HyracksDataException {
         super.configure(ctx, configuration, warningCollector, filterEvaluatorFactory);
 
         IApplicationContext appCtx = (IApplicationContext) ctx.getApplicationContext();
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/gcs/GCSInputStreamFactory.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/gcs/GCSInputStreamFactory.java
index 433fecd..165f340 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/gcs/GCSInputStreamFactory.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/input/record/reader/gcs/GCSInputStreamFactory.java
@@ -49,7 +49,7 @@
 
     @Override
     public void configure(IServiceContext ctx, Map<String, String> configuration, IWarningCollector warningCollector,
-            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException {
+            IExternalFilterEvaluatorFactory filterEvaluatorFactory) throws AlgebricksException, HyracksDataException {
         super.configure(ctx, configuration, warningCollector, filterEvaluatorFactory);
 
         // Ensure the validity of include/exclude
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataPrefix.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataPrefix.java
index 97bf776..899a179 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataPrefix.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataPrefix.java
@@ -44,6 +44,7 @@
 import org.apache.asterix.om.utils.ProjectionFiltrationTypeUtil;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
 
 public class ExternalDataPrefix {
 
@@ -208,12 +209,11 @@
     /**
      * Evaluates whether the provided key satisfies the conditions of the evaluator or not
      *
-     * @param key ke
+     * @param key       ke
      * @param evaluator evaluator
-     *
      * @return true if key satisfies the evaluator conditions, false otherwise
      */
-    public boolean evaluate(String key, IExternalFilterEvaluator evaluator) throws AlgebricksException {
+    public boolean evaluate(String key, IExternalFilterEvaluator evaluator) throws HyracksDataException {
         List<String> keySegments = extractPrefixSegments(key);
 
         // segments of object key have to be larger than segments of the prefix
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataUtils.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataUtils.java
index 9d36b4a..e60190b 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataUtils.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/ExternalDataUtils.java
@@ -75,7 +75,7 @@
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.types.TypeTagUtil;
 import org.apache.asterix.runtime.evaluators.common.NumberUtils;
-import org.apache.asterix.runtime.projection.ExternalDatasetProjectionInfo;
+import org.apache.asterix.runtime.projection.ExternalDatasetProjectionFiltrationInfo;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -900,7 +900,7 @@
                 || ExternalDataConstants.FORMAT_PARQUET.equals(properties.get(ExternalDataConstants.KEY_FORMAT));
     }
 
-    public static void setExternalDataProjectionInfo(ExternalDatasetProjectionInfo projectionInfo,
+    public static void setExternalDataProjectionInfo(ExternalDatasetProjectionFiltrationInfo projectionInfo,
             Map<String, String> properties) throws IOException {
         properties.put(ExternalDataConstants.KEY_REQUESTED_FIELDS,
                 serializeExpectedTypeToString(projectionInfo.getProjectedType()));
@@ -922,7 +922,7 @@
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
         Base64.Encoder encoder = Base64.getEncoder();
-        ExternalDatasetProjectionInfo.writeTypeField(expectedType, dataOutputStream);
+        ExternalDatasetProjectionFiltrationInfo.writeTypeField(expectedType, dataOutputStream);
         return encoder.encodeToString(byteArrayOutputStream.toByteArray());
     }
 
@@ -938,7 +938,8 @@
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
         Base64.Encoder encoder = Base64.getEncoder();
-        ExternalDatasetProjectionInfo.writeFunctionCallInformationMapField(functionCallInfoMap, dataOutputStream);
+        ExternalDatasetProjectionFiltrationInfo.writeFunctionCallInformationMapField(functionCallInfoMap,
+                dataOutputStream);
         return encoder.encodeToString(byteArrayOutputStream.toByteArray());
     }
 
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/HDFSUtils.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/HDFSUtils.java
index 2618ae6..a11a8dd 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/HDFSUtils.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/util/HDFSUtils.java
@@ -43,7 +43,7 @@
 import org.apache.asterix.external.input.stream.HDFSInputStream;
 import org.apache.asterix.external.util.ExternalDataConstants.ParquetOptions;
 import org.apache.asterix.om.types.ARecordType;
-import org.apache.asterix.runtime.projection.ExternalDatasetProjectionInfo;
+import org.apache.asterix.runtime.projection.ExternalDatasetProjectionFiltrationInfo;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.BlockLocation;
@@ -271,7 +271,7 @@
         Base64.Decoder decoder = Base64.getDecoder();
         byte[] typeBytes = decoder.decode(encoded);
         DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(typeBytes));
-        return ExternalDatasetProjectionInfo.createTypeField(dataInputStream);
+        return ExternalDatasetProjectionFiltrationInfo.createTypeField(dataInputStream);
     }
 
     public static void setFunctionCallInformationMap(Map<String, FunctionCallInformation> funcCallInfoMap,
@@ -287,7 +287,7 @@
             Base64.Decoder decoder = Base64.getDecoder();
             byte[] functionCallInfoMapBytes = decoder.decode(encoded);
             DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(functionCallInfoMapBytes));
-            return ExternalDatasetProjectionInfo.createFunctionCallInformationMap(dataInputStream);
+            return ExternalDatasetProjectionFiltrationInfo.createFunctionCallInformationMap(dataInputStream);
         }
         return null;
     }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
index 25eab7f..f4e15de 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
@@ -28,7 +28,7 @@
 import java.util.Map;
 
 import org.apache.asterix.common.config.DatasetConfig.DatasetType;
-import org.apache.asterix.common.external.NoOpExternalFilterEvaluatorFactory;
+import org.apache.asterix.common.external.IExternalFilterEvaluatorFactory;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.external.api.ITypedAdapterFactory;
 import org.apache.asterix.external.util.ExternalDataUtils;
@@ -42,7 +42,7 @@
 import org.apache.asterix.metadata.utils.KeyFieldTypeUtil;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.IAType;
-import org.apache.asterix.runtime.projection.ExternalDatasetProjectionInfo;
+import org.apache.asterix.runtime.projection.ExternalDatasetProjectionFiltrationInfo;
 import org.apache.hyracks.algebricks.common.constraints.AlgebricksPartitionConstraint;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.common.utils.Pair;
@@ -139,9 +139,11 @@
                         addExternalProjectionInfo(projectionFiltrationInfo, edd.getProperties());
                 properties = addSubPath(externalDataSource.getProperties(), properties);
                 properties.put(KEY_EXTERNAL_SCAN_BUFFER_SIZE, String.valueOf(externalScanBufferSize));
-                ITypedAdapterFactory adapterFactory = metadataProvider.getConfiguredAdapterFactory(externalDataset,
-                        edd.getAdapter(), properties, (ARecordType) itemType, context.getWarningCollector(),
-                        NoOpExternalFilterEvaluatorFactory.INSTANCE);
+                IExternalFilterEvaluatorFactory filterEvaluatorFactory = IndexUtil
+                        .createExternalFilterEvaluatorFactory(context, typeEnv, projectionFiltrationInfo, properties);
+                ITypedAdapterFactory adapterFactory =
+                        metadataProvider.getConfiguredAdapterFactory(externalDataset, edd.getAdapter(), properties,
+                                (ARecordType) itemType, context.getWarningCollector(), filterEvaluatorFactory);
                 return metadataProvider.getExternalDatasetScanRuntime(jobSpec, itemType, adapterFactory,
                         tupleFilterFactory, outputLimit);
             case INTERNAL:
@@ -182,7 +184,8 @@
             //properties could be cached and reused, so we make a copy per query
             propertiesCopy = new HashMap<>(properties);
             try {
-                ExternalDatasetProjectionInfo externalProjectionInfo = (ExternalDatasetProjectionInfo) projectionInfo;
+                ExternalDatasetProjectionFiltrationInfo externalProjectionInfo =
+                        (ExternalDatasetProjectionFiltrationInfo) projectionInfo;
                 ExternalDataUtils.setExternalDataProjectionInfo(externalProjectionInfo, propertiesCopy);
             } catch (IOException e) {
                 throw new IllegalStateException(e);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java
index 6a67313..b0d503c 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java
@@ -36,8 +36,11 @@
 import org.apache.asterix.common.config.DatasetConfig;
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.external.IExternalFilterEvaluatorFactory;
+import org.apache.asterix.common.external.NoOpExternalFilterEvaluatorFactory;
 import org.apache.asterix.common.transactions.TxnId;
 import org.apache.asterix.external.indexing.ExternalFile;
+import org.apache.asterix.external.util.ExternalDataPrefix;
 import org.apache.asterix.metadata.dataset.DatasetFormatInfo;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.Dataset;
@@ -45,12 +48,14 @@
 import org.apache.asterix.metadata.entities.InternalDatasetDetails;
 import org.apache.asterix.metadata.utils.filter.ColumnFilterBuilder;
 import org.apache.asterix.metadata.utils.filter.ColumnRangeFilterBuilder;
+import org.apache.asterix.metadata.utils.filter.ExternalFilterBuilder;
 import org.apache.asterix.om.base.AString;
 import org.apache.asterix.om.base.IAObject;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.runtime.job.listener.JobEventListenerFactory;
 import org.apache.asterix.runtime.projection.ColumnDatasetProjectionFiltrationInfo;
+import org.apache.asterix.runtime.projection.ExternalDatasetProjectionFiltrationInfo;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.common.utils.Pair;
@@ -325,4 +330,19 @@
                 datasetRequestedType);
     }
 
+    public static IExternalFilterEvaluatorFactory createExternalFilterEvaluatorFactory(JobGenContext context,
+            IVariableTypeEnvironment typeEnv, IProjectionFiltrationInfo projectionFiltrationInfo,
+            Map<String, String> properties) throws AlgebricksException {
+        if (projectionFiltrationInfo == DefaultProjectionFiltrationInfo.INSTANCE) {
+            return NoOpExternalFilterEvaluatorFactory.INSTANCE;
+        }
+
+        ExternalDataPrefix prefix = new ExternalDataPrefix(properties);
+        ExternalDatasetProjectionFiltrationInfo pfi =
+                (ExternalDatasetProjectionFiltrationInfo) projectionFiltrationInfo;
+        ExternalFilterBuilder build = new ExternalFilterBuilder(pfi, context, typeEnv, prefix);
+
+        return build.build();
+    }
+
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ExternalFilterBuilder.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ExternalFilterBuilder.java
new file mode 100644
index 0000000..4165e32
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ExternalFilterBuilder.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.metadata.utils.filter;
+
+import org.apache.asterix.common.external.IExternalFilterEvaluatorFactory;
+import org.apache.asterix.common.external.NoOpExternalFilterEvaluatorFactory;
+import org.apache.asterix.external.input.filter.ExternalFilterEvaluatorFactory;
+import org.apache.asterix.external.input.filter.ExternalFilterValueEvaluatorFactory;
+import org.apache.asterix.external.util.ExternalDataPrefix;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.runtime.projection.ExternalDatasetProjectionFiltrationInfo;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.jobgen.impl.JobGenContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+
+public class ExternalFilterBuilder extends AbstractFilterBuilder {
+    private final ExternalDataPrefix prefix;
+
+    public ExternalFilterBuilder(ExternalDatasetProjectionFiltrationInfo projectionFiltrationInfo,
+            JobGenContext context, IVariableTypeEnvironment typeEnv, ExternalDataPrefix prefix) {
+        super(projectionFiltrationInfo.getFilterPaths(), projectionFiltrationInfo.getFilterExpression(), context,
+                typeEnv);
+        this.prefix = prefix;
+    }
+
+    public IExternalFilterEvaluatorFactory build() throws AlgebricksException {
+        if (filterExpression == null || filterPaths.isEmpty()) {
+            return NoOpExternalFilterEvaluatorFactory.INSTANCE;
+        }
+        IScalarEvaluatorFactory evalFactory = createEvaluator(filterExpression);
+        if (evalFactory == null) {
+            return NoOpExternalFilterEvaluatorFactory.INSTANCE;
+        }
+        return new ExternalFilterEvaluatorFactory(prefix.getComputedFieldNames().size(), evalFactory);
+    }
+
+    @Override
+    protected IScalarEvaluatorFactory createValueAccessor(ILogicalExpression expression) {
+        ARecordType path = filterPaths.get(expression);
+        int index = prefix.getPaths().indexOf(path);
+        return new ExternalFilterValueEvaluatorFactory(index, prefix.getComputedFieldTypes().get(index));
+    }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/SerializerDeserializerUtil.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/SerializerDeserializerUtil.java
index 664eb28..f2809b9 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/SerializerDeserializerUtil.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/SerializerDeserializerUtil.java
@@ -73,7 +73,10 @@
 
     public static void serializeTag(IAObject instance, DataOutput out) throws HyracksDataException {
         IAType t = instance.getType();
-        ATypeTag tag = t.getTypeTag();
+        serializeTag(t.getTypeTag(), out);
+    }
+
+    public static void serializeTag(ATypeTag tag, DataOutput out) throws HyracksDataException {
         try {
             out.writeByte(tag.serialize());
         } catch (IOException e) {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ColumnDatasetProjectionFiltrationInfo.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ColumnDatasetProjectionFiltrationInfo.java
index 0a5ef7a..4227c31 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ColumnDatasetProjectionFiltrationInfo.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ColumnDatasetProjectionFiltrationInfo.java
@@ -22,7 +22,6 @@
 import static org.apache.asterix.om.utils.ProjectionFiltrationTypeUtil.EMPTY_TYPE;
 
 import java.io.IOException;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 
@@ -32,30 +31,21 @@
 
 import com.fasterxml.jackson.core.JsonGenerator;
 
-public class ColumnDatasetProjectionFiltrationInfo extends ExternalDatasetProjectionInfo {
+public class ColumnDatasetProjectionFiltrationInfo extends ExternalDatasetProjectionFiltrationInfo {
     private final ARecordType metaProjectedType;
-    private final ILogicalExpression filterExpression;
-    private final Map<ILogicalExpression, ARecordType> filterPaths;
     private final ILogicalExpression rangeFilterExpression;
 
     public ColumnDatasetProjectionFiltrationInfo(ARecordType recordRequestedType, ARecordType metaProjectedType,
             Map<String, FunctionCallInformation> sourceInformationMap, Map<ILogicalExpression, ARecordType> filterPaths,
             ILogicalExpression filterExpression, ILogicalExpression rangeFilterExpression) {
-        super(recordRequestedType, sourceInformationMap);
+        super(recordRequestedType, sourceInformationMap, filterPaths, filterExpression);
         this.metaProjectedType = metaProjectedType;
-
-        this.filterExpression = filterExpression;
         this.rangeFilterExpression = rangeFilterExpression;
-        this.filterPaths = filterPaths;
     }
 
     private ColumnDatasetProjectionFiltrationInfo(ColumnDatasetProjectionFiltrationInfo other) {
-        super(other.projectedType, other.functionCallInfoMap);
+        super(other.projectedType, other.functionCallInfoMap, other.filterPaths, other.filterExpression);
         metaProjectedType = other.metaProjectedType;
-
-        filterExpression = other.filterExpression;
-        filterPaths = new HashMap<>(other.filterPaths);
-
         rangeFilterExpression = other.rangeFilterExpression;
     }
 
@@ -96,15 +86,13 @@
 
     @Override
     public void print(JsonGenerator generator) throws IOException {
-        if (projectedType == ALL_FIELDS_TYPE) {
-            return;
-        }
-
         StringBuilder builder = new StringBuilder();
-        if (projectedType == EMPTY_TYPE) {
-            generator.writeStringField("project", projectedType.getTypeName());
-        } else {
-            generator.writeStringField("project", getOnelinerSchema(projectedType, builder));
+        if (projectedType != ALL_FIELDS_TYPE) {
+            if (projectedType == EMPTY_TYPE) {
+                generator.writeStringField("project", projectedType.getTypeName());
+            } else {
+                generator.writeStringField("project", getOnelinerSchema(projectedType, builder));
+            }
         }
 
         if (metaProjectedType != null && metaProjectedType != ALL_FIELDS_TYPE) {
@@ -124,14 +112,6 @@
         return metaProjectedType;
     }
 
-    public ILogicalExpression getFilterExpression() {
-        return filterExpression;
-    }
-
-    public Map<ILogicalExpression, ARecordType> getFilterPaths() {
-        return filterPaths;
-    }
-
     public ILogicalExpression getRangeFilterExpression() {
         return rangeFilterExpression;
     }
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ExternalDatasetProjectionInfo.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ExternalDatasetProjectionFiltrationInfo.java
similarity index 71%
rename from asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ExternalDatasetProjectionInfo.java
rename to asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ExternalDatasetProjectionFiltrationInfo.java
index 55919b3..13fc6e2 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ExternalDatasetProjectionInfo.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/ExternalDatasetProjectionFiltrationInfo.java
@@ -31,22 +31,29 @@
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.visitor.SimpleStringBuilderForIATypeVisitor;
 import org.apache.commons.lang3.SerializationUtils;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.metadata.IProjectionFiltrationInfo;
 import org.apache.hyracks.algebricks.core.algebra.prettyprint.AlgebricksStringBuilderWriter;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 
-public class ExternalDatasetProjectionInfo implements IProjectionFiltrationInfo {
+public class ExternalDatasetProjectionFiltrationInfo implements IProjectionFiltrationInfo {
     protected final ARecordType projectedType;
+
+    protected final ILogicalExpression filterExpression;
+    protected final Map<ILogicalExpression, ARecordType> filterPaths;
     protected final Map<String, FunctionCallInformation> functionCallInfoMap;
 
-    public ExternalDatasetProjectionInfo(ARecordType projectedType,
-            Map<String, FunctionCallInformation> sourceInformationMap) {
+    public ExternalDatasetProjectionFiltrationInfo(ARecordType projectedType,
+            Map<String, FunctionCallInformation> sourceInformationMap, Map<ILogicalExpression, ARecordType> filterPaths,
+            ILogicalExpression filterExpression) {
         this.projectedType = projectedType;
         this.functionCallInfoMap = sourceInformationMap;
+        this.filterExpression = filterExpression;
+        this.filterPaths = filterPaths;
     }
 
-    private ExternalDatasetProjectionInfo(ExternalDatasetProjectionInfo other) {
+    private ExternalDatasetProjectionFiltrationInfo(ExternalDatasetProjectionFiltrationInfo other) {
         if (other.projectedType == ALL_FIELDS_TYPE) {
             projectedType = ALL_FIELDS_TYPE;
         } else if (other.projectedType == EMPTY_TYPE) {
@@ -55,11 +62,14 @@
             projectedType = other.projectedType.deepCopy(other.projectedType);
         }
         functionCallInfoMap = new HashMap<>(other.functionCallInfoMap);
+
+        filterExpression = other.filterExpression;
+        filterPaths = new HashMap<>(other.filterPaths);
     }
 
     @Override
-    public ExternalDatasetProjectionInfo createCopy() {
-        return new ExternalDatasetProjectionInfo(this);
+    public ExternalDatasetProjectionFiltrationInfo createCopy() {
+        return new ExternalDatasetProjectionFiltrationInfo(this);
     }
 
     public ARecordType getProjectedType() {
@@ -70,6 +80,14 @@
         return functionCallInfoMap;
     }
 
+    public ILogicalExpression getFilterExpression() {
+        return filterExpression;
+    }
+
+    public Map<ILogicalExpression, ARecordType> getFilterPaths() {
+        return filterPaths;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -78,32 +96,43 @@
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-        ExternalDatasetProjectionInfo otherInfo = (ExternalDatasetProjectionInfo) o;
+        ExternalDatasetProjectionFiltrationInfo otherInfo = (ExternalDatasetProjectionFiltrationInfo) o;
         return projectedType.deepEqual(otherInfo.projectedType)
                 && Objects.equals(functionCallInfoMap, otherInfo.functionCallInfoMap);
     }
 
     @Override
     public void print(AlgebricksStringBuilderWriter writer) {
-        if (projectedType == ALL_FIELDS_TYPE) {
-            return;
+        if (projectedType != ALL_FIELDS_TYPE) {
+            writer.append(" project (");
+            if (projectedType == EMPTY_TYPE) {
+                writer.append(projectedType.getTypeName());
+            } else {
+                writer.append(getOnelinerSchema(projectedType, new StringBuilder()));
+            }
+            writer.append(')');
         }
 
-        writer.append(" project (");
-        if (projectedType == EMPTY_TYPE) {
-            writer.append(projectedType.getTypeName());
-        } else {
-            writer.append(getOnelinerSchema(projectedType, new StringBuilder()));
+        if (filterExpression != null) {
+            writer.append(" prefix-filter on: ");
+            writer.append(filterExpression.toString());
         }
-        writer.append(')');
     }
 
     @Override
     public void print(JsonGenerator generator) throws IOException {
-        if (projectedType == ALL_FIELDS_TYPE) {
-            return;
+        StringBuilder builder = new StringBuilder();
+        if (projectedType != ALL_FIELDS_TYPE) {
+            if (projectedType == EMPTY_TYPE) {
+                generator.writeStringField("project", projectedType.getTypeName());
+            } else {
+                generator.writeStringField("project", getOnelinerSchema(projectedType, builder));
+            }
         }
-        generator.writeStringField("project", getOnelinerSchema(projectedType, new StringBuilder()));
+
+        if (filterExpression != null) {
+            generator.writeStringField("filter-on", filterExpression.toString());
+        }
     }
 
     protected String getOnelinerSchema(ARecordType type, StringBuilder builder) {
diff --git a/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/evaluators/EvaluatorContext.java b/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/evaluators/EvaluatorContext.java
index 901e788..c74568b 100644
--- a/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/evaluators/EvaluatorContext.java
+++ b/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/evaluators/EvaluatorContext.java
@@ -26,7 +26,7 @@
 import org.apache.hyracks.api.context.IHyracksTaskContext;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 
-public final class EvaluatorContext implements IEvaluatorContext {
+public class EvaluatorContext implements IEvaluatorContext {
 
     private final IServiceContext serviceContext;