Skip to content

Conversation

kanoshiou
Copy link
Contributor

@kanoshiou kanoshiou commented Apr 30, 2025

Because we aim to minimize the number of attributes required from field_caps at pre-analysis time, a removal check helps eliminate fields defined by users (such as eval). However, commands like lookup join and enrich can introduce fields with the same names as user-defined fields. To accommodate this, we ensure that aliases are not removed from the attributes list when a subsequent JOIN occurs.

For the query:

from message_types | eval type = 1 | lookup join message_types_lookup on message | drop message | grok type "%{WORD:b}" | stats x = max(b) | keep x 

The plan grok type "%{WORD:b} passes the removal check and initiates alias removal down the tree. However, the removal process should halt at lookup join due to the reason mentioned above. The issue arises because the original code allows progression to eval type = 1, which inadvertently removes the type field. As a result, the field type ends up being of type integer defined by eval type = 1, rather than preserving the keyword type field type obtained from message_types_lookup.

Closes #127468

@elasticsearchmachine elasticsearchmachine added needs:triage Requires assignment of a team area label external-contributor Pull request authored by a developer outside the Elasticsearch team v9.1.0 labels Apr 30, 2025
@PeteGillinElastic PeteGillinElastic added :Analytics/ES|QL AKA ESQL and removed needs:triage Requires assignment of a team area label labels May 1, 2025
@elasticsearchmachine elasticsearchmachine added the Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) label May 1, 2025
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-analytical-engine (Team:Analytics)

@astefan astefan self-requested a review May 5, 2025 13:42
@astefan astefan self-assigned this May 5, 2025
@astefan astefan added the >bug label May 5, 2025
@astefan
Copy link
Contributor

astefan commented May 5, 2025

buildkite test this

@kanoshiou
Copy link
Contributor Author

I'm really confused. I can get a result of 4325287503714500000 when I run the query on my local machine, but the test says it should be 4325287503714500302. It seems the test result is right, I will update the branch.

@astefan astefan requested a review from luigidellaquila May 5, 2025 16:31
Copy link
Contributor

@astefan astefan left a comment

Choose a reason for hiding this comment

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

@kanoshiou I really appreciate you provided this PR and you tried to understand where the fix needs to go.

Unfortunately, this is a trivial fix that doesn't quite catch the true reason for the initial failure.

The essence of the failure is the fact that lookup join can override the type user-provided field with its own type field. The type from eval is of type integer while the type that comes from the lookup join is of type keyword. Because the list of field names didn't contain type the Analyzer couldn't learn about that type that exists in message_types_lookup and the only thing it knew about its type is that it comes from eval.

lookup join (like enrich and maybe inlinestats) are special in the sense that they add some columns to the result, so some of the rules we have in EsqlSession.fieldNames need to be adjusted to account for these special characteristics. Because lookup join can add a field of the same name as type coming from an eval before the said lookup join command, we have a special check in fieldNames that forbids the removal of those Aliases.

Your proposed solution does this:

  • places the input references of grok in a new variable, instead of the referenceBuilder that was used before
  • the special check above for lookup join is not applied to referenceBuilder for grok because the input reference is not there anymore
  • you add to referenceBuilder the content of the grok-special variable

This is a bypass of the lookup join special removal check.

Instead, let the grok references in referenceBuilder where they are and don't let the special lookup join check remove it. The issue is with the lookup join check, not with grok, so adjust that one. I have the feeling that check is applicable in other cases, only that we didn't catch those yet.

@kanoshiou
Copy link
Contributor Author

@astefan Thank you for your review and for taking the time to provide such a detailed explanation of the issue's root cause. Your insights have been incredibly helpful, and I truly appreciate your guidance on my code, it has given me a much deeper understanding. I’ve learned a lot from your feedback!

I have reverted the bypass and implemented a modification that I believe addresses the issue. If there are any areas that need improvement or further adjustments, please let me know, I’d be happy to refine it further.

@astefan
Copy link
Contributor

astefan commented May 9, 2025

@kanoshiou I have a simpler suggestion for the change in EsqlSession. Instead of the original code in main

if (canRemoveAliases[0] && couldOverrideAliases(p)) { 

we can do:

if (canRemoveAliases[0] && p.anyMatch(c -> couldOverrideAliases(c))) { 

It will slightly change some of the existent tests in IndexResolverFieldNamesTests in terms of which eval generated field name will be put in the list of fieldNames, but I think that's acceptable.

Please, try it out and let me know your thoughts.

@astefan
Copy link
Contributor

astefan commented May 9, 2025

buildkite test this

@astefan astefan self-requested a review May 9, 2025 09:28
@kanoshiou
Copy link
Contributor Author

Thank you for your review and suggestions, @astefan!

I believe the statement p.anyMatch(c -> couldOverrideAliases(c)) will always return true since there must be an UnresolvedRelation at the end. If we disregard the UnresolvedRelation case, I believe your code essentially avoids alias removal whenever there is a lookup join or enrich operation in the tree. However, this contradicts the original intent of minimizing the number of attributes required from field_caps at pre-analysis time.

@astefan
Copy link
Contributor

astefan commented May 9, 2025

I believe the statement p.anyMatch(c -> couldOverrideAliases(c)) will always return true since there must be an UnresolvedRelation at the end

Indeed, I forgot about this part. UnresolvedRelation needs to also be accounted for in couldOverrideAliases method.

I believe your code essentially avoids alias removal whenever there is a lookup join or enrich operation in the tree

Yes

However, this contradicts the original intent of minimizing the number of attributes required from field_caps at pre-analysis time.

Yes, it's a fine balance. Being too aggressive in minimizing the list of fields could lead to some of the issues we've had recently. Having more fields in that list, but still avoiding to ask for all the fields (*) which is what we had before, is still an improvement.

kanoshiou added 3 commits May 12, 2025 11:05
…moval # Conflicts: #	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@astefan astefan self-requested a review May 20, 2025 09:55
@astefan astefan added auto-backport Automatically create backport pull requests when merged v8.19.0 v9.0.2 labels May 20, 2025
@kanoshiou
Copy link
Contributor Author

Thank you for your review @astefan! Your suggestion has been applied in ee9de1c.

@astefan
Copy link
Contributor

astefan commented May 20, 2025

buildkite test this

Copy link
Contributor

@astefan astefan left a comment

Choose a reason for hiding this comment

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

LGTM

kanoshiou added 2 commits May 20, 2025 20:19
…moval # Conflicts: #	x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java #	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java #	x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
@astefan
Copy link
Contributor

astefan commented May 20, 2025

@kanoshiou please, look into the conflicts. Most likely, they are coming from the freshly merged PR.

@kanoshiou
Copy link
Contributor Author

@astefan conflicts resolved.

@astefan
Copy link
Contributor

astefan commented May 20, 2025

buildkite test this

@astefan astefan merged commit 88b61e3 into elastic:main May 21, 2025
19 checks passed
@elasticsearchmachine
Copy link
Collaborator

💚 Backport successful

Status Branch Result
8.19
9.0
@kanoshiou
Copy link
Contributor Author

Thank you @astefan!

astefan added a commit to astefan/elasticsearch that referenced this pull request May 21, 2025
--------- Co-authored-by: Andrei Stefan <astefan@users.noreply.github.com>
elasticsearchmachine pushed a commit that referenced this pull request May 21, 2025
--------- Co-authored-by: kanoshiou <73424326+kanoshiou@users.noreply.github.com>
elasticsearchmachine pushed a commit that referenced this pull request May 21, 2025
* ESQL: Avoid unintended attribute removal (#127563) --------- Co-authored-by: Andrei Stefan <astefan@users.noreply.github.com> * Checkstyle * Checkstyle again * Slightly change the test because 8.19 has fewer indices in the index pattern used (9.x also has host_inventory index). --------- Co-authored-by: kanoshiou <73424326+kanoshiou@users.noreply.github.com>
elasticsearchmachine pushed a commit that referenced this pull request Jul 4, 2025
@astefan astefan added the v8.18.4 label Jul 4, 2025
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 >bug external-contributor Pull request authored by a developer outside the Elasticsearch team Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v8.18.4 v8.19.0 v9.0.2 v9.1.0

4 participants