Skip to content

Commit 156ed98

Browse files
Enhance logical plan explicitly projecting join keys (#88833)
1 parent 0599919 commit 156ed98

File tree

2 files changed

+35
-20
lines changed

2 files changed

+35
-20
lines changed

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/PostAnalyzer.java

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.elasticsearch.xpack.ql.tree.NodeUtils;
2121
import org.elasticsearch.xpack.ql.tree.Source;
2222
import org.elasticsearch.xpack.ql.type.DataTypes;
23-
import org.elasticsearch.xpack.ql.util.Holder;
2423

2524
import static java.util.Collections.emptyList;
2625
import static org.elasticsearch.xpack.ql.tree.Source.synthetic;
@@ -46,29 +45,25 @@ public LogicalPlan postAnalyze(LogicalPlan plan, EqlConfiguration configuration)
4645

4746
// implicit project + fetch size (if needed)
4847

49-
Holder<Boolean> hasJoin = new Holder<>(Boolean.FALSE);
50-
5148
Source projectCtx = synthetic("<implicit-project>");
52-
if (plan.anyMatch(Sequence.class::isInstance)) {
53-
hasJoin.set(Boolean.TRUE);
49+
final boolean isSequence = plan.anyMatch(Sequence.class::isInstance);
50+
final boolean isSample = plan.anyMatch(Sample.class::isInstance);
51+
if (isSequence || isSample) {
5452
// first per KeyedFilter
5553
plan = plan.transformUp(KeyedFilter.class, k -> {
56-
Project p = new Project(projectCtx, k.child(), k.extractionAttributes());
57-
58-
// TODO: this could be incorporated into the query generation
59-
LogicalPlan fetchSize = new LimitWithOffset(
60-
synthetic("<fetch-size>"),
61-
new Literal(synthetic("<fetch-value>"), configuration.fetchSize(), DataTypes.INTEGER),
62-
p
63-
);
64-
65-
return new KeyedFilter(k.source(), fetchSize, k.keys(), k.timestamp(), k.tiebreaker());
54+
LogicalPlan newPlan = new Project(projectCtx, k.child(), isSequence ? k.extractionAttributes() : k.keys());
55+
if (isSequence) {
56+
// TODO: this could be incorporated into the query generation
57+
newPlan = new LimitWithOffset(
58+
synthetic("<fetch-size>"),
59+
new Literal(synthetic("<fetch-value>"), configuration.fetchSize(), DataTypes.INTEGER),
60+
newPlan
61+
);
62+
}
63+
return new KeyedFilter(k.source(), newPlan, k.keys(), k.timestamp(), k.tiebreaker());
6664
});
67-
}
68-
69-
hasJoin.set(hasJoin.get() || plan.anyMatch(Sample.class::isInstance));
70-
// in case of event queries, filter everything
71-
if (hasJoin.get() == false) {
65+
} else {
66+
// in case of event queries, filter everything
7267
plan = new Project(projectCtx, plan, emptyList());
7368
}
7469
}

x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/optimizer/OptimizerTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,26 @@ public void testReduceBinaryComparisons() {
701701
assertEquals(6, ((Literal) gte.right()).value());
702702
}
703703

704+
public void testSampleOptimizations() {
705+
String q = "sample by user_name [any where true] by bool [any where true] by bool";
706+
LogicalPlan plan = sample(accept(q));
707+
assertTrue(plan instanceof Sample);
708+
List<LogicalPlan> projects = plan.collectFirstChildren(x -> x instanceof Project);
709+
assertEquals(2, projects.size());
710+
for (LogicalPlan sub : projects) {
711+
Project proj = (Project) sub;
712+
// ensure that only join keys are explicitly projected (ie. all the other fields are excluded)
713+
assertEquals(2, proj.projections().size());
714+
List<String> projections = proj.projections()
715+
.stream()
716+
.map(FieldAttribute.class::cast)
717+
.map(FieldAttribute::name)
718+
.collect(toList());
719+
assertTrue(projections.contains("user_name"));
720+
assertTrue(projections.contains("bool"));
721+
}
722+
}
723+
704724
private AbstractJoin randomSequenceOrSample(KeyedFilter rule1, KeyedFilter rule2) {
705725
Sequence seq = sequence(rule1, rule2);
706726
Sample sample = sample(rule1, rule2);

0 commit comments

Comments
 (0)