Skip to content

Conversation

smalyshev
Copy link
Contributor

@smalyshev smalyshev commented Sep 17, 2025

  • The remote Enrich hack and the verification workaround that it necessitates are removed
  • Limit with remote Enrich is handled by duplicating the limits around Enrich
  • TopN with remote Enrich is handled by duplicating around Enrich and adjusting projections
  • Introduced CardinalityPreserving interface to mark nodes that preserve cardinality
  • Introduced the capability to run optimizations only on coordinator plan (CoordinatorOnly interface)
  • Added post-optimizer check that ensures remote Enrich is not moved to the coordinator plan

TODO: this does not fix the issue of local (not remote) Lookup Join always being forced on the coordinator by Limits, we may address this in the followup, this one is meaty enough as it is.

Closes #115897
Fixes #118531

@smalyshev smalyshev changed the title Replace remote Enrich hack with proper handling of remote Enrich [WIP] Replace remote Enrich hack with proper handling of remote Enrich Sep 18, 2025
Copy link
Contributor

@alex-spies alex-spies left a comment

Choose a reason for hiding this comment

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

I had a first look at the new optimizer rules and left some comments.

@smalyshev smalyshev changed the title [WIP] Replace remote Enrich hack with proper handling of remote Enrich Replace remote Enrich hack with proper handling of remote Enrich Sep 25, 2025
@smalyshev smalyshev marked this pull request as ready for review September 26, 2025 01:45
@elasticsearchmachine elasticsearchmachine added the Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) label Sep 26, 2025
@elasticsearchmachine
Copy link
Collaborator

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

Copy link
Contributor

@alex-spies alex-spies left a comment

Choose a reason for hiding this comment

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

Done a first pass - need another one. I'm like halfway through it, but haven't fully thought through the added optimizer rules, yet.

I noticed that this doesn't add new optimizer tests, yet. That's something I think we should really add before this can be merged; I'd go and try really hard to find edge cases where the hoisting mechanism, the new local-only topn/limit etc. may break.

(The generative tests will also do that to some extent (let's make sure they actually create remote-only enrichs!), but it's good to have a human-made baseline.)

);
}

protected static Batch<LogicalPlan> operators(boolean local) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Hey, we have 3 mechanisms now that convey whether a rule should be run on the coordinator, the data node, or behave differently depending on global/local: this boolean parameter, the CoordinatorOnly interface, and the method LocalLogicalPlanOptimizer#localOperators which does some special filtering on its own.

I like the CoordinatorOnly interface, but'd prefer we settle on 1 mechanism if possible.

Maybe rather than a CoordinatorOnly interface, we should have a DifferentOnDataNode interface (yes, the name is horrible, I didn't have much time to think :D ) with a method localVersion (or so) that either gives the data node version of the optimizer rule (applies to CombineProjections and PropagateEmptyRelation) or null (applies to all rules marked CoordinatorOnly in this PR).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made LocalLogicalPlanOptimizer#localOperators respect the CoordinatorOnly marker, so that's the same thing now, except for rule that work on both sides, but differently (PropagateEmptyRelation). I agree that it could be refined further but not sure the best way yet.

import java.util.Objects;

public class Limit extends UnaryPlan implements TelemetryAware, PipelineBreaker {
public class Limit extends UnaryPlan implements TelemetryAware, PipelineBreaker, ExecutesOn {
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a little confusing now that this is PipelineBreaker but can still execute on ANY sometimes.

Out of scope, but maybe we'll want to reconcile the two interfaces later; PipelineBreaker could be another enum variant; so we'd have "executes anywhere", "executes only on data nodes", "breaks the pipeline if we're not already on the coordinator", "runs only on the coordinator".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The thing is, commands like LIMIT are "sometimes pipeline breakers" now, but we don't have an interface like that. It may be a good idea to think about how to refine that, but I don't think in this patch.

@smalyshev smalyshev added v9.2.0 auto-backport Automatically create backport pull requests when merged labels Oct 3, 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 >refactoring Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v9.2.0 v9.3.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ESQL: Improve Enrich handling in mapper/remote enrich planning ESQL: incorrect planning of remote enrich
5 participants