Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QL: Introduce common analyzer base class #65325

Merged
merged 4 commits into from
Nov 23, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 abstract static 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);
}
}
4 changes: 2 additions & 2 deletions x-pack/plugin/sql/qa/server/src/main/resources/date.csv-spec
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ SELECT TRUNCATE(YEAR(TODAY() - INTERVAL 50 YEARS) / 1000) AS result;


currentDateFilter
SELECT first_name FROM test_emp WHERE hire_date > CURRENT_DATE() - INTERVAL 35 YEARS ORDER BY first_name ASC LIMIT 10;
SELECT first_name FROM test_emp WHERE hire_date > CURRENT_DATE() - INTERVAL 44 YEARS ORDER BY first_name ASC LIMIT 10;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as it happens an entry in the dataset failed this condition today (21/11/1985) - I've updated the filter to remain the same for another 9 years :)


first_name
-----------------
Expand Down Expand Up @@ -265,4 +265,4 @@ HAVING DATE_PARSE(DATETIME_FORMAT(MAX(birth_date), 'dd/MM/uuuu'), 'dd/MM/uuuu')
1963-03-21 00:00:00.000Z | 03
1962-12-29 00:00:00.000Z | 12
null | null
;
;
Loading