2525import org .elasticsearch .compute .data .DocVector ;
2626import org .elasticsearch .compute .data .IntVector ;
2727import org .elasticsearch .compute .data .Page ;
28+ import org .elasticsearch .compute .data .Vector ;
2829import org .elasticsearch .compute .operator .DriverContext ;
2930import org .elasticsearch .compute .operator .EvalOperator ;
3031import org .elasticsearch .core .Releasable ;
@@ -45,12 +46,14 @@ public record ShardConfig(Query query, IndexSearcher searcher) {}
4546
4647 private final BlockFactory blockFactory ;
4748 private final ShardConfig [] shards ;
49+ private final DocScorerVectorProvider docScorerVectorProvider ;
4850
4951 private ShardState [] perShardState = EMPTY_SHARD_STATES ;
5052
51- public LuceneQueryExpressionEvaluator (BlockFactory blockFactory , ShardConfig [] shards ) {
53+ LuceneQueryExpressionEvaluator (BlockFactory blockFactory , ShardConfig [] shards , DocScorerVectorProvider docScorerVectorProvider ) {
5254 this .blockFactory = blockFactory ;
5355 this .shards = shards ;
56+ this .docScorerVectorProvider = docScorerVectorProvider ;
5457 }
5558
5659 @ Override
@@ -65,6 +68,8 @@ public Block eval(Page page) {
6568 }
6669 } catch (IOException e ) {
6770 throw new UncheckedIOException (e );
71+ } finally {
72+ Releasables .closeExpectNoException (docScorerVectorProvider );
6873 }
6974 }
7075
@@ -98,7 +103,7 @@ public Block eval(Page page) {
98103 * common.
99104 * </p>
100105 */
101- private BooleanVector evalSingleSegmentNonDecreasing (DocVector docs ) throws IOException {
106+ private Vector evalSingleSegmentNonDecreasing (DocVector docs ) throws IOException {
102107 ShardState shardState = shardState (docs .shards ().getInt (0 ));
103108 SegmentState segmentState = shardState .segmentState (docs .segments ().getInt (0 ));
104109 int min = docs .docs ().getInt (0 );
@@ -124,32 +129,31 @@ private BooleanVector evalSingleSegmentNonDecreasing(DocVector docs) throws IOEx
124129 * the order that the {@link DocVector} came in.
125130 * </p>
126131 */
127- private BooleanVector evalSlow (DocVector docs ) throws IOException {
132+ private Vector evalSlow (DocVector docs ) throws IOException {
128133 int [] map = docs .shardSegmentDocMapForwards ();
129134 // Clear any state flags from the previous run
130135 int prevShard = -1 ;
131136 int prevSegment = -1 ;
132137 SegmentState segmentState = null ;
133- try (BooleanVector .Builder builder = blockFactory .newBooleanVectorFixedBuilder (docs .getPositionCount ())) {
134- for (int i = 0 ; i < docs .getPositionCount (); i ++) {
135- int shard = docs .shards ().getInt (docs .shards ().getInt (map [i ]));
136- int segment = docs .segments ().getInt (map [i ]);
137- if (segmentState == null || prevShard != shard || prevSegment != segment ) {
138- segmentState = shardState (shard ).segmentState (segment );
139- segmentState .initScorer (docs .docs ().getInt (map [i ]));
140- prevShard = shard ;
141- prevSegment = segment ;
142- }
143- if (segmentState .noMatch ) {
144- builder .appendBoolean (false );
145- } else {
146- segmentState .scoreSingleDocWithScorer (builder , docs .docs ().getInt (map [i ]));
147- }
138+ docScorerVectorProvider .init (docs .getPositionCount ());
139+ for (int i = 0 ; i < docs .getPositionCount (); i ++) {
140+ int shard = docs .shards ().getInt (docs .shards ().getInt (map [i ]));
141+ int segment = docs .segments ().getInt (map [i ]);
142+ if (segmentState == null || prevShard != shard || prevSegment != segment ) {
143+ segmentState = shardState (shard ).segmentState (segment );
144+ segmentState .initScorer (docs .docs ().getInt (map [i ]));
145+ prevShard = shard ;
146+ prevSegment = segment ;
148147 }
149- try (BooleanVector outOfOrder = builder .build ()) {
150- return outOfOrder .filter (docs .shardSegmentDocMapBackwards ());
148+ if (segmentState .noMatch ) {
149+ docScorerVectorProvider .scoreNoHit ();
150+ } else {
151+ segmentState .scoreSingleDocWithScorer (docs .docs ().getInt (map [i ]));
151152 }
152153 }
154+ try (Vector outOfOrder = docScorerVectorProvider .build ()) {
155+ return outOfOrder .filter (docs .shardSegmentDocMapBackwards ());
156+ }
153157 }
154158
155159 @ Override
@@ -244,7 +248,7 @@ BooleanVector scoreDense(int min, int max) throws IOException {
244248 return blockFactory .newConstantBooleanVector (false , length );
245249 }
246250 }
247- try (DenseCollector collector = new DenseCollector (blockFactory , min , max )) {
251+ try (DenseCollector collector = new DenseCollector (blockFactory , docScorerVectorProvider , min , max )) {
248252 bulkScorer .score (collector , ctx .reader ().getLiveDocs (), min , max + 1 );
249253 return collector .build ();
250254 }
@@ -254,17 +258,16 @@ BooleanVector scoreDense(int min, int max) throws IOException {
254258 * Score a vector of doc ids using {@link Scorer}. If you have a dense range of
255259 * doc ids it'd be faster to use {@link #scoreDense}.
256260 */
257- BooleanVector scoreSparse (IntVector docs ) throws IOException {
261+ Vector scoreSparse (IntVector docs ) throws IOException {
258262 initScorer (docs .getInt (0 ));
259263 if (noMatch ) {
260- return blockFactory . newConstantBooleanVector ( false , docs .getPositionCount ());
264+ return docScorerVectorProvider . noneMatch ( docs .getPositionCount ());
261265 }
262- try (BooleanVector .Builder builder = blockFactory .newBooleanVectorFixedBuilder (docs .getPositionCount ())) {
263- for (int i = 0 ; i < docs .getPositionCount (); i ++) {
264- scoreSingleDocWithScorer (builder , docs .getInt (i ));
265- }
266- return builder .build ();
266+ docScorerVectorProvider .init (docs .getPositionCount ());
267+ for (int i = 0 ; i < docs .getPositionCount (); i ++) {
268+ scoreSingleDocWithScorer (docs .getInt (i ));
267269 }
270+ return docScorerVectorProvider .build ();
268271 }
269272
270273 private void initScorer (int minDocId ) throws IOException {
@@ -283,13 +286,17 @@ private void initScorer(int minDocId) throws IOException {
283286 }
284287 }
285288
286- private void scoreSingleDocWithScorer (BooleanVector . Builder builder , int doc ) throws IOException {
289+ private void scoreSingleDocWithScorer (int doc ) throws IOException {
287290 if (scorer .iterator ().docID () == doc ) {
288- builder . appendBoolean ( true );
291+ docScorerVectorProvider . scoreHit ( scorer );
289292 } else if (scorer .iterator ().docID () > doc ) {
290- builder . appendBoolean ( false );
293+ docScorerVectorProvider . scoreNoHit ( );
291294 } else {
292- builder .appendBoolean (scorer .iterator ().advance (doc ) == doc );
295+ if (scorer .iterator ().advance (doc ) == doc ) {
296+ docScorerVectorProvider .scoreHit (scorer );
297+ } else {
298+ docScorerVectorProvider .scoreNoHit ();
299+ }
293300 }
294301 }
295302 }
@@ -305,17 +312,22 @@ private void scoreSingleDocWithScorer(BooleanVector.Builder builder, int doc) th
305312 static class DenseCollector implements LeafCollector , Releasable {
306313 private final BooleanVector .FixedBuilder builder ;
307314 private final int max ;
315+ private final DocScorerVectorProvider docScorerVectorProvider ;
316+ private Scorable scorable ;
308317
309318 int next ;
310319
311- DenseCollector (BlockFactory blockFactory , int min , int max ) {
320+ DenseCollector (BlockFactory blockFactory , DocScorerVectorProvider docScorerVectorProvider , int min , int max ) {
312321 this .builder = blockFactory .newBooleanVectorFixedBuilder (max - min + 1 );
313322 this .max = max ;
323+ this .docScorerVectorProvider = docScorerVectorProvider ;
314324 next = min ;
315325 }
316326
317327 @ Override
318- public void setScorer (Scorable scorable ) {}
328+ public void setScorer (Scorable scorable ) {
329+ this .scorable = scorable ;
330+ }
319331
320332 @ Override
321333 public void collect (int doc ) {
@@ -342,6 +354,62 @@ public void close() {
342354 }
343355 }
344356
357+ private interface DocScorerVectorProvider extends Releasable {
358+
359+ Vector noneMatch (int docs );
360+
361+ void init (int numDocs );
362+
363+ void scoreHit (Scorable scorable );
364+
365+ void scoreNoHit ();
366+
367+ Vector build ();
368+ }
369+
370+ static class NonScoringDocScorerVectorProvider implements DocScorerVectorProvider {
371+
372+ private final BlockFactory blockFactory ;
373+ private BooleanVector .Builder builder ;
374+
375+ NonScoringDocScorerVectorProvider (BlockFactory blockFactory ) {
376+ this .blockFactory = blockFactory ;
377+ }
378+
379+ @ Override
380+ public Vector noneMatch (int docs ) {
381+ return blockFactory .newConstantBooleanVector (false , docs );
382+ }
383+
384+ @ Override
385+ public void init (int numDocs ) {
386+ builder = blockFactory .newBooleanVectorFixedBuilder (numDocs );
387+ }
388+
389+ @ Override
390+ public void scoreHit (Scorable scorable ) {
391+ assert builder != null : "init must be called before scoring" ;
392+ builder .appendBoolean (true );
393+ }
394+
395+ @ Override
396+ public void scoreNoHit () {
397+ assert builder != null : "init must be called before scoring" ;
398+ builder .appendBoolean (false );
399+ }
400+
401+ @ Override
402+ public Vector build () {
403+ assert builder != null : "init must be called before scoring" ;
404+ return builder .build ();
405+ }
406+
407+ @ Override
408+ public void close () {
409+ Releasables .closeExpectNoException (builder );
410+ }
411+ }
412+
345413 public static class Factory implements EvalOperator .ExpressionEvaluator .Factory {
346414 private final ShardConfig [] shardConfigs ;
347415
@@ -351,7 +419,11 @@ public Factory(ShardConfig[] shardConfigs) {
351419
352420 @ Override
353421 public EvalOperator .ExpressionEvaluator get (DriverContext context ) {
354- return new LuceneQueryExpressionEvaluator (context .blockFactory (), shardConfigs );
422+ return new LuceneQueryExpressionEvaluator (
423+ context .blockFactory (),
424+ shardConfigs ,
425+ new NonScoringDocScorerVectorProvider (context .blockFactory ())
426+ );
355427 }
356428 }
357429}
0 commit comments