88package org .elasticsearch .compute .operator ;
99
1010import org .elasticsearch .compute .data .Block ;
11+ import org .elasticsearch .compute .data .BlockFactory ;
1112import org .elasticsearch .compute .data .BooleanBlock ;
13+ import org .elasticsearch .compute .data .DoubleBlock ;
14+ import org .elasticsearch .compute .data .DoubleVector ;
1215import org .elasticsearch .compute .data .Page ;
1316import org .elasticsearch .compute .operator .EvalOperator .ExpressionEvaluator ;
1417import org .elasticsearch .core .Releasables ;
1720
1821public class FilterOperator extends AbstractPageMappingOperator {
1922
23+ public static final int SCORE_BLOCK_INDEX = 1 ;
24+
2025 private final EvalOperator .ExpressionEvaluator evaluator ;
26+ private final boolean usesScoring ;
27+ private final BlockFactory blockFactory ;
2128
22- public record FilterOperatorFactory (ExpressionEvaluator .Factory evaluatorSupplier ) implements OperatorFactory {
29+ public record FilterOperatorFactory (ExpressionEvaluator .Factory evaluatorSupplier , boolean usesScoring ) implements OperatorFactory {
2330
2431 @ Override
2532 public Operator get (DriverContext driverContext ) {
26- return new FilterOperator (evaluatorSupplier .get (driverContext ));
33+ return new FilterOperator (evaluatorSupplier .get (driverContext ), usesScoring , driverContext . blockFactory () );
2734 }
2835
2936 @ Override
@@ -32,30 +39,33 @@ public String describe() {
3239 }
3340 }
3441
35- public FilterOperator (EvalOperator . ExpressionEvaluator evaluator ) {
42+ public FilterOperator (ExpressionEvaluator evaluator , boolean usesScoring , BlockFactory blockFactory ) {
3643 this .evaluator = evaluator ;
44+ this .usesScoring = usesScoring ;
45+ this .blockFactory = blockFactory ;
3746 }
3847
3948 @ Override
4049 protected Page process (Page page ) {
4150 int rowCount = 0 ;
4251 int [] positions = new int [page .getPositionCount ()];
4352
44- try (BooleanBlock test = (BooleanBlock ) evaluator .eval (page )) {
45- if (test .areAllValuesNull ()) {
53+ try (BooleanBlock filterResultBlock = (BooleanBlock ) evaluator .eval (page )) {
54+ if (filterResultBlock .areAllValuesNull ()) {
4655 // All results are null which is like false. No values selected.
4756 page .releaseBlocks ();
4857 return null ;
4958 }
59+
5060 // TODO we can detect constant true or false from the type
5161 // TODO or we could make a new method in bool-valued evaluators that returns a list of numbers
5262 for (int p = 0 ; p < page .getPositionCount (); p ++) {
53- if (test .isNull (p ) || test .getValueCount (p ) != 1 ) {
63+ if (filterResultBlock .isNull (p ) || filterResultBlock .getValueCount (p ) != 1 ) {
5464 // Null is like false
5565 // And, for now, multivalued results are like false too
5666 continue ;
5767 }
58- if (test .getBoolean (test .getFirstValueIndex (p ))) {
68+ if (filterResultBlock .getBoolean (filterResultBlock .getFirstValueIndex (p ))) {
5969 positions [rowCount ++] = p ;
6070 }
6171 }
@@ -64,7 +74,14 @@ protected Page process(Page page) {
6474 page .releaseBlocks ();
6575 return null ;
6676 }
67- if (rowCount == page .getPositionCount ()) {
77+ final DoubleBlock scoreBlock ;
78+ if (usesScoring ) {
79+ scoreBlock = evaluator .score (page , blockFactory );
80+ } else {
81+ scoreBlock = null ;
82+ }
83+
84+ if (rowCount == page .getPositionCount () && (usesScoring == false || scoreBlock .asVector ().isConstant ())) {
6885 return page ;
6986 }
7087 positions = Arrays .copyOf (positions , rowCount );
@@ -73,10 +90,15 @@ protected Page process(Page page) {
7390 boolean success = false ;
7491 try {
7592 for (int i = 0 ; i < page .getBlockCount (); i ++) {
76- filteredBlocks [i ] = page .getBlock (i ).filter (positions );
93+ if (usesScoring && i == SCORE_BLOCK_INDEX ) {
94+ filteredBlocks [i ] = createScoresBlock (rowCount , page .getBlock (i ), scoreBlock , positions );
95+ } else {
96+ filteredBlocks [i ] = page .getBlock (i ).filter (positions );
97+ }
7798 }
7899 success = true ;
79100 } finally {
101+ Releasables .closeExpectNoException (scoreBlock );
80102 page .releaseBlocks ();
81103 if (success == false ) {
82104 Releasables .closeExpectNoException (filteredBlocks );
@@ -86,6 +108,15 @@ protected Page process(Page page) {
86108 }
87109 }
88110
111+ private Block createScoresBlock (int rowCount , DoubleBlock originalScoreBlock , DoubleBlock newScoreBlock , int [] positions ) {
112+ // Create a new scores block with the retrieved scores, that will replace the existing one on the result page
113+ DoubleVector .Builder updatedScoresBuilder = blockFactory .newDoubleVectorBuilder (rowCount );
114+ for (int j = 0 ; j < rowCount ; j ++) {
115+ updatedScoresBuilder .appendDouble (originalScoreBlock .getDouble (positions [j ]) + newScoreBlock .getDouble (positions [j ]));
116+ }
117+ return updatedScoresBuilder .build ().asBlock ().filter (positions );
118+ }
119+
89120 @ Override
90121 public String toString () {
91122 return "FilterOperator[" + "evaluator=" + evaluator + ']' ;
0 commit comments