99package org .elasticsearch .lucene .queries ;
1010
1111import org .apache .lucene .index .DocValuesSkipper ;
12+ import org .apache .lucene .index .NumericDocValues ;
1213import org .apache .lucene .search .DocIdSetIterator ;
1314import org .apache .lucene .search .TwoPhaseIterator ;
1415
2021final class TimestampIterator extends TwoPhaseIterator {
2122
2223 private final RangeNoGapsApproximation approximation ;
23- private final TwoPhaseIterator innerTwoPhase ;
24+ private final NumericDocValues timestamps ;
25+
26+ private final long minTimestamp ;
27+ private final long maxTimestamp ;
2428
2529 TimestampIterator (
26- TwoPhaseIterator twoPhase ,
30+ NumericDocValues timestamps ,
2731 DocValuesSkipper timestampSkipper ,
2832 DocValuesSkipper primaryFieldSkipper ,
2933 long minTimestamp ,
3034 long maxTimestamp
3135 ) {
32- super (new RangeNoGapsApproximation (twoPhase . approximation () , timestampSkipper , primaryFieldSkipper , minTimestamp , maxTimestamp ));
36+ super (new RangeNoGapsApproximation (timestamps , timestampSkipper , primaryFieldSkipper , minTimestamp , maxTimestamp ));
3337 this .approximation = (RangeNoGapsApproximation ) approximation ();
34- this .innerTwoPhase = twoPhase ;
38+ this .timestamps = timestamps ;
39+ this .minTimestamp = minTimestamp ;
40+ this .maxTimestamp = maxTimestamp ;
3541 }
3642
3743 static final class RangeNoGapsApproximation extends DocIdSetIterator {
@@ -48,6 +54,7 @@ static final class RangeNoGapsApproximation extends DocIdSetIterator {
4854 // Track a decision for all doc IDs between the current doc ID and upTo inclusive.
4955 Match match = Match .MAYBE ;
5056 int upTo = -1 ;
57+ int primaryFieldUpTo = -1 ;
5158
5259 RangeNoGapsApproximation (
5360 DocIdSetIterator innerApproximation ,
@@ -78,13 +85,10 @@ public int advance(int target) throws IOException {
7885 while (true ) {
7986 if (target > upTo ) {
8087 timestampSkipper .advance (target );
81- // If target doesn't have a value and is between two blocks, it is possible that advance()
82- // moved to a block that doesn't contain `target`.
83- target = Math .max (target , timestampSkipper .minDocID (0 ));
84- if (target == NO_MORE_DOCS ) {
85- return doc = NO_MORE_DOCS ;
86- }
8788 upTo = timestampSkipper .maxDocID (0 );
89+ if (upTo == DocIdSetIterator .NO_MORE_DOCS ) {
90+ return doc = DocIdSetIterator .NO_MORE_DOCS ;
91+ }
8892 match = match (0 );
8993
9094 // If we have a YES or NO decision, see if we still have the same decision on a higher
@@ -107,18 +111,17 @@ public int advance(int target) throws IOException {
107111 }
108112 break ;
109113 case NO :
110- if (match == Match . NO ) {
114+ if (target > primaryFieldUpTo ) {
111115 primaryFieldSkipper .advance (target );
112- int betterUptTo = -1 ;
113116 for (int level = 0 ; level < primaryFieldSkipper .numLevels (); level ++) {
114117 if (primaryFieldSkipper .minValue (level ) == primaryFieldSkipper .maxValue (level )) {
115- betterUptTo = primaryFieldSkipper .maxDocID (level );
118+ primaryFieldUpTo = primaryFieldSkipper .maxDocID (level );
116119 } else {
117120 break ;
118121 }
119122 }
120- if (betterUptTo > upTo ) {
121- upTo = betterUptTo ;
123+ if (primaryFieldUpTo > upTo ) {
124+ upTo = primaryFieldUpTo ;
122125 }
123126 }
124127
@@ -156,7 +159,10 @@ Match match(int level) {
156159 public boolean matches () throws IOException {
157160 return switch (approximation .match ) {
158161 case YES -> true ;
159- case MAYBE -> innerTwoPhase .matches ();
162+ case MAYBE -> {
163+ final long value = timestamps .longValue ();
164+ yield value >= minTimestamp && value <= maxTimestamp ;
165+ }
160166 case NO -> throw new IllegalStateException ("Unpositioned approximation" );
161167 };
162168 }
@@ -171,7 +177,7 @@ public int docIDRunEnd() throws IOException {
171177
172178 @ Override
173179 public float matchCost () {
174- return innerTwoPhase . matchCost ();
180+ return 2 ; // 2 comparisons
175181 }
176182
177183 enum Match {
0 commit comments