Skip to content

Commit

Permalink
QL: Introduce common analyzer base class
Browse files Browse the repository at this point in the history
Extract the analyzer base classes into a common project similar to the
Optimizer ones.
Extract AddMissingEqualsOnBoolFields a common rule to be used across

Close #63695
  • Loading branch information
costin committed Nov 20, 2020
1 parent 533f77b commit a0de6ce
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
import java.util.Collection;
import java.util.LinkedHashSet;

import static java.util.Collections.singletonList;
import static java.util.Arrays.asList;
import static org.elasticsearch.xpack.eql.analysis.AnalysisUtils.resolveAgainstList;
import static org.elasticsearch.xpack.ql.analyzer.AnalyzerRules.AddMissingEqualsToBoolField;

public class Analyzer extends RuleExecutor<LogicalPlan> {

Expand All @@ -42,7 +43,10 @@ protected Iterable<RuleExecutor<LogicalPlan>.Batch> batches() {
new ResolveRefs(),
new ResolveFunctions());

return singletonList(resolution);
Batch cleanup = new Batch("Finish Analysis", Limiter.ONCE,
new AddMissingEqualsToBoolField());

return asList(resolution, cleanup);
}

public LogicalPlan analyze(LogicalPlan plan) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@
import org.elasticsearch.xpack.eql.util.MathUtils;
import org.elasticsearch.xpack.eql.util.StringUtils;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.FieldAttribute;
import org.elasticsearch.xpack.ql.expression.Literal;
import org.elasticsearch.xpack.ql.expression.NamedExpression;
import org.elasticsearch.xpack.ql.expression.Order;
import org.elasticsearch.xpack.ql.expression.Order.NullsPosition;
import org.elasticsearch.xpack.ql.expression.Order.OrderDirection;
import org.elasticsearch.xpack.ql.expression.predicate.Predicates;
import org.elasticsearch.xpack.ql.expression.predicate.logical.And;
import org.elasticsearch.xpack.ql.expression.predicate.logical.BinaryLogic;
import org.elasticsearch.xpack.ql.expression.predicate.logical.Not;
import org.elasticsearch.xpack.ql.expression.predicate.logical.Or;
import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull;
Expand Down Expand Up @@ -75,9 +73,6 @@ protected Iterable<RuleExecutor<LogicalPlan>.Batch> batches() {
new ReplaceSurrogateFunction(),
new ReplaceRegexMatch());

Batch syntactic = new Batch("Rewrite Syntactic Sugar", Limiter.ONCE,
new AddMissingEquals());

Batch operators = new Batch("Operator Optimization",
new ConstantFolding(),
// boolean
Expand Down Expand Up @@ -109,7 +104,7 @@ protected Iterable<RuleExecutor<LogicalPlan>.Batch> batches() {
Batch label = new Batch("Set as Optimized", Limiter.ONCE,
new SetAsOptimized());

return asList(substitutions, syntactic, operators, constraints, operators, ordering, local, label);
return asList(substitutions, operators, constraints, operators, ordering, local, label);
}

private static class ReplaceWildcards extends OptimizerRule<Filter> {
Expand Down Expand Up @@ -153,33 +148,6 @@ private static boolean isWildcard(Expression expr) {
}
}

private static class AddMissingEquals extends OptimizerRule<Filter> {

@Override
protected LogicalPlan rule(Filter filter) {
// check the condition itself
Expression condition = replaceRawBoolFieldWithEquals(filter.condition());
// otherwise look for binary logic
if (condition == filter.condition()) {
condition = condition.transformUp(b ->
b.replaceChildren(asList(replaceRawBoolFieldWithEquals(b.left()), replaceRawBoolFieldWithEquals(b.right())))
, BinaryLogic.class);
}

if (condition != filter.condition()) {
filter = new Filter(filter.source(), filter.child(), condition);
}
return filter;
}

private Expression replaceRawBoolFieldWithEquals(Expression e) {
if (e instanceof FieldAttribute) {
e = new Equals(e.source(), e, Literal.of(e, Boolean.TRUE));
}
return e;
}
}

private static class ReplaceNullChecks extends OptimizerRule<Filter> {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

package org.elasticsearch.xpack.ql.analyzer;

import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.FieldAttribute;
import org.elasticsearch.xpack.ql.expression.Literal;
import org.elasticsearch.xpack.ql.expression.predicate.logical.BinaryLogic;
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.Equals;
import org.elasticsearch.xpack.ql.plan.logical.Filter;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
import org.elasticsearch.xpack.ql.rule.Rule;

import static java.util.Arrays.asList;

public final class AnalyzerRules {

public static class AddMissingEqualsToBoolField extends AnalyzerRule<Filter> {

@Override
protected LogicalPlan rule(Filter filter) {
// check the condition itself
Expression condition = replaceRawBoolFieldWithEquals(filter.condition());
// otherwise look for binary logic
if (condition == filter.condition()) {
condition = condition.transformUp(b ->
b.replaceChildren(asList(replaceRawBoolFieldWithEquals(b.left()), replaceRawBoolFieldWithEquals(b.right())))
, BinaryLogic.class);
}

if (condition != filter.condition()) {
filter = new Filter(filter.source(), filter.child(), condition);
}
return filter;
}

private Expression replaceRawBoolFieldWithEquals(Expression e) {
if (e instanceof FieldAttribute) {
e = new Equals(e.source(), e, Literal.of(e, Boolean.TRUE));
}
return e;
}

@Override
protected boolean skipResolved() {
return false;
}
}


public static abstract class AnalyzerRule<SubPlan extends LogicalPlan> extends Rule<SubPlan, LogicalPlan> {

// transformUp (post-order) - that is first children and then the node
// but with a twist; only if the tree is not resolved or analyzed
@Override
public final LogicalPlan apply(LogicalPlan plan) {
return plan.transformUp(t -> t.analyzed() || skipResolved() && t.resolved() ? t : rule(t), typeToken());
}

@Override
protected abstract LogicalPlan rule(SubPlan plan);

protected boolean skipResolved() {
return true;
}
}

public abstract static class BaseAnalyzerRule extends AnalyzerRule<LogicalPlan> {

@Override
protected LogicalPlan rule(LogicalPlan plan) {
if (plan.childrenResolved() == false) {
return plan;
}
return doRule(plan);
}

protected abstract LogicalPlan doRule(LogicalPlan plan);
}
}
Loading

0 comments on commit a0de6ce

Please sign in to comment.