Skip to content

Commit 9cff1ac

Browse files
authored
ESQL: Fix a bug in LuceneQueryExpressionEvaluator (#117252) (#117279) (#118078)
* ESQL: Fix a bug in LuceneQueryExpressionEvaluator This fixes Lucene usage bug in `LuceneQueryExpressionEvaluator`, the evaluator we plan to use to run things like `MATCH` when we *can't* push it to a source operator. That'll be useful for things like: ``` FROM foo | STATS COUNT(), COUNT() WHERE MATCH(message, "error") ``` Explanation: When using Lucene's `Scorer` and `BulkScorer` you must stay on the same thread. It's a rule. Most of the time nothing bad happens if you shift threads, but sometimes things explode and Lucene doesn't work. Driver can shift from one thread to another - that's just how it's designed. It's a "yield after running a while" kind of thing. In tests we sometimes get a version of the `Scorer` and `BulkScorer` that assert that you don't shift threads. That is what caused this test failure. Anyway! This builds protection into `LuceneQueryExpressionEvaluator` so that if it *does* shift threads then it'll rebuild the `Scorer` and `BulkScorer`. That makes the test happy and makes even the most grump Lucene object happy. Closes #116879
1 parent a8e3bac commit 9cff1ac

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,18 +191,29 @@ SegmentState segmentState(int segment) throws IOException {
191191
private class SegmentState {
192192
private final Weight weight;
193193
private final LeafReaderContext ctx;
194+
194195
/**
195196
* Lazily initialed {@link Scorer} for this. {@code null} here means uninitialized
196197
* <strong>or</strong> that {@link #noMatch} is true.
197198
*/
198199
private Scorer scorer;
199200

201+
/**
202+
* Thread that initialized the {@link #scorer}.
203+
*/
204+
private Thread scorerThread;
205+
200206
/**
201207
* Lazily initialed {@link BulkScorer} for this. {@code null} here means uninitialized
202208
* <strong>or</strong> that {@link #noMatch} is true.
203209
*/
204210
private BulkScorer bulkScorer;
205211

212+
/**
213+
* Thread that initialized the {@link #bulkScorer}.
214+
*/
215+
private Thread bulkScorerThread;
216+
206217
/**
207218
* Set to {@code true} if, in the process of building a {@link Scorer} or {@link BulkScorer},
208219
* the {@link Weight} tells us there aren't any matches.
@@ -223,7 +234,10 @@ BooleanVector scoreDense(int min, int max) throws IOException {
223234
if (noMatch) {
224235
return blockFactory.newConstantBooleanVector(false, length);
225236
}
226-
if (bulkScorer == null) {
237+
if (bulkScorer == null || // The bulkScorer wasn't initialized
238+
Thread.currentThread() != bulkScorerThread // The bulkScorer was initialized on a different thread
239+
) {
240+
bulkScorerThread = Thread.currentThread();
227241
bulkScorer = weight.bulkScorer(ctx);
228242
if (bulkScorer == null) {
229243
noMatch = true;
@@ -257,8 +271,11 @@ private void initScorer(int minDocId) throws IOException {
257271
if (noMatch) {
258272
return;
259273
}
260-
if (scorer == null || scorer.iterator().docID() > minDocId) {
261-
// The previous block might have been beyond this one, reset the scorer and try again.
274+
if (scorer == null || // Scorer not initialized
275+
scorerThread != Thread.currentThread() || // Scorer initialized on a different thread
276+
scorer.iterator().docID() > minDocId // The previous block came "after" this one
277+
) {
278+
scorerThread = Thread.currentThread();
262279
scorer = weight.scorer(ctx);
263280
if (scorer == null) {
264281
noMatch = true;

0 commit comments

Comments
 (0)