Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
d777561
Add check that remote enrich stays on remote side
smalyshev Sep 4, 2025
a93438f
Merge branch 'main' into remote-enrich-check
smalyshev Sep 8, 2025
b6244e5
Make it more generic
smalyshev Sep 9, 2025
a787ae8
[CI] Auto commit changes from spotless
Sep 9, 2025
6d638be
Verifier refactor
smalyshev Sep 9, 2025
95ef823
Merge branch 'main' into remote-enrich-check
smalyshev Sep 9, 2025
2490f60
Merge branch 'main' into remote-enrich-check
smalyshev Sep 12, 2025
4e16026
Fix the fix for https://github.com/elastic/elasticsearch/issues/118531
smalyshev Sep 12, 2025
e3324c0
Merge branch 'main' into remote-enrich-check
smalyshev Sep 17, 2025
dd7dd79
Remove old hacks
smalyshev Sep 17, 2025
31df078
Replace remote Enrich hack with proper handling of remote Enrich
smalyshev Sep 17, 2025
8dde748
Don't stop for ANY enrich
smalyshev Sep 17, 2025
d053fe4
Add TopN handling
smalyshev Sep 18, 2025
9b185e8
Merge branch 'main' into entich-remote-unhack
smalyshev Sep 18, 2025
93c827d
Oops, forgot the file
smalyshev Sep 18, 2025
a78a2c8
fix multiple topNs
smalyshev Sep 18, 2025
ea421ca
fix tests
smalyshev Sep 18, 2025
e70043e
test fixes
smalyshev Sep 19, 2025
9edcd72
Ban Limit + MvExpand before remote Enrich
smalyshev Sep 19, 2025
7c6c9b1
Update docs/changelog/135051.yaml
smalyshev Sep 19, 2025
3f2e2e9
spotless
smalyshev Sep 19, 2025
3d909ce
Move check pre optimizer
smalyshev Sep 19, 2025
ddc5815
Merge branch 'remote-enrich-limit' into entich-remote-unhack
smalyshev Sep 19, 2025
587ae4c
fix tests
smalyshev Sep 19, 2025
f9686e5
[CI] Update transport version definitions
Sep 20, 2025
30146a1
test fixes
smalyshev Sep 22, 2025
8dc2101
[CI] Update transport version definitions
Sep 22, 2025
77acee7
Merge branch 'main' into entich-remote-unhack
smalyshev Sep 22, 2025
346d17f
Update x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/…
smalyshev Sep 22, 2025
54d3aec
fix merge
smalyshev Sep 22, 2025
3d51a5c
test fixes
smalyshev Sep 22, 2025
f2e9fde
spotless
smalyshev Sep 22, 2025
f762627
Fix tests
smalyshev Sep 22, 2025
9bbdb26
Cleanup
smalyshev Sep 22, 2025
10581b8
Fix test
smalyshev Sep 22, 2025
47694c4
[CI] Auto commit changes from spotless
Sep 23, 2025
0a7cc56
Add project handling
smalyshev Sep 23, 2025
3c6e699
[CI] Update transport version definitions
Sep 23, 2025
6eb2468
Add two topN test
smalyshev Sep 23, 2025
0c1ee72
Merge branch 'main' into entich-remote-unhack
smalyshev Sep 23, 2025
abc1a7d
Clean up plan/optimizer structure
smalyshev Sep 24, 2025
da237a2
Introduce CardinalityExpanding
smalyshev Sep 24, 2025
809e528
Switch to CardinalityPreserving
smalyshev Sep 24, 2025
605b0c8
Block multiple TopN handling as it's semantically unsound
smalyshev Sep 24, 2025
6b7838e
Remove todo
smalyshev Sep 24, 2025
810e795
[Build] Update checkstyle from 10.3 to 11.0.1
breskeby Sep 24, 2025
0ae16c2
Merge branch 'pr/135381' into entich-remote-unhack
smalyshev Sep 24, 2025
819760e
Remove exclusion
smalyshev Sep 24, 2025
7baa484
Merge branch 'main' into entich-remote-unhack
smalyshev Sep 24, 2025
1bd78e6
Add missing dependency verification
breskeby Sep 24, 2025
0b70d07
Merge branch 'pr/135381' into entich-remote-unhack
smalyshev Sep 24, 2025
ec179e1
[Build] update eclipse formatter used by spotless
breskeby Sep 24, 2025
e1e4f21
Merge branch 'pr/135382' into entich-remote-unhack
smalyshev Sep 24, 2025
62f72b1
spotless
smalyshev Sep 24, 2025
3ab2bf7
Merge branch 'main' into entich-remote-unhack
smalyshev Sep 25, 2025
15f9cbf
cleanup
smalyshev Sep 25, 2025
616021d
Cleanups
smalyshev Sep 25, 2025
255bce5
clean test
smalyshev Sep 25, 2025
c8a109b
moar tests
smalyshev Sep 25, 2025
7b28e9f
oops typo
smalyshev Sep 25, 2025
3af3540
Merge branch 'main' into entich-remote-unhack
smalyshev Sep 25, 2025
00bc8b7
Merge branch 'main' into entich-remote-unhack
smalyshev Oct 3, 2025
6df9352
Feedback, pass 1
smalyshev Oct 3, 2025
3f58415
More feedback
smalyshev Oct 3, 2025
8c0c305
Remove limit optimization - data node optimizer will take care of it
smalyshev Oct 3, 2025
2145a40
moar tests
smalyshev Oct 3, 2025
74c8a9d
avoid forbidden lore
smalyshev Oct 3, 2025
69c2225
More tests
smalyshev Oct 4, 2025
e9160a5
TopN tests
smalyshev Oct 6, 2025
9b40f1d
Merge branch 'main' into entich-remote-unhack
smalyshev Oct 6, 2025
4c052ec
fix test
smalyshev Oct 7, 2025
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 @@ -402,6 +402,61 @@ public void testTopNThenEnrichRemote() {
assertThat(executionInfo.clusterAliases(), equalTo(Set.of("", "c1", "c2")));
assertCCSExecutionInfoDetails(executionInfo);
}

// No renames, no KEEP - this is required to verify that ENRICH does not break sort with fields it overrides
query = """
FROM *:events,events
| eval ip= TO_STR(host)
| SORT timestamp, user, ip
| LIMIT 5
| ENRICH _remote:hosts
""";
try (EsqlQueryResponse resp = runQuery(query, requestIncludeMeta)) {
assertThat(
getValuesList(resp),
equalTo(
List.of(
List.of("192.168.1.2", 1L, "andres", "192.168.1.2", "Windows"),
List.of("192.168.1.3", 1L, "matthew", "192.168.1.3", "MacOS"),
Arrays.asList("192.168.1.25", 1L, "park", (String) null, (String) null),
List.of("192.168.1.5", 2L, "akio", "192.168.1.5", "Android"),
List.of("192.168.1.6", 2L, "sergio", "192.168.1.6", "iOS")
)
)
);
EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
assertThat(executionInfo.includeCCSMetadata(), equalTo(responseExpectMeta));
assertThat(executionInfo.clusterAliases(), equalTo(Set.of("", "c1", "c2")));
assertCCSExecutionInfoDetails(executionInfo);
}
}

public void testLimitWithCardinalityChange() {
String query = String.format(Locale.ROOT, """
FROM *:events,events
| eval ip= TO_STR(host)
| LIMIT 10
| WHERE user != "andres"
| %s
""", enrichHosts(Enrich.Mode.REMOTE));
// This is currently not supported, because WHERE is not cardinality preserving
var error = expectThrows(VerificationException.class, () -> runQuery(query, randomBoolean()).close());
assertThat(error.getMessage(), containsString("ENRICH with remote policy can't be executed after [LIMIT 10]@3:3"));
}

public void testTopNTwiceThenEnrichRemote() {
String query = String.format(Locale.ROOT, """
FROM *:events,events
| eval ip= TO_STR(host)
| SORT timestamp
| LIMIT 9
| SORT ip, user
| LIMIT 5
| ENRICH _remote:hosts
""", enrichHosts(Enrich.Mode.REMOTE));
// This is currently not supported, because we can not handle double topN with remote enrich
var error = expectThrows(VerificationException.class, () -> runQuery(query, randomBoolean()).close());
assertThat(error.getMessage(), containsString("ENRICH with remote policy can't be executed after [SORT timestamp]"));
}

public void testLimitThenEnrichRemote() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
*/
public interface PostOptimizationVerificationAware {

/**
* Marker interface for verifiers that should only be run on Coordinator
*/
interface CoordinatorOnly extends PostOptimizationVerificationAware {}

/**
* Validates the implementing expression - discovered failures are reported to the given
* {@link Failures} class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

import org.elasticsearch.xpack.esql.VerificationException;
import org.elasticsearch.xpack.esql.common.Failures;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.OptimizerRules;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.PropagateEmptyRelation;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.ReplaceStatsFilteredAggWithEval;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.ReplaceStringCasingWithInsensitiveRegexMatch;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.IgnoreNullMetrics;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.InferIsNotNull;
Expand All @@ -24,6 +24,7 @@
import org.elasticsearch.xpack.esql.rule.Rule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.elasticsearch.common.util.CollectionUtils.arrayAsArrayList;
Expand All @@ -39,7 +40,7 @@
*/
public class LocalLogicalPlanOptimizer extends ParameterizedRuleExecutor<LogicalPlan, LocalLogicalOptimizerContext> {

private final LogicalVerifier verifier = LogicalVerifier.INSTANCE;
private final LogicalVerifier verifier = LogicalVerifier.LOCAL_INSTANCE;

private static final List<Batch<LogicalPlan>> RULES = arrayAsArrayList(
new Batch<>(
Expand All @@ -53,7 +54,7 @@ public class LocalLogicalPlanOptimizer extends ParameterizedRuleExecutor<Logical
new ReplaceDateTruncBucketWithRoundTo()
),
localOperators(),
cleanup()
localCleanup()
);

public LocalLogicalPlanOptimizer(LocalLogicalOptimizerContext localLogicalOptimizerContext) {
Expand All @@ -75,8 +76,7 @@ private static Batch<LogicalPlan> localOperators() {
for (var r : rules) {
switch (r) {
case PropagateEmptyRelation ignoredPropagate -> newRules.add(new LocalPropagateEmptyRelation());
// skip it: once a fragment contains an Agg, this can no longer be pruned, which the rule can do
case ReplaceStatsFilteredAggWithEval ignoredReplace -> {
case OptimizerRules.CoordinatorOnly ignored -> {
}
default -> newRules.add(r);
}
Expand All @@ -88,9 +88,18 @@ private static Batch<LogicalPlan> localOperators() {
return operators.with(newRules.toArray(Rule[]::new));
}

@SuppressWarnings("unchecked")
private static Batch<LogicalPlan> localCleanup() {
var cleanup = cleanup();
return cleanup.with(
// Remove CoordinatorOnly rules
Arrays.stream(cleanup.rules()).filter(r -> r instanceof OptimizerRules.CoordinatorOnly == false).toArray(Rule[]::new)
);
}

public LogicalPlan localOptimize(LogicalPlan plan) {
LogicalPlan optimized = execute(plan);
Failures failures = verifier.verify(optimized, true, plan.output());
Failures failures = verifier.verify(optimized, plan.output());
if (failures.hasFailures()) {
throw new VerificationException(failures);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class LocalPhysicalPlanOptimizer extends ParameterizedRuleExecutor<Physic

private static final List<Batch<PhysicalPlan>> RULES = rules(true);

private final PhysicalVerifier verifier = PhysicalVerifier.INSTANCE;
private final PhysicalVerifier verifier = PhysicalVerifier.LOCAL_INSTANCE;

public LocalPhysicalPlanOptimizer(LocalPhysicalOptimizerContext context) {
super(context);
Expand All @@ -47,7 +47,7 @@ public PhysicalPlan localOptimize(PhysicalPlan plan) {
}

PhysicalPlan verify(PhysicalPlan optimizedPlan, List<Attribute> expectedOutputAttributes) {
Failures failures = verifier.verify(optimizedPlan, true, expectedOutputAttributes);
Failures failures = verifier.verify(optimizedPlan, expectedOutputAttributes);
if (failures.hasFailures()) {
throw new VerificationException(failures);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
import org.elasticsearch.xpack.esql.optimizer.rules.logical.CombineBinaryComparisons;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.CombineDisjunctions;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.CombineEvals;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.CombineLimitTopN;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.CombineProjections;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.ConstantFolding;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.ExtractAggregateCommonFilter;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.FoldNull;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.HoistRemoteEnrichLimit;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.HoistRemoteEnrichTopN;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.LiteralsOnTheRight;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.PartiallyFoldCase;
import org.elasticsearch.xpack.esql.optimizer.rules.logical.PropagateEmptyRelation;
Expand Down Expand Up @@ -93,8 +96,8 @@
* <li>{@link LogicalPlanOptimizer#cleanup()} Which can replace sorts+limit with a TopN</li>
* </ul>
*
* <p>Note that the {@link LogicalPlanOptimizer#operators(boolean)} and {@link LogicalPlanOptimizer#cleanup()} steps are reapplied at the
* {@link LocalLogicalPlanOptimizer} layer.</p>
* <p>Note that the {@link LogicalPlanOptimizer#operators(boolean)} and {@link LogicalPlanOptimizer#cleanup()} steps are reapplied
* at the {@link LocalLogicalPlanOptimizer} layer.</p>
*/
public class LogicalPlanOptimizer extends ParameterizedRuleExecutor<LogicalPlan, LogicalOptimizerContext> {

Expand All @@ -115,7 +118,7 @@ public LogicalPlanOptimizer(LogicalOptimizerContext optimizerContext) {
public LogicalPlan optimize(LogicalPlan verified) {
var optimized = execute(verified);

Failures failures = verifier.verify(optimized, false, verified.output());
Failures failures = verifier.verify(optimized, verified.output());
if (failures.hasFailures()) {
throw new VerificationException(failures);
}
Expand Down Expand Up @@ -166,6 +169,7 @@ protected static Batch<LogicalPlan> substitutions() {
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.

return new Batch<>(
"Operator Optimization",
new HoistRemoteEnrichLimit(),
new CombineProjections(local),
new CombineEvals(),
new PropagateEmptyRelation(),
Expand Down Expand Up @@ -212,6 +216,13 @@ protected static Batch<LogicalPlan> operators(boolean local) {
}

protected static Batch<LogicalPlan> cleanup() {
return new Batch<>("Clean Up", new ReplaceLimitAndSortAsTopN(), new ReplaceRowAsLocalRelation(), new PropgateUnmappedFields());
return new Batch<>(
"Clean Up",
new ReplaceLimitAndSortAsTopN(),
new HoistRemoteEnrichTopN(),
new ReplaceRowAsLocalRelation(),
new PropgateUnmappedFields(),
new CombineLimitTopN()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,18 @@
import org.elasticsearch.xpack.esql.capabilities.PostOptimizationVerificationAware;
import org.elasticsearch.xpack.esql.common.Failures;
import org.elasticsearch.xpack.esql.optimizer.rules.PlanConsistencyChecker;
import org.elasticsearch.xpack.esql.plan.logical.Enrich;
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;

public final class LogicalVerifier extends PostOptimizationPhasePlanVerifier<LogicalPlan> {
public static final LogicalVerifier LOCAL_INSTANCE = new LogicalVerifier(true);
public static final LogicalVerifier INSTANCE = new LogicalVerifier(false);

public static final LogicalVerifier INSTANCE = new LogicalVerifier();

private LogicalVerifier() {}

@Override
boolean skipVerification(LogicalPlan optimizedPlan, boolean skipRemoteEnrichVerification) {
if (skipRemoteEnrichVerification) {
// AwaitsFix https://github.com/elastic/elasticsearch/issues/118531
var enriches = optimizedPlan.collectFirstChildren(Enrich.class::isInstance);
if (enriches.isEmpty() == false && ((Enrich) enriches.get(0)).mode() == Enrich.Mode.REMOTE) {
return true;
}
}
return false;
private LogicalVerifier(boolean isLocal) {
super(isLocal);
}

@Override
Expand All @@ -44,14 +33,16 @@ void checkPlanConsistency(LogicalPlan optimizedPlan, Failures failures, Failures
PlanConsistencyChecker.checkPlan(p, depFailures);

if (failures.hasFailures() == false) {
if (p instanceof PostOptimizationVerificationAware pova) {
if (p instanceof PostOptimizationVerificationAware pova
&& (pova instanceof PostOptimizationVerificationAware.CoordinatorOnly && isLocal) == false) {
pova.postOptimizationVerification(failures);
}
if (p instanceof PostOptimizationPlanVerificationAware popva) {
checkers.add(popva.postOptimizationPlanVerification());
}
p.forEachExpression(ex -> {
if (ex instanceof PostOptimizationVerificationAware va) {
if (ex instanceof PostOptimizationVerificationAware va
&& (va instanceof PostOptimizationVerificationAware.CoordinatorOnly && isLocal) == false) {
va.postOptimizationVerification(failures);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public PhysicalPlan optimize(PhysicalPlan plan) {
}

PhysicalPlan verify(PhysicalPlan optimizedPlan, List<Attribute> expectedOutputAttributes) {
Failures failures = verifier.verify(optimizedPlan, false, expectedOutputAttributes);
Failures failures = verifier.verify(optimizedPlan, expectedOutputAttributes);
if (failures.hasFailures()) {
throw new VerificationException(failures);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,19 @@
import org.elasticsearch.xpack.esql.core.expression.Attribute;
import org.elasticsearch.xpack.esql.core.expression.Expressions;
import org.elasticsearch.xpack.esql.optimizer.rules.PlanConsistencyChecker;
import org.elasticsearch.xpack.esql.plan.logical.Enrich;
import org.elasticsearch.xpack.esql.plan.physical.EnrichExec;
import org.elasticsearch.xpack.esql.plan.logical.ExecutesOn;
import org.elasticsearch.xpack.esql.plan.physical.FieldExtractExec;
import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;

import static org.elasticsearch.xpack.esql.common.Failure.fail;

/** Physical plan verifier. */
public final class PhysicalVerifier extends PostOptimizationPhasePlanVerifier<PhysicalPlan> {
public static final PhysicalVerifier LOCAL_INSTANCE = new PhysicalVerifier(true);
public static final PhysicalVerifier INSTANCE = new PhysicalVerifier(false);

public static final PhysicalVerifier INSTANCE = new PhysicalVerifier();

private PhysicalVerifier() {}

@Override
boolean skipVerification(PhysicalPlan optimizedPlan, boolean skipRemoteEnrichVerification) {
if (skipRemoteEnrichVerification) {
// AwaitsFix https://github.com/elastic/elasticsearch/issues/118531
var enriches = optimizedPlan.collectFirstChildren(EnrichExec.class::isInstance);
if (enriches.isEmpty() == false && ((EnrichExec) enriches.get(0)).mode() == Enrich.Mode.REMOTE) {
return true;
}
}
return false;
private PhysicalVerifier(boolean isLocal) {
super(isLocal);
}

@Override
Expand All @@ -54,6 +43,19 @@ void checkPlanConsistency(PhysicalPlan optimizedPlan, Failures failures, Failure
);
}
}

// This check applies only for coordinator physical plans (isLocal == false)
if (isLocal == false && p instanceof ExecutesOn ex && ex.executesOn() == ExecutesOn.ExecuteLocation.REMOTE) {
failures.add(
fail(
p,
"Physical plan contains remote executing operation [{}] in local part. "
+ "This usually means this command is incompatible with some of the preceding commands.",
p.nodeName()
)
);
}

PlanConsistencyChecker.checkPlan(p, depFailures);

if (failures.hasFailures() == false) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@
*/
public abstract class PostOptimizationPhasePlanVerifier<P extends QueryPlan<P>> {

// Are we verifying the global plan (coordinator) or a local plan (data node)?
protected final boolean isLocal;

protected PostOptimizationPhasePlanVerifier(boolean isLocal) {
this.isLocal = isLocal;
}

/** Verifies the optimized plan */
public Failures verify(P optimizedPlan, boolean skipRemoteEnrichVerification, List<Attribute> expectedOutputAttributes) {
public Failures verify(P optimizedPlan, List<Attribute> expectedOutputAttributes) {
Failures failures = new Failures();
Failures depFailures = new Failures();
if (skipVerification(optimizedPlan, skipRemoteEnrichVerification)) {
return failures;
}

checkPlanConsistency(optimizedPlan, failures, depFailures);

Expand All @@ -47,8 +51,6 @@ public Failures verify(P optimizedPlan, boolean skipRemoteEnrichVerification, Li
return failures;
}

abstract boolean skipVerification(P optimizedPlan, boolean skipRemoteEnrichVerification);

abstract void checkPlanConsistency(P optimizedPlan, Failures failures, Failures depFailures);

private static void verifyOutputNotChanged(QueryPlan<?> optimizedPlan, List<Attribute> expectedOutputAttributes, Failures failures) {
Expand All @@ -67,7 +69,7 @@ private static void verifyOutputNotChanged(QueryPlan<?> optimizedPlan, List<Attr
.stream()
.anyMatch(x -> x.name().equals(ProjectAwayColumns.ALL_FIELDS_PROJECTED));
// LookupJoinExec represents the lookup index with EsSourceExec and this is turned into EsQueryExec by
// ReplaceSourceAttributes. Because InsertFieldExtractions doesn't apply to lookup indices, the
// ReplaceSourceAttributes. Because InsertFieldExtraction doesn't apply to lookup indices, the
// right hand side will only have the EsQueryExec providing the _doc attribute and nothing else.
// We perform an optimizer run on every fragment. LookupJoinExec also contains such a fragment,
// and currently it only contains an EsQueryExec after optimization.
Expand Down
Loading