Skip to content

Commit

Permalink
[optimise] Rewrite predicates that contain a statically computable po…
Browse files Browse the repository at this point in the history
…sition() expression with a number, e.g. [position() eq 1] becomes [1]. This means that the evaluation of the predicate will now instead have POSITIONAL execution mode instead of BOOLEAN, which in turn means that the predicate can be evaluated once instead of single-stepping over each context item.
  • Loading branch information
adamretter committed Dec 1, 2024
1 parent de45c85 commit bae0899
Showing 1 changed file with 61 additions and 1 deletion.
62 changes: 61 additions & 1 deletion exist-core/src/main/java/org/exist/xquery/Optimizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,20 @@
*/
package org.exist.xquery;

import com.evolvedbinary.j8fu.tuple.Tuple2;
import org.exist.storage.DBBroker;
import org.exist.xquery.functions.array.ArrayConstructor;
import org.exist.xquery.functions.fn.FunPosition;
import org.exist.xquery.pragmas.Optimize;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.Type;

import javax.annotation.Nullable;
import java.util.*;

import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple;
import static org.apache.commons.lang3.ArrayUtils.isNotEmpty;

/**
Expand Down Expand Up @@ -165,7 +169,39 @@ public void visitLocationStep(final LocationStep locationStep) {
}
}

public void visitFilteredExpr(FilteredExpression filtered) {
/**
* Test whether we can optimise position() withing a predicate to a POSITIONAL version of a predicate.
*
* @param predicate the predicate to test
*
* @return the inner expr to be replaced and the literal value to replace it with if it can be optimised, null otherwise.
*/
private @Nullable Tuple2<Expression, LiteralValue> canOptimizeToPositionalPredicate(final Predicate predicate) {
if (predicate.getSubExpressionCount() == 1) {
final Expression predInnerExpr = predicate.getSubExpression(0);
if (predInnerExpr instanceof final ValueComparison valueComparison && valueComparison.getRelation() == Constants.Comparison.EQ) {
final Expression left = valueComparison.getLeft();
final Expression right = valueComparison.getRight();

if (left instanceof final InternalFunctionCall leftInternalFunctionCall && leftInternalFunctionCall.getFunction() instanceof FunPosition
&& right instanceof final LiteralValue rightLiteralValue && rightLiteralValue.returnsType() == Type.INTEGER) {

// NOTE(AR) if the predicate is like [position() eq 1] or [position() = 1] then we could rewrite it to [1]
return Tuple(predInnerExpr, rightLiteralValue);

} else if (left instanceof final LiteralValue leftLiteralValue && leftLiteralValue.returnsType() == Type.INTEGER
&& right instanceof final InternalFunctionCall rightInternalFunctionCall && rightInternalFunctionCall.getFunction() instanceof FunPosition) {

// NOTE(AR) if the predicate is like [1 eq position()] or [1 = position()] then we could rewrite it to [1]
return Tuple(predInnerExpr, leftLiteralValue);
}
}
}
return null;
}

@Override
public void visitFilteredExpr(final FilteredExpression filtered) {
super.visitFilteredExpr(filtered);

// check if filtered expression can be simplified:
Expand Down Expand Up @@ -309,6 +345,30 @@ public void visitGeneralComparison(GeneralComparison comparison) {

public void visitPredicate(Predicate predicate) {
++predicates;

// NOTE(AR) try and optimise position() withing a predicate to a POSITIONAL version of a predicate
@Nullable final Tuple2<Expression, LiteralValue> predOptimizableInnerExpr = canOptimizeToPositionalPredicate(predicate);
if (predOptimizableInnerExpr != null) {
try {
// Replace the predicates expression with a literal number

predicate.replace(predOptimizableInnerExpr._1, predOptimizableInnerExpr._2);

// traverse to outermost predicate and then call analyze! to make sure execution mode is correct
Expression parentExpr = predicate;
Predicate outermostPredicate = predicate;
while ((parentExpr = parentExpr.getParent()) != null) {
if (parentExpr instanceof final Predicate parentPredicate) {
outermostPredicate = parentPredicate;
}
}
outermostPredicate.analyze(new AnalyzeContextInfo(outermostPredicate.getParent(), 0));

} catch (final XPathException e) {
LOG.warn("Failed to optimize expression within predicate: {}: {}", predOptimizableInnerExpr, e.getMessage(), e);
}
}

super.visitPredicate(predicate);
--predicates;
}
Expand Down

0 comments on commit bae0899

Please sign in to comment.