>From Preetham Poluparthi <[email protected]>:

Preetham Poluparthi has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20828?usp=email )


Change subject: [ASTERIXDB-3677][COMP] Optimize only for {}
......................................................................

[ASTERIXDB-3677][COMP] Optimize only for {}

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

Ext-ref: MB-70076
Change-Id: Ida835829ef744424d385f38899a9788469253f2c
---
M asterixdb/NOTICE
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java
A 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InlineIfMissingFunctionRule.java
M hyracks-fullstack/NOTICE
M 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonExpressionsRule.java
6 files changed, 160 insertions(+), 2 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/28/20828/1

diff --git a/asterixdb/NOTICE b/asterixdb/NOTICE
index 5118782..a44569b 100644
--- a/asterixdb/NOTICE
+++ b/asterixdb/NOTICE
@@ -1,5 +1,5 @@
 Apache AsterixDB
-Copyright 2015-2025 The Apache Software Foundation
+Copyright 2015-2026 The Apache Software Foundation

 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
index 3cea23f..68cdf30 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
@@ -177,6 +177,7 @@
         List<IAlgebraicRewriteRule> typeInfer = new LinkedList<>();
         typeInfer.add(new InlineUnnestFunctionRule());
         typeInfer.add(new InferTypesRule());
+        // maybe here
         typeInfer.add(new CheckFilterExpressionTypeRule());
         return typeInfer;
     }
@@ -347,6 +348,7 @@
         planCleanupRules.add(new 
IntroduceDynamicTypeCastForExternalFunctionRule());
         planCleanupRules.add(new RemoveUnusedAssignAndAggregateRule());
         planCleanupRules.add(new RemoveCartesianProductWithEmptyBranchRule());
+        //        planCleanupRules.add(new InlineIfMissingFunctionRule());
         planCleanupRules.add(new InjectTypeCastForFunctionArgumentsRule());
         planCleanupRules.add(new InjectTypeCastForUnionRule());
         // (1) RemoveOrReplaceDefaultNullCastRule and (2) 
RemoveUnknownCheckForKnownTypesRule has to run in this order
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java
index 98c54e6..eb494ae 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java
@@ -30,6 +30,8 @@
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
 import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.IAType;
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.commons.lang3.mutable.MutableObject;
@@ -115,6 +117,18 @@
             BiIntPredicate argChecker, IOptimizationContext context) throws 
AlgebricksException {
         IVariableTypeEnvironment env = op.computeInputTypeEnvironment(context);
         IAType producedType = (IAType) env.getType(func);
+
+        for (Mutable<ILogicalExpression> argRef : func.getArguments()) {
+            ILogicalExpression argExpr = argRef.get();
+            IAType type = (IAType) env.getType(argExpr);
+            if (type.getTypeTag() == ATypeTag.OBJECT) {
+                ARecordType recordType = (ARecordType) type;
+                if (!recordType.isOpen() && recordType.getFieldNames().length 
== 0) {
+                    producedType = new ARecordType(null, new String[0], new 
IAType[0], true);
+                }
+            }
+        }
+
         List<Mutable<ILogicalExpression>> argRefs = func.getArguments();
         int argSize = argRefs.size();
         boolean rewritten = false;
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InlineIfMissingFunctionRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InlineIfMissingFunctionRule.java
new file mode 100644
index 0000000..24b71e7
--- /dev/null
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InlineIfMissingFunctionRule.java
@@ -0,0 +1,130 @@
+/*
+ * 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.optimizer.rules;
+
+import java.util.List;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.IAType;
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class InlineIfMissingFunctionRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
+            throws AlgebricksException {
+
+        ILogicalOperator op = opRef.getValue();
+        if (op.getInputs().isEmpty()) {
+            return false;
+        }
+        // Populates the latest type information.
+        context.computeAndSetTypeEnvironmentForOperator(op);
+        if (op.acceptExpressionTransform(exprRef -> inlineIfMissing(op, 
exprRef, context))) {
+            // Generates the up-to-date type information.
+            context.computeAndSetTypeEnvironmentForOperator(op);
+            // 1. keep {} inlined. MUST
+            // 2a. optimize only for {} using a rule
+            // 2b. optimize only for {} in 
InjectTypeCastForFunctionArgumentsRule = know when a cast can't be done and use 
generalized.
+            // e.g. if-missing-or-null(to-object(a), cast({})); cast to 
open-rec instead of cast to {"id": int}
+
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean inlineIfMissing(ILogicalOperator op, 
Mutable<ILogicalExpression> exprRef,
+            IOptimizationContext context) throws AlgebricksException {
+
+        ILogicalExpression expr = exprRef.getValue();
+        if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return false;
+        }
+        boolean rewritten = false;
+        AbstractFunctionCallExpression func = (AbstractFunctionCallExpression) 
expr;
+
+        for (Mutable<ILogicalExpression> argRef : func.getArguments()) {
+            if (inlineIfMissing(op, argRef, context)) {
+                context.computeAndSetTypeEnvironmentForOperator(op);
+                rewritten = true;
+            }
+        }
+        rewritten |= rewriteFunction(op, exprRef, context);
+        return rewritten;
+    }
+
+    private static boolean rewriteFunction(ILogicalOperator op, 
Mutable<ILogicalExpression> exprRef,
+            IOptimizationContext context) throws AlgebricksException {
+
+        ILogicalExpression expr = exprRef.getValue();
+        AbstractFunctionCallExpression func = (AbstractFunctionCallExpression) 
expr;
+
+        if (func.getFunctionIdentifier() != 
BuiltinFunctions.IF_MISSING_OR_NULL) {
+            return false;
+        }
+
+        List<Mutable<ILogicalExpression>> argRefList = func.getArguments();
+        if (argRefList.isEmpty()) {
+            exprRef.setValue(ConstantExpression.NULL);
+            return true;
+        }
+
+        IVariableTypeEnvironment env = op.computeInputTypeEnvironment(context);
+
+        IAType type = (IAType) env.getType(argRefList.get(0).get());
+
+        if (type.getTypeTag() != ATypeTag.MISSING && type.getTypeTag() != 
ATypeTag.NULL
+                && type.getTypeTag() != ATypeTag.ANY) {
+            exprRef.setValue(argRefList.get(0).get());
+            return true;
+        }
+
+        List<Mutable<ILogicalExpression>> newArgsList = func.getArguments();
+
+        for (Mutable<ILogicalExpression> argRef : argRefList) {
+            ILogicalExpression argExpr = argRef.getValue();
+            IAType argType = (IAType) env.getType(argExpr);
+
+            if (argType.getTypeTag() == ATypeTag.ANY) {
+                newArgsList.add(argRef);
+            } else if (argType.getTypeTag() != ATypeTag.MISSING && 
argType.getTypeTag() != ATypeTag.NULL) {
+                newArgsList.add(argRef);
+                break;
+            }
+
+        }
+
+        argRefList.clear();
+        argRefList.addAll(newArgsList);
+        return true;
+
+    }
+
+}
diff --git a/hyracks-fullstack/NOTICE b/hyracks-fullstack/NOTICE
index 722db88..9050c82 100644
--- a/hyracks-fullstack/NOTICE
+++ b/hyracks-fullstack/NOTICE
@@ -1,5 +1,5 @@
 Apache Hyracks and Algebricks
-Copyright 2015-2025 The Apache Software Foundation
+Copyright 2015-2026 The Apache Software Foundation

 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonExpressionsRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonExpressionsRule.java
index e2ba557..eca1802 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonExpressionsRule.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonExpressionsRule.java
@@ -89,6 +89,8 @@
     // Set of operators for which common subexpression elimination should not 
be performed.
     private static final Set<LogicalOperatorTag> ignoreOps = new HashSet<>(6);

+    private static final Set<String> NON_EXTRACTABLE_FUNCTION_NAMES = new 
HashSet<>();
+
     static {
         ignoreOps.add(LogicalOperatorTag.UNNEST);
         ignoreOps.add(LogicalOperatorTag.UNNEST_MAP);
@@ -97,6 +99,8 @@
         ignoreOps.add(LogicalOperatorTag.AGGREGATE);
         ignoreOps.add(LogicalOperatorTag.RUNNINGAGGREGATE);
         ignoreOps.add(LogicalOperatorTag.WINDOW); //TODO: can extract from 
partition/order/frame expressions
+
+        NON_EXTRACTABLE_FUNCTION_NAMES.add("cast");
     }

     @Override
@@ -260,6 +264,14 @@
         return modified;
     }

+    private static boolean isExprExtractable(ILogicalExpression expr) {
+        if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return false;
+        }
+        AbstractFunctionCallExpression funcExpr = 
(AbstractFunctionCallExpression) expr;
+        return 
!NON_EXTRACTABLE_FUNCTION_NAMES.contains(funcExpr.getFunctionIdentifier().getName());
+    }
+
     private class CommonExpressionSubstitutionVisitor implements 
ILogicalExpressionReferenceTransform {

         private IOptimizationContext context;

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20828?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: asterixdb
Gerrit-Branch: trinity
Gerrit-Change-Id: Ida835829ef744424d385f38899a9788469253f2c
Gerrit-Change-Number: 20828
Gerrit-PatchSet: 1
Gerrit-Owner: Preetham Poluparthi <[email protected]>

Reply via email to