-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LUCENE-9449 Skip docs with _doc sort and "after" #1725
Changes from 1 commit
3fbc44a
5fcddf7
fabfca5
746c8fa
21de242
26534c5
4252fcd
485fe4f
a7c4e85
92fa246
27ff519
493d9eb
45577aa
e69fa27
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,8 +58,8 @@ private static final class OneComparatorFieldValueHitQueue<T extends FieldValueH | |
private final int oneReverseMul; | ||
private final FieldComparator<?> oneComparator; | ||
|
||
public OneComparatorFieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompetitiveDocs) { | ||
super(fields, size, filterNonCompetitiveDocs); | ||
public OneComparatorFieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompetitiveDocs, boolean hasAfter) { | ||
super(fields, size, filterNonCompetitiveDocs, hasAfter); | ||
|
||
assert fields.length == 1; | ||
oneComparator = comparators[0]; | ||
|
@@ -95,8 +95,8 @@ protected boolean lessThan(final Entry hitA, final Entry hitB) { | |
*/ | ||
private static final class MultiComparatorsFieldValueHitQueue<T extends FieldValueHitQueue.Entry> extends FieldValueHitQueue<T> { | ||
|
||
public MultiComparatorsFieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompetitiveDocs) { | ||
super(fields, size, filterNonCompetitiveDocs); | ||
public MultiComparatorsFieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompetitiveDocs, boolean hasAfter) { | ||
super(fields, size, filterNonCompetitiveDocs, hasAfter); | ||
} | ||
|
||
@Override | ||
|
@@ -121,7 +121,7 @@ protected boolean lessThan(final Entry hitA, final Entry hitB) { | |
} | ||
|
||
// prevent instantiation and extension. | ||
private FieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompetitiveDocs) { | ||
private FieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompetitiveDocs, boolean hasAfter) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point of time, topValue for comparators is not set yet, that's why we need |
||
super(size); | ||
// When we get here, fields.length is guaranteed to be > 0, therefore no | ||
// need to check it again. | ||
|
@@ -140,7 +140,7 @@ private FieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompet | |
// try to rewrite the 1st comparator to the comparator that can skip non-competitive documents | ||
// skipping functionality is beneficial only for the 1st comparator | ||
comparators[i] = FilteringFieldComparator.wrapToFilteringComparator(field.getComparator(size, i), | ||
field.reverse, numComparators == 1); | ||
field.reverse, numComparators == 1, hasAfter); | ||
} else { | ||
comparators[i] = field.getComparator(size, i); | ||
} | ||
|
@@ -160,18 +160,20 @@ private FieldValueHitQueue(SortField[] fields, int size, boolean filterNonCompet | |
* The number of hits to retain. Must be greater than zero. | ||
* @param filterNonCompetitiveDocs | ||
* {@code true} If comparators should be allowed to filter non-competitive documents, {@code false} otherwise | ||
* @param hasAfter | ||
* {@code true} If this sort has "after" FieldDoc | ||
*/ | ||
public static <T extends FieldValueHitQueue.Entry> FieldValueHitQueue<T> create(SortField[] fields, int size, | ||
boolean filterNonCompetitiveDocs) { | ||
boolean filterNonCompetitiveDocs, boolean hasAfter) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we avoid adding |
||
|
||
if (fields.length == 0) { | ||
throw new IllegalArgumentException("Sort must contain at least one field"); | ||
} | ||
|
||
if (fields.length == 1) { | ||
return new OneComparatorFieldValueHitQueue<>(fields, size, filterNonCompetitiveDocs); | ||
return new OneComparatorFieldValueHitQueue<>(fields, size, filterNonCompetitiveDocs, hasAfter); | ||
} else { | ||
return new MultiComparatorsFieldValueHitQueue<>(fields, size, filterNonCompetitiveDocs); | ||
return new MultiComparatorsFieldValueHitQueue<>(fields, size, filterNonCompetitiveDocs, hasAfter); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.lucene.search; | ||
|
||
import org.apache.lucene.index.LeafReaderContext; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* A wrapper over {@code DocComparator} that has "after" FieldDoc. | ||
* This comparator can quickly skip to the desired "after" document. | ||
*/ | ||
class FilteringDocComparator<Integer> extends FilteringFieldComparator<Integer> { | ||
public FilteringDocComparator(FieldComparator<Integer> in, boolean reverse, boolean singleSort) { | ||
super(in, reverse, singleSort); | ||
} | ||
|
||
@Override | ||
public final FilteringLeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException { | ||
LeafFieldComparator inLeafComparator = in.getLeafComparator(context); | ||
return new FilteringDocLeafComparator(inLeafComparator, context); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.lucene.search; | ||
|
||
import org.apache.lucene.index.LeafReaderContext; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* This comparator is used when there is sort by _doc asc together with "after" FieldDoc. | ||
* The comparator provides an iterator that can quickly skip to the desired "after" document. | ||
*/ | ||
public class FilteringDocLeafComparator implements FilteringLeafFieldComparator { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe rename to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like |
||
private final FieldComparator.DocComparator in; | ||
private DocIdSetIterator topValueIterator; // iterator that starts from topValue if possible | ||
private final int minDoc; | ||
private final int maxDoc; | ||
private final int docBase; | ||
private boolean iteratorUpdated = false; | ||
|
||
public FilteringDocLeafComparator(LeafFieldComparator in, LeafReaderContext context) { | ||
mayya-sharipova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.in = (FieldComparator.DocComparator) in; | ||
this.minDoc = this.in.topValue + 1; | ||
this.maxDoc = context.reader().maxDoc(); | ||
this.docBase = context.docBase; | ||
this.topValueIterator = DocIdSetIterator.all(maxDoc); | ||
} | ||
|
||
@Override | ||
public DocIdSetIterator competitiveIterator() { | ||
return new DocIdSetIterator() { | ||
private int doc; | ||
|
||
@Override | ||
public int nextDoc() throws IOException { | ||
return doc = topValueIterator.nextDoc(); | ||
} | ||
|
||
@Override | ||
public int docID() { | ||
return doc; | ||
} | ||
|
||
@Override | ||
public long cost() { | ||
return topValueIterator.cost(); | ||
} | ||
|
||
@Override | ||
public int advance(int target) throws IOException { | ||
return doc = topValueIterator.advance(target); | ||
} | ||
}; | ||
|
||
} | ||
|
||
@Override | ||
public boolean iteratorUpdated() { | ||
return iteratorUpdated; | ||
} | ||
|
||
@Override | ||
public void setQueueFull() { | ||
} | ||
|
||
@Override | ||
public void setHitsThresholdReached() { | ||
if (iteratorUpdated) return; | ||
if (docBase + maxDoc <= minDoc) { | ||
topValueIterator = DocIdSetIterator.empty(); // skip this segment | ||
} | ||
final int segmentMinDoc = Math.max(0, minDoc - docBase); | ||
topValueIterator = new MinDocIterator(segmentMinDoc, maxDoc); | ||
iteratorUpdated = true; | ||
} | ||
|
||
@Override | ||
public void setBottom(int slot) { | ||
in.setBottom(slot); | ||
} | ||
|
||
@Override | ||
public int compareBottom(int doc) { | ||
return in.compareBottom(doc); | ||
} | ||
|
||
@Override | ||
public int compareTop(int doc) { | ||
return in.compareTop(doc); | ||
} | ||
|
||
@Override | ||
public void copy(int slot, int doc) throws IOException { | ||
in.copy(slot, doc); | ||
} | ||
|
||
@Override | ||
public void setScorer(Scorable scorer) throws IOException { | ||
in.setScorer(scorer); | ||
} | ||
|
||
|
||
static class MinDocIterator extends DocIdSetIterator { | ||
final int segmentMinDoc; | ||
final int maxDoc; | ||
int doc = -1; | ||
|
||
MinDocIterator(int segmentMinDoc, int maxDoc) { | ||
this.segmentMinDoc = segmentMinDoc; | ||
this.maxDoc = maxDoc; | ||
} | ||
|
||
@Override | ||
public int docID() { | ||
return doc; | ||
} | ||
|
||
@Override | ||
public int nextDoc() throws IOException { | ||
return advance(doc + 1); | ||
} | ||
|
||
@Override | ||
public int advance(int target) throws IOException { | ||
assert target > doc; | ||
if (doc == -1) { | ||
// skip directly to minDoc | ||
doc = Math.max(target, segmentMinDoc); | ||
} else { | ||
doc = target; | ||
} | ||
if (doc >= maxDoc) { | ||
doc = NO_MORE_DOCS; | ||
} | ||
return doc; | ||
} | ||
|
||
@Override | ||
public long cost() { | ||
return maxDoc - segmentMinDoc; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,10 +68,12 @@ public int compareValues(T first, T second) { | |
* @param comparator – comparator to wrap | ||
* @param reverse – if this sort is reverse | ||
* @param singleSort – true if this sort is based on a single field and there are no other sort fields for tie breaking | ||
* @param hasAfter – true if this sort has after FieldDoc | ||
* @return comparator wrapped as a filtering comparator or the original comparator if the filtering functionality | ||
* is not implemented for it | ||
*/ | ||
public static FieldComparator<?> wrapToFilteringComparator(FieldComparator<?> comparator, boolean reverse, boolean singleSort) { | ||
public static FieldComparator<?> wrapToFilteringComparator(FieldComparator<?> comparator, boolean reverse, boolean singleSort, | ||
boolean hasAfter) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need to add the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At that moment topValue is not set yet, it will be set later in the constructor of |
||
Class<?> comparatorClass = comparator.getClass(); | ||
if (comparatorClass == FieldComparator.LongComparator.class){ | ||
return new FilteringNumericComparator<>((FieldComparator.LongComparator) comparator, reverse, singleSort); | ||
|
@@ -85,6 +87,9 @@ public static FieldComparator<?> wrapToFilteringComparator(FieldComparator<?> co | |
if (comparatorClass == FieldComparator.FloatComparator.class){ | ||
return new FilteringNumericComparator<>((FieldComparator.FloatComparator) comparator, reverse, singleSort); | ||
} | ||
if (comparatorClass == FieldComparator.DocComparator.class && hasAfter && reverse == false) { // if SortField.DOC with after | ||
return new FilteringDocComparator<>((FieldComparator.DocComparator) comparator, reverse, singleSort); | ||
} | ||
return comparator; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure that
hasAfter
is really needed here.