|
17 | 17 | package org.apache.lucene.document; |
18 | 18 |
|
19 | 19 | import java.io.IOException; |
20 | | -import java.io.UncheckedIOException; |
21 | 20 | import java.util.Objects; |
22 | 21 | import java.util.function.LongPredicate; |
23 | 22 | import org.apache.lucene.index.DocValues; |
|
37 | 36 | import org.apache.lucene.search.ScoreMode; |
38 | 37 | import org.apache.lucene.search.ScorerSupplier; |
39 | 38 | import org.apache.lucene.search.Sort; |
| 39 | +import org.apache.lucene.search.SortField; |
40 | 40 | import org.apache.lucene.search.TwoPhaseIterator; |
41 | 41 | import org.apache.lucene.search.Weight; |
42 | 42 | import org.apache.lucene.util.BytesRef; |
@@ -121,8 +121,12 @@ public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOExcepti |
121 | 121 | DocValuesSkipper skipper = context.reader().getDocValuesSkipper(field); |
122 | 122 | SortedSetDocValues values = DocValues.getSortedSet(context.reader(), field); |
123 | 123 | final SortedDocValues singleton = DocValues.unwrapSingleton(values); |
124 | | - if (singleton != null && skipper != null && isDensePrimarySort(context.reader(), skipper)) { |
125 | | - return getScorerSupplierFromDensePrimarySort(context, singleton, values, skipper); |
| 124 | + final SortField primarySortField; |
| 125 | + if (singleton != null |
| 126 | + && skipper != null |
| 127 | + && (primarySortField = densePrimarySort(context.reader(), skipper)) != null) { |
| 128 | + return getScorerSupplierFromDensePrimarySort( |
| 129 | + context, singleton, values, skipper, primarySortField); |
126 | 130 | } |
127 | 131 | // implement ScorerSupplier, since we do some expensive stuff to make a scorer |
128 | 132 | return new ConstantScoreScorerSupplier(score(), scoreMode, context.reader().maxDoc()) { |
@@ -166,121 +170,40 @@ private ScorerSupplier getScorerSupplierFromDensePrimarySort( |
166 | 170 | LeafReaderContext context, |
167 | 171 | SortedDocValues singleton, |
168 | 172 | SortedSetDocValues values, |
169 | | - DocValuesSkipper skipper) { |
170 | | - final Sort indexSort = context.reader().getMetaData().sort(); |
171 | | - return new ConstantScoreScorerSupplier(score(), scoreMode, context.reader().maxDoc()) { |
172 | | - int skipperMinDocId = -1, skipperMaxDocId = -1; |
173 | | - long minOrd, maxOrd; |
174 | | - boolean skipperMinDocIdExact = false, skipperMaxDocIdExact = false; |
| 173 | + DocValuesSkipper skipper, |
| 174 | + SortField sortField) { |
| 175 | + return new SortedSkipperScorerSupplier( |
| 176 | + skipper, sortField, score(), scoreMode, context.reader().maxDoc()) { |
| 177 | + long minOrd = -1, maxOrd = -1; |
175 | 178 |
|
176 | 179 | @Override |
177 | | - public DocIdSetIterator iterator(long leadCost) throws IOException { |
178 | | - if (skipperMinDocId == -1) { |
179 | | - computeSkipperDocIds(); |
180 | | - } |
181 | | - final int minDocID; |
182 | | - final int maxDocID; |
183 | | - if (indexSort.getSort()[0].getReverse()) { |
184 | | - minDocID = |
185 | | - skipperMinDocIdExact |
186 | | - ? skipperMinDocId |
187 | | - : nextDoc(skipperMinDocId, singleton, l -> l <= maxOrd); |
188 | | - maxDocID = |
189 | | - skipperMaxDocIdExact |
190 | | - ? skipperMaxDocId |
191 | | - : nextDoc(skipperMaxDocId, singleton, l -> l < minOrd); |
192 | | - } else { |
193 | | - minDocID = |
194 | | - skipperMinDocIdExact |
195 | | - ? skipperMinDocId |
196 | | - : nextDoc(skipperMinDocId, singleton, l -> l >= minOrd); |
197 | | - maxDocID = |
198 | | - skipperMaxDocIdExact |
199 | | - ? skipperMaxDocId |
200 | | - : nextDoc(skipperMaxDocId, singleton, l -> l > maxOrd); |
| 180 | + protected long getLowerValue() throws IOException { |
| 181 | + if (minOrd == -1) { |
| 182 | + minOrd = minOrd(values); |
201 | 183 | } |
202 | | - return minDocID == maxDocID |
203 | | - ? DocIdSetIterator.empty() |
204 | | - : DocIdSetIterator.range(minDocID, maxDocID); |
| 184 | + return minOrd; |
205 | 185 | } |
206 | 186 |
|
207 | 187 | @Override |
208 | | - public long cost() { |
209 | | - if (skipperMinDocId == -1) { |
210 | | - try { |
211 | | - // Similar to PointValues, IOExceptions needs to be caught and rethrown as |
212 | | - // UncheckedIOException |
213 | | - computeSkipperDocIds(); |
214 | | - } catch (IOException e) { |
215 | | - throw new UncheckedIOException(e); |
216 | | - } |
| 188 | + protected long getUpperValue() throws IOException { |
| 189 | + if (maxOrd == -1) { |
| 190 | + maxOrd = maxOrd(values); |
217 | 191 | } |
218 | | - if (skipperMinDocIdExact && skipperMaxDocIdExact) { |
219 | | - return skipperMaxDocId - skipperMinDocId; |
220 | | - } |
221 | | - // TODO: expose skipper block size here? |
222 | | - return Math.min(context.reader().maxDoc(), 4096 + skipperMaxDocId - skipperMinDocId); |
| 192 | + return maxOrd; |
223 | 193 | } |
224 | 194 |
|
225 | | - private void computeSkipperDocIds() throws IOException { |
226 | | - minOrd = minOrd(values); |
227 | | - maxOrd = upperValue != null && upperValue.equals(lowerValue) ? minOrd : maxOrd(values); |
228 | | - if (minOrd > maxOrd || minOrd > skipper.maxValue() || maxOrd < skipper.minValue()) { |
229 | | - skipperMinDocId = skipperMaxDocId = DocIdSetIterator.NO_MORE_DOCS; |
230 | | - skipperMinDocIdExact = skipperMaxDocIdExact = true; |
231 | | - return; |
232 | | - } |
233 | | - if (skipper.minValue() >= minOrd && skipper.maxValue() <= maxOrd) { |
234 | | - skipperMinDocId = 0; |
235 | | - skipperMaxDocId = skipper.docCount(); |
236 | | - skipperMinDocIdExact = skipperMaxDocIdExact = true; |
237 | | - return; |
| 195 | + @Override |
| 196 | + protected int nextDoc(int startDocId, LongPredicate predicate) throws IOException { |
| 197 | + int doc = singleton.docID(); |
| 198 | + if (startDocId > doc) { |
| 199 | + doc = singleton.advance(startDocId); |
238 | 200 | } |
239 | | - if (indexSort.getSort()[0].getReverse()) { |
240 | | - if (skipper.maxValue() <= maxOrd) { |
241 | | - skipperMinDocId = 0; |
242 | | - skipperMinDocIdExact = true; |
243 | | - } else { |
244 | | - skipper.advance(Long.MIN_VALUE, maxOrd); |
245 | | - skipperMinDocId = skipper.minDocID(0); |
246 | | - skipperMinDocIdExact = skipper.maxValue(0) == maxOrd; |
247 | | - } |
248 | | - if (skipper.minValue() >= minOrd) { |
249 | | - skipperMaxDocId = skipper.docCount(); |
250 | | - skipperMaxDocIdExact = true; |
251 | | - } else { |
252 | | - skipper.advance(Long.MIN_VALUE, minOrd); |
253 | | - skipperMaxDocId = |
254 | | - skipper.minValue(0) == minOrd ? skipper.maxDocID(0) + 1 : skipper.minDocID(0); |
255 | | - // we can read the next block, if the maxValue is different to minOrd, then we |
256 | | - // should be done, we |
257 | | - // don't need to visit the doc values. But what is more expensive, visit one doc |
258 | | - // value or one skipper block? |
259 | | - skipperMaxDocIdExact = false; |
260 | | - } |
261 | | - } else { |
262 | | - if (skipper.minValue() >= minOrd) { |
263 | | - skipperMinDocId = 0; |
264 | | - skipperMinDocIdExact = true; |
265 | | - } else { |
266 | | - skipper.advance(minOrd, Long.MAX_VALUE); |
267 | | - skipperMinDocId = skipper.minDocID(0); |
268 | | - skipperMinDocIdExact = skipper.minValue(0) == minOrd; |
269 | | - } |
270 | | - if (skipper.maxValue() <= maxOrd) { |
271 | | - skipperMaxDocId = skipper.docCount(); |
272 | | - skipperMaxDocIdExact = true; |
273 | | - } else { |
274 | | - skipper.advance(maxOrd, Long.MAX_VALUE); |
275 | | - skipperMaxDocId = |
276 | | - skipper.maxValue(0) == maxOrd ? skipper.maxDocID(0) + 1 : skipper.minDocID(0); |
277 | | - // we can read the next block, if the minValue is different to maxOrd, then we |
278 | | - // should be done, we |
279 | | - // don't need to visit the doc values. But what is more expensive, visit one doc |
280 | | - // value or one skipper block? |
281 | | - skipperMaxDocIdExact = false; |
| 201 | + for (; doc < DocIdSetIterator.NO_MORE_DOCS; doc = singleton.nextDoc()) { |
| 202 | + if (predicate.test(singleton.ordValue())) { |
| 203 | + break; |
282 | 204 | } |
283 | 205 | } |
| 206 | + return doc; |
284 | 207 | } |
285 | 208 | }; |
286 | 209 | } |
@@ -326,30 +249,16 @@ private long maxOrd(SortedSetDocValues values) throws IOException { |
326 | 249 | return maxOrd; |
327 | 250 | } |
328 | 251 |
|
329 | | - private boolean isDensePrimarySort(LeafReader reader, DocValuesSkipper skipper) { |
| 252 | + private SortField densePrimarySort(LeafReader reader, DocValuesSkipper skipper) { |
330 | 253 | if (skipper.docCount() != reader.maxDoc()) { |
331 | | - return false; |
| 254 | + return null; |
332 | 255 | } |
333 | 256 | final Sort indexSort = reader.getMetaData().sort(); |
334 | 257 | if (indexSort == null |
335 | 258 | || indexSort.getSort().length == 0 |
336 | 259 | || indexSort.getSort()[0].getField().equals(field) == false) { |
337 | | - return false; |
338 | | - } |
339 | | - return true; |
340 | | - } |
341 | | - |
342 | | - private static int nextDoc(int startDoc, SortedDocValues docValues, LongPredicate predicate) |
343 | | - throws IOException { |
344 | | - int doc = docValues.docID(); |
345 | | - if (startDoc > doc) { |
346 | | - doc = docValues.advance(startDoc); |
347 | | - } |
348 | | - for (; doc < DocIdSetIterator.NO_MORE_DOCS; doc = docValues.nextDoc()) { |
349 | | - if (predicate.test(docValues.ordValue())) { |
350 | | - break; |
351 | | - } |
| 260 | + return null; |
352 | 261 | } |
353 | | - return doc; |
| 262 | + return indexSort.getSort()[0]; |
354 | 263 | } |
355 | 264 | } |
0 commit comments