Skip to content

Commit 6d92767

Browse files
authored
[8.17] Fix early termination in LuceneSourceOperator (elastic#123197) (elastic#123839)
The LuceneSourceOperator is supposed to terminate when it reaches the limit; unfortunately, we don't have a test to cover this. Due to this bug, we continue scanning all segments, even though we discard the results as the limit was reached. This can cause performance issues for simple queries like FROM .. | LIMIT 10, when Lucene indices are on the warm or cold tier. I will submit a follow-up PR to ensure we only collect up to the limit across multiple drivers.
1 parent 37230dc commit 6d92767

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

docs/changelog/123197.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 123197
2+
summary: Fix early termination in `LuceneSourceOperator`
3+
area: ES|QL
4+
type: bug
5+
issues: []

x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSourceOperator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public void collect(int doc) {
100100

101101
@Override
102102
public boolean isFinished() {
103-
return doneCollecting;
103+
return doneCollecting || remainingDocs <= 0;
104104
}
105105

106106
@Override

x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneSourceOperatorTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.compute.operator.DriverContext;
2626
import org.elasticsearch.compute.operator.Operator;
2727
import org.elasticsearch.compute.operator.OperatorTestCase;
28+
import org.elasticsearch.compute.operator.SourceOperator;
2829
import org.elasticsearch.compute.operator.TestResultPageSinkOperator;
2930
import org.elasticsearch.core.IOUtils;
3031
import org.elasticsearch.index.cache.query.TrivialQueryCachingPolicy;
@@ -112,6 +113,27 @@ public void testShardDataPartitioning() {
112113
testSimple(driverContext(), size, limit);
113114
}
114115

116+
public void testEarlyTermination() {
117+
int size = between(1_000, 20_000);
118+
int limit = between(10, size);
119+
LuceneSourceOperator.Factory factory = simple(randomFrom(DataPartitioning.values()), size, limit);
120+
try (SourceOperator sourceOperator = factory.get(driverContext())) {
121+
assertFalse(sourceOperator.isFinished());
122+
int collected = 0;
123+
while (sourceOperator.isFinished() == false) {
124+
Page page = sourceOperator.getOutput();
125+
if (page != null) {
126+
collected += page.getPositionCount();
127+
page.releaseBlocks();
128+
}
129+
if (collected >= limit) {
130+
assertTrue("source operator is not finished after reaching limit", sourceOperator.isFinished());
131+
assertThat(collected, equalTo(limit));
132+
}
133+
}
134+
}
135+
}
136+
115137
public void testEmpty() {
116138
testSimple(driverContext(), 0, between(10, 10_000));
117139
}

0 commit comments

Comments
 (0)