Skip to content

Conversation

carlosdelest
Copy link
Member

@carlosdelest carlosdelest commented Sep 23, 2024

Adds a match() function, behind snapshot builds.

This is similar to the work done on #112590. It adds a new FullTextFunction for match queries.

This PR modifies the ESQL grammar to allow match to be a valid function identifier - as the MATCH operator introduced the MATCH token.

Some reworking needed to be done in FullTextFunction for adding multiple ordinal parameters support.

It has the same limitations as QSTR - FullTextFunctions need to be pushed down to Lucene as part of the local physical plan optimizing. We're limiting the commands that can be used before the function, so we don't allow commands that may alter the existing columns (DROP, KEEP, EVAL).

@carlosdelest carlosdelest added auto-backport Automatically create backport pull requests when merged v8.16.0 labels Sep 23, 2024
return resolution;
}

public static TypeResolution isNotFoldable(Expression e, String operationName, ParamOrdinal paramOrd) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed isNotFoldable() method as it was unused, and created isNotNull()

// Source commands
assertEquals("1:13: [QSTR] function cannot be used after SHOW", error("show info | where qstr(\"8.16.0\")"));
assertEquals("1:13: [QSTR] function cannot be used after SHOW", error("show info | where qstr(\"Anna\")"));
assertEquals("1:17: [QSTR] function cannot be used after ROW", error("row a= \"Anna\" | where qstr(\"Anna\")"));
Copy link
Member Author

Choose a reason for hiding this comment

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

Tests for match and qstr have been refactored so they are shared where possible

Copy link
Member

@fang-xing-esql fang-xing-esql left a comment

Choose a reason for hiding this comment

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

Thank you for addressing some of the comments from yesterday @carlosdelest . Some of them that you might have missed are highlighted below.


private static void checkDisjunction(Set<Failure> failures, Or or, Expression left, Expression right) {
left.forEachDown(FullTextFunction.class, ftf -> {
if (canPushToSource(right, x -> false) == false) {
Copy link
Member

Choose a reason for hiding this comment

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

Calling canPushToSource from the coordinator is not quite right. I'd suggests to disable Match with disjunctions for now as a known limitation, and open a separate issue to find a solution in general.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, let's disable this entirely and use a follow up issue. Done in 0dd782c

}

@Override
public String functionName() {
Copy link
Member

Choose a reason for hiding this comment

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

Could you please change the name of MatchFunction and QueryStringFunction to Match and QueryString respectively?

Don't forget the change the name of these two classes.

Comment on lines 745 to 825
public void testQueryStringWithDisjunctionsThatCannotBePushedDown() {
assumeTrue("skipping because QSTR is not enabled", EsqlCapabilities.Cap.QSTR_FUNCTION.isEnabled());

checkWithDisjunctionsThatCannotBePushedDown("QSTR", "qstr(\"first_name: Anna\")");
}

public void testMatchWithDisjunctionsThatCannotBePushedDown() {
assumeTrue("skipping because MATCH function is not enabled", EsqlCapabilities.Cap.MATCH_FUNCTION.isEnabled());

checkWithDisjunctionsThatCannotBePushedDown("MATCH", "match(first_name, \"Anna\")");
}

private void checkWithDisjunctionsThatCannotBePushedDown(String functionName, String functionInvocation) {
VerificationException ve = expectThrows(
VerificationException.class,
() -> plannerOptimizer.plan("from test | where " + functionInvocation + " or length(first_name) > 12", IS_SV_STATS)
);
assertThat(
ve.getMessage(),
containsString(
LoggerMessageFormat.format(
null,
"1:19: Invalid condition [{} or length(first_name) > 12]. "
+ "Function {} can't be used as part of an or condition that includes [length(first_name) > 12]",
functionInvocation,
functionName
)
)
);
ve = expectThrows(
VerificationException.class,
() -> plannerOptimizer.plan(
"from test | where (" + functionInvocation + " and emp_no < 1000) or (length(first_name) > 12 and emp_no > 1000)",
IS_SV_STATS
)
);
assertThat(
ve.getMessage(),
containsString(
LoggerMessageFormat.format(
null,
"1:19: Invalid condition [({} and emp_no < 1000) or (length(first_name) > 12 and emp_no > 1000)]. "
+ "Function {} can't be used as part of an or condition that includes [length(first_name) > 12 and emp_no > 1000]",
functionInvocation,
functionName
)
)
);
}

public void testMatchFunctionDisjunctionNonPushableClauses() {
assumeTrue("skipping because MATCH function is not enabled", EsqlCapabilities.Cap.MATCH_FUNCTION.isEnabled());
String queryText = """
from test
| where match(first_name, "Peter") or length(last_name) > 10
""";

VerificationException ve = expectThrows(VerificationException.class, () -> plannerOptimizer.plan(queryText, IS_SV_STATS));
assertThat(
ve.getMessage(),
containsString(
"Invalid condition [match(first_name, \"Peter\") or length(last_name) > 10]. "
+ "Function MATCH can't be used as part of an or condition that includes [length(last_name) > 10]"
)
);
}

public void testMatchFunctionIsNotNullable() {
assumeTrue("skipping because MATCH function is not enabled", EsqlCapabilities.Cap.MATCH_FUNCTION.isEnabled());

String queryText = """
row n = null | eval text = n + 5 | where match(text::keyword, "Anna")
""";

VerificationException ve = expectThrows(VerificationException.class, () -> plannerOptimizer.plan(queryText, IS_SV_STATS));
assertThat(
ve.getMessage(),
containsString("[MATCH] cannot operate on [text::keyword], which is not a field from an index mapping")
);
}

Copy link
Member

Choose a reason for hiding this comment

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

Move these tests catching VerificationException to LogicalPlanOptimizerTests.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done in 87807ed

* @param action the action to execute for each parent of the specified typeToken
*/
@SuppressWarnings("unchecked")
public <E extends T> E forEachParent(Class<E> typeToken, BiConsumer<E, ? super T> action) {
Copy link
Member

Choose a reason for hiding this comment

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

Could this be moved the Verifier? Just want to be cautious, Node is an important class, we change it only if it is necessary.

Don't forget to move this into Verifier, and keep Node unchanged.

@carlosdelest
Copy link
Member Author

Sorry @fang-xing-esql , but I didn't see any additional comments nor can I find them now. Thanks for pasting them again.

Don't forget the change the name of these two classes.

Done in d4e6256

Don't forget to move this into Verifier, and keep Node unchanged.

OK, moved in 03a0246 and simplified in 2e5ce4e

@carlosdelest
Copy link
Member Author

@fang-xing-esql , I think I have addressed all comments as of now.

If there are no more comments to address, let me know and I'll add the test-release label for a final check.

@carlosdelest carlosdelest added the test-release Trigger CI checks against release build label Oct 10, 2024
@carlosdelest
Copy link
Member Author

@elasticmachine update branch

@carlosdelest
Copy link
Member Author

@fang-xing-esql , I added the test-release label and the tests are green. Are there any other remaining concern for this function to be merged?

# Conflicts:
#	x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java
Copy link
Member

@fang-xing-esql fang-xing-esql left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks a lot for all the efforts and being patient with me @carlosdelest !

I wonder if there is an issue created for keeping track of full text functions with disjunctions(OR) yet? Can we have it linked to this PR, so that we don't forget about it? Thanks again!

@carlosdelest carlosdelest merged commit a262eb6 into elastic:main Oct 14, 2024
17 checks passed
@elasticsearchmachine
Copy link
Collaborator

💔 Backport failed

The backport operation could not be completed due to the following error:

An unexpected error occurred when attempting to backport this PR.

You can use sqren/backport to manually backport by running backport --upstream elastic/elasticsearch --pr 113374

@carlosdelest
Copy link
Member Author

💚 All backports created successfully

Status Branch Result
8.x

Questions ?

Please refer to the Backport tool documentation

carlosdelest added a commit to carlosdelest/elasticsearch that referenced this pull request Oct 14, 2024
davidkyle pushed a commit to davidkyle/elasticsearch that referenced this pull request Oct 14, 2024
georgewallace pushed a commit to georgewallace/elasticsearch that referenced this pull request Oct 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Analytics/ES|QL AKA ESQL auto-backport Automatically create backport pull requests when merged backport pending >feature Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) test-release Trigger CI checks against release build v8.16.0 v9.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants