Index: src/java/org/apache/lucene/search/BooleanQuery.java =================================================================== --- src/java/org/apache/lucene/search/BooleanQuery.java (revision 768733) +++ src/java/org/apache/lucene/search/BooleanQuery.java (working copy) @@ -173,7 +173,8 @@ /** Returns the list of clauses in this query. */ public List clauses() { return clauses; } - private class BooleanWeight implements Weight { + // nocommit -- was private + public class BooleanWeight implements Weight { protected Similarity similarity; protected ArrayList weights; @@ -187,6 +188,10 @@ } } + public Weight subWeight(int index) { + return (Weight) weights.get(index); + } + public Query getQuery() { return BooleanQuery.this; } public float getValue() { return getBoost(); } Index: src/java/org/apache/lucene/index/SegmentReader.java =================================================================== --- src/java/org/apache/lucene/index/SegmentReader.java (revision 768733) +++ src/java/org/apache/lucene/index/SegmentReader.java (working copy) @@ -41,7 +41,8 @@ /** * @version $Id$ */ -class SegmentReader extends DirectoryIndexReader { +// nocommit +public class SegmentReader extends DirectoryIndexReader { private String segment; private SegmentInfo si; private int readBufferSize; @@ -569,6 +570,10 @@ } } } + + public BitVector getDeletedDocs() { + return deletedDocs; + } private void loadDeletedDocs() throws IOException { // NOTE: the bitvector is stored using the regular directory, not cfs Index: src/java/org/apache/lucene/index/SegmentTermDocs.java =================================================================== --- src/java/org/apache/lucene/index/SegmentTermDocs.java (revision 768733) +++ src/java/org/apache/lucene/index/SegmentTermDocs.java (working copy) @@ -21,7 +21,8 @@ import org.apache.lucene.util.BitVector; import org.apache.lucene.store.IndexInput; -class SegmentTermDocs implements TermDocs { +// nocommit +public class SegmentTermDocs implements TermDocs { protected SegmentReader parent; protected IndexInput freqStream; protected int count; @@ -93,6 +94,15 @@ } } + // nocommit + public IndexInput getFreqStream() { + return freqStream; + } + // nocommit + public int getTermFreq() { + return df; + } + public void close() throws IOException { freqStream.close(); if (skipListReader != null) Index: src/java/org/apache/lucene/index/MultiSegmentReader.java =================================================================== --- src/java/org/apache/lucene/index/MultiSegmentReader.java (revision 768733) +++ src/java/org/apache/lucene/index/MultiSegmentReader.java (working copy) @@ -32,7 +32,8 @@ /** * An IndexReader which reads indexes with multiple segments. */ -class MultiSegmentReader extends DirectoryIndexReader implements Cloneable { +// nocommit +public class MultiSegmentReader extends DirectoryIndexReader implements Cloneable { protected SegmentReader[] subReaders; private int[] starts; // 1st docno for each segment private Map normsCache = new HashMap(); Index: contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java =================================================================== --- contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java (revision 768733) +++ contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java (working copy) @@ -93,6 +93,8 @@ type = SortField.FLOAT; } else if (typeString.equals("int")) { type = SortField.INT; + } else if (typeString.equals("long")) { + type = SortField.LONG; } else if (typeString.equals("string")) { type = SortField.STRING; } else if (typeString.equals("string_val")) { Index: contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java =================================================================== --- contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java (revision 768733) +++ contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java (working copy) @@ -23,6 +23,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.HashMap; +import java.util.Random; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; @@ -32,11 +34,20 @@ import org.apache.lucene.document.Fieldable; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.TopDocs; +import org.apache.lucene.search.TopFieldDocs; +import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.TopFieldCollector; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.Sort; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.DocIdSet; +import org.apache.lucene.index.SegmentReader; +import org.apache.lucene.util.BitVector; +import org.apache.lucene.util.OpenBitSet; +import org.apache.lucene.util.SortedVIntList; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.QueryScorer; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; @@ -44,6 +55,7 @@ import org.apache.lucene.search.highlight.TokenSources; import org.apache.lucene.search.highlight.InvalidTokenOffsetsException; import org.apache.lucene.store.Directory; +import org.apache.lucene.search.FastSearch; /** @@ -60,9 +72,16 @@ */ public abstract class ReadTask extends PerfTask { + private final double fpct; + public ReadTask(PerfRunData runData) { super(runData); + fpct = getRunData().getConfig().get("filter.pct", 0.0); } + // nocommit + static boolean first = true; + final private FastSearch fastSearch = new FastSearch(); + public int doLogic() throws Exception { int res = 0; boolean closeReader = false; @@ -97,20 +116,45 @@ } QueryMaker queryMaker = getQueryMaker(); Query q = queryMaker.makeQuery(); + Filter filter = getFilter(); Sort sort = getSort(); TopDocs hits; final int numHits = numHits(); if (numHits > 0) { - if (sort != null) { + + if (doSearchSpec) { + if (sort == null) { + hits = fastSearch.search(searcher, q, filter, numHits); + } else { + hits = fastSearch.search(searcher, q, filter, sort, withScore(), withMaxScore(), true, numHits); + } + } else if (sort != null) { TopFieldCollector collector = TopFieldCollector.create(sort, numHits, - true, withScore(), withMaxScore()); - searcher.search(q, collector); + true, withScore(), withMaxScore()); + searcher.search(q, filter, collector); hits = collector.topDocs(); } else { - hits = searcher.search(q, numHits); + hits = searcher.search(q, filter, numHits); } - //System.out.println("q=" + q + ":" + hits.totalHits + " total hits"); + // nocommit + if (first && hits != null) { + System.out.println("NUMHITS=" + hits.totalHits); + if (hits instanceof TopFieldDocs) { + for(int i=0;i 0.0) { + System.out.println("FILT=" + fpct); + filter = new MyFilter(fpct); + } else if (first2) { + System.out.println("FILT=none"); + first2 = false; + } + } + return filter; + } + + static final HashMap filters = new HashMap(); + static private final boolean filtSparse = false; + + private class MyFilter extends Filter { + private final double fpct; + + MyFilter(double fpct) { + this.fpct = fpct; + } + + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { + DocIdSet bits = (DocIdSet) filters.get(reader); + if (bits == null) { + final int numDocs = reader.maxDoc(); + OpenBitSet openBits = new OpenBitSet(numDocs); + final Random r = new java.util.Random(42244224); + int setCount = 0; + final boolean inverted; + final double fpct2; + if (fpct > 50.0) { + fpct2 = 100.0 - fpct; + inverted = true; + } else { + fpct2 = fpct; + inverted = false; + } + + final int target = (int) ((fpct2/100.0)*numDocs); + while(setCount < target) { + setCount += openBits.getAndSet(r.nextInt(numDocs)) ? 0:1; + } + if (setCount != openBits.cardinality()) { + throw new RuntimeException("count mismatch"); + } + if (inverted) { + OpenBitSet bits2 = new OpenBitSet(numDocs); + for(int i=0;i + @@ -165,8 +166,13 @@ + + + + + - + Index: contrib/spec/gen.py =================================================================== --- contrib/spec/gen.py (revision 0) +++ contrib/spec/gen.py (revision 0) @@ -0,0 +1,1012 @@ +import sys +import os + +# TODO +# - handle "sort by docid" +# - handle custom sorting +# - have "single warmup" that does things like check for no-nulls in FieldCache for string, no max/min val in numeric ifelds, etc +# - allow custom collector +# - handle the "no norms" case by specializing "1" in +# - specialize the "omitTF" case +# - ARGH -- undo the "pre-fill w/ sentinel", or, first loop to pre-fill, then 2nd loop w/ already full +# - fix to statically gen all possibilities; then make a "pass through" optimizer, and run all lucene tests +# - make "valueType" a comparator +# - get custom comparator working; must call setScorer +# - optimize for "never null" string +# - OR-qery +# - gen minNrShouldMatch variants +# - relax to N clauses +# - allow prohibited, must terms +# - relax having to get the precise totalHits -- then we can rule +# out matches (when sorting by fields) during TermScorer +# - don't make double-while loop when doing next() +# - make sure we are pulling & comparing values of top n +# - Bucket shared pool +# - inline string comparator -- no nulls vs nulls case +# - or query +# - instead of linked list, simple array-of-ints? are ints cheaper to change than pointers? (no write barrier) +# - get generic way to "push" fast per-doc rejection criteria down +# to atomic queries (eg testing bottomVal) +# - need both boolean or scorers because collecting by field w/o +# maxScore should score "on demand" +# - make boolean or scorer like non-docs-in-order collector +# - somehow, split out query gen code that's "in the to loop" vs "a +# sub-clause", ie, can do compete/score/collect itself or must +# strongly separate doc vs score +# - HMM: we can 'writeCompetes' down in the sub-queries? eg no +# sense considering a given doc, from TermQuery, if it cannot compete +# in current field-sorted queue +# - re-instate "i am top query" optimization, eg for termquery +# - collapse the while loops +# - just break instead of setting docend sentinel +# - allow turning off hitCount++ +# - RelevanceComparator is broken +# - inline stringvalord comp +# - we can skip freq, instead of reading into freq var, if hit does not compete +# - when score is "no" we should have single "skip freq vint" read +# - maybe use a custom "skipVInt" method -- reads the bytes w/o building int +# - FIX score: don't compute it we are not tracking maxScore +# - support sparse filters (as iterator, boolean query clause?) +# - get reversed working +# - cleanup +# - merge in all stop criteria, eg ++count > aLimit +# - for scoredoc we do't need to re-add docBase -- just init doc=0 +# - hmm: will we "flood" the instruction cache when many threads running different specialized code? +# - share norms per field (if multiple term queries run against same field) +# - for real integration +# - need to "know" that filter will give us an openbitset, somehow? +# - tweak order of ifs +# - allow deletes/no per segment +# - TODO: figure out if side-by-side arrays are slower, or +# pointer-to-obj is slower, for the queue +# - score doc & fields +# - assert topN > 0 +# - downHeap could be optimized -- that initial "if k < 10" +# - for TopScoreDoc collection, try to re-coalesce multiple if statemetns (it got slower!!) + +END_DOC = sys.maxint + +class Writer: + + def __init__(self): + self.indent = 0 + self.l = [] + self.vars = {} + self.upto = 0 + + def __call__(self, s): + if s.find('}') != -1: + self.indent -= 1 + c = 0 + while c < len(s)-1 and s[c] == ' ': + c += 1 + self.l.append(' '*(2*self.indent-c) + s) + if s.find('{') != -1: + self.indent += 1 + + def __str__(self): + return '\n'.join(self.l) + + def getVar(self, prefix): + upto = 0 + while True: + v = '%s%s' % (prefix, upto) + if v not in self.vars: + self.vars[v] = True + return v + upto += 1 + + def getID(self): + s ='q%d' % self.upto + self.upto += 1 + return s + + def releaseVar(self, v): + del self.vars[v] + +class BasePQCollector: + + valueType = None + docsAlwaysInOrder = True + + def __init__(self, w): + self.w = w + + def upperValueType(self, isFieldCache=False): + if self.valueType == 'int': + if isFieldCache: + return 'Int' + else: + return 'Integer' + else: + return self.valueType[0].upper() + self.valueType[1:] + + def readerInit(self): + pass + + def writeTempBottom(self): + pass + + def writeTopClass(self): + pass + + def topInit(self): + self.w('int hitCount = 0;') + + def collectOne(self, q, checkEndDoc=True, docsInOrder=True): + w = self.w + if checkEndDoc: + w('if (doc == %s) {' % END_DOC) + w(' break;') + w('}') + w('hitCount++;') + + if DEBUG: + w('System.out.println("doc=" + (doc+docBase) + " score=" + %s);' % q.scoreVar) + + if not docsInOrder: + w(' final int fullDoc = doc + docBase;') + + #w('System.out.println("rx=" + rx + " doc=" + (doc+docBase) + " ord=" + order[doc] + " val=" + lookup[order[doc]] + " bottom.ord=" + bottom.ord + " bottom.val=" + bottom.val);') + self.writeCompetes(q, docsInOrder) + + w('') + + if docsInOrder: + w(' final int fullDoc = doc + docBase;') + + self.copyCurrentToBottom() + + w('') + w(' // downheap') + + iVar = w.getVar('i') + w(' int %s = 1;' % iVar) + + jVar = w.getVar('j') + w(' int %s = %s << 1;' % (jVar, iVar)) + + kVar = w.getVar('k') + w(' int %s = %s+1;' % (kVar, jVar)) + w(' if (%s <= topN) {' % kVar) + self.lessThan(kVar, jVar, 'lt') + #w(' System.out.println("init lt=" + lt);') + w(' if (lt) {') + w(' %s = %s;' % (jVar, kVar)) + w(' }') + w(' }') + w(' while(%s <= topN) {' % jVar) + self.currentGreaterThanBreak(jVar, docsInOrder) + self.copy(jVar, iVar) + w(' %s = %s;' % (iVar, jVar)) + w(' %s = %s << 1;' % (jVar, iVar)) + w(' %s = %s+1;' % (kVar, jVar)) + w(' if (%s <= topN) {' % kVar) + self.lessThan(kVar, jVar, 'lt') + w(' if (lt) {') + w(' %s = %s;' % (jVar, kVar)) + w(' }') + w(' }') + w(' }') + w.releaseVar(kVar) + w.releaseVar(jVar) + + self.installBottom(iVar) + w.releaseVar(iVar) + + self.endInsert() + + # matches writeCompetes + w('}') + + def createResults(self, v, c): + w = self.w + + w('') + if self.__class__ == ScoreDocCollector: + self.w('final float maxScore = queueScores[1];') + + w('// Build results -- sort pqueue entries') + w('final SorterTemplate sorter = new SorterTemplate() {') + w(' protected int compare(int i, int j) {') + self.lessThan('i', 'j', 'lt') + w(' if (lt) {') + w(' return 1;') + w(' } else {') + w(' // pq entries are never equal') + w(' return -1;') + w(' }') + w(' }') + w(' protected void swap(int i, int j) {') + self.swap('i', 'j') + w(' }') + w('};') + + w('// Extract results') + w('final int numHits = hitCount > topN ? topN : hitCount;') + w('sorter.quickSort(1, numHits);') + w('final ScoreDoc[] hits = new ScoreDoc[numHits];') + w('for(int i=0;i= score) {' % v) + else: + self.w('if (queueScores[%s] > score || (queueScores[%s] == score && queueDocs[%s] < fullDoc)) {' % (v, v, v)) + self.w(' break;') + self.w('}') + + def lessThan(self, a, b, v): + self.w('final boolean %s = queueScores[%s] < queueScores[%s] || (queueScores[%s] == queueScores[%s] && queueDocs[%s] > queueDocs[%s]);' % (v, a, b, a, b, a, b)) + + def copy(self, src, dest): + self.w('queueDocs[%s] = queueDocs[%s];' % (dest, src)) + self.w('queueScores[%s] = queueScores[%s];' % (dest, src)) + + def installBottom(self, dest): + self.w('queueDocs[%s] = fullDoc;' % dest) + self.w('queueScores[%s] = score;' % dest) + + def copyCurrentToBottom(self): + if DEBUG: + self.w('System.out.println(" boot doc=" + queueDocs[1] + " for new doc=" + fullDoc + " (eq?=" + (score == bottomScore) + ")" + " score=" + score + " bottomScore=" + bottomScore);') + self.w('queueDocs[1] = fullDoc;') + self.w('queueScores[1] = score;') + + def endInsert(self): + self.w('bottomScore = queueScores[1];') + if not self.docsAlwaysInOrder: + self.w('bottomDoc = queueDocs[1];') + if DEBUG: + self.w('System.out.println(" bottom=" + bottomScore + " doc=" + queueDocs[1]);') + + def writeCompetes(self, q, docsInOrder=True): + q.writeScore(self) + if docsInOrder: + self.w('if (score > bottomScore) {') + else: + self.w('if (score > bottomScore || (score == bottomScore && fullDoc < bottomDoc)) {') + + def swap(self, i, j): + w = self.w + w('final int itmp = queueDocs[%s];' % i) + w('queueDocs[%s] = queueDocs[%s];' % (i, j)) + w('queueDocs[%s] = itmp;' % j) + w('final float ftmp = queueScores[%s];' % i) + w('queueScores[%s] = queueScores[%s];' % (i, j)) + w('queueScores[%s] = ftmp;' % j) + + def createTopDocs(self): + self.w('final TopDocs results = new TopDocs(hitCount, hits, queueScores[1]);') + + +class StringOrdValComparator: + + def __init__(self, w): + self.w = w + + def setFieldValue(self, src): + self.w('fields[0] = queue[1+%s].val;' % src) + + def writeCompetesDef(self): + w = self.w + w('private final int competes(final Entry bottom, final int ord, final String val) {') + w(' // ords are comparable') + #w(' System.out.println("competes bottom.ord=" + bottom.ord + " vs docOrd=" + ord + " val=" + val);') + w(' final int c = bottom.ord - ord;') + w(' if (c != 0) {') + w(' return c;') + w(' } else {') + w(' if (bottom.val == null) {') + w(' if (val == null) {') + w(' return 0;') + w(' } else {') + w(' return -1;') + w(' }') + w(' } else if (val == null) {') + w(' return 1;') + w(' } else {') + w(' return bottom.val.compareTo(val);') + w(' }') + w(' }') + w('}') + + def writeCompetes(self, q, docsInOrder): + w = self.w + #w('System.out.println("collect doc=" + doc);') + if docsInOrder: + w('if (competes(bottom, order[doc], lookup[order[doc]]) > 0) {') + #w('System.out.println(" competes! doc=" + doc + " val=" + lookup[order[doc]] + " bottom.ord=" + bottom.ord + " bottom.val=" + bottom.val);') + else: + w('final int cx = competes(bottom, order[doc], lookup[order[doc]]);') + w('if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) {') + + def currentGreaterThanBreak(self, v, docsInOrder=True): + w = self.w + w('final int c = compareOrdVal(queue[%s], bottom);' % v) + if docsInOrder: + w('if (c <= 0) {') + #w(' System.out.println(" now break k0=" + k0 + " j0=" + j0 + " c=" + c);') + else: + w('if (c < 0 || (c == 0 && queue[%s].docID < bottom.docID)) {' % v) + w(' break;') + w('}') + + def copyCurrentToBottom(self): + self.w('bottom.ord = order[doc];') + self.w('bottom.val = lookup[bottom.ord];') + self.w('bottom.readerGen = rx;') + + def initSingleEntryQueue(self): + self.w('e.ord = Integer.MAX_VALUE;') + self.w('e.val = sentinel;') + + def writeTop(self): + self.w('// U+FFFF is not a valid unicode char, so this is a safe sentinel') + self.w('final String sentinel = new String("\uFFFF");') + + def endInsert(self): + self.writeConvertBottom() + + #self.w('System.out.println("set bottom.ord=" + bottom.ord);') + pass + + def writeCompare(self): + w = self.w + w('private final int compareOrdVal(Entry e1, Entry e2) {') + #w(' System.out.println("compareOrdVal e1.readerGen=" + e1.readerGen + " e2.readerGen=" + e2.readerGen);') + #w(' System.out.println("compareOrdVal e1.val=" + e1.val + " e2.val=" + e2.val);') + w(' if (e1.readerGen == e2.readerGen) {') + w(' // ords are comparable') + w(' final int c = e1.ord - e2.ord;') + #w(' System.out.println(" c=" + c);') + w(' if (c != 0) {') + w(' return c;') + w(' }') + w(' }') + w(' if (e1.val == null) {') + w(' if (e2.val == null) {') + w(' return 0;') + w(' } else {') + w(' return -1;') + w(' }') + w(' } else if (e2.val == null) {') + w(' return 1;') + w(' }') + w(' return e1.val.compareTo(e2.val);') + w('}') + + def writeBinarySearch(self): + self.w(''' final private static int binarySearch(String[] a, String key) { + return binarySearch(a, key, 0, a.length-1); + }''') + + self.w(''' final private static int binarySearch(String[] a, String key, int low, int high) { + + while (low <= high) { + int mid = (low + high) >>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + }''') + + def writeTopClass(self): + self.writeCompare() + self.writeCompetesDef() + self.writeBinarySearch() + + def writeEntryClass(self): + self.w('int ord;') + self.w('String val;') + self.w('int readerGen;') + + def writePerReader(self): + self.w('StringIndex sx = ExtendedFieldCache.EXT_DEFAULT.getStringIndex(r, sortFieldID);') + self.w('final String[] lookup = sx.lookup;') + self.w('final int[] order = sx.order;') + self.writeConvertBottom() + + def writeConvertBottom(self): + self.w('if (bottom.readerGen != rx) {') + self.w('if (bottom.val != null) {') + self.w(' final int index = binarySearch(lookup, bottom.val);') + self.w(' if (index < 0) {') + self.w(' bottom.ord = -index-2;') + self.w(' } else {') + self.w(' bottom.ord = index;') + self.w(' }') + #self.w(' System.out.println("next reader (rx=" + rx + ") set bottom.ord=" + bottom.ord + " bottom.val=" + bottom.val);') + self.w('} else {') + self.w(' bottom.ord = 0;') + self.w('}') + self.w('bottom.readerGen = rx;') + self.w('}') + +class SortByOneFieldCollector(BasePQCollector): + + def __init__(self, w, doTrackScores, doMaxScore): + BasePQCollector.__init__(self, w) + self.doTrackScores = doTrackScores + self.doMaxScore = doMaxScore + + def needsScores(self): + return self.doTrackScores or self.doMaxScore + + def createScoreDoc(self, dest, src): + self.w('final Comparable[] fields = new Comparable[1];') + if self.valueType is not None: + self.w('fields[0] = new %s(queue[1+%s].value);' % (self.upperValueType(), src)) + elif self.comp is not None: + self.comp.setFieldValue(src) + else: + self.w('fields[0] = comp.value(queue[1+%s].slot);' % src) + if self.doTrackScores: + s = 'queue[1+%s].score' % src + else: + s = 'Float.NaN' + self.w('%s = new FieldDoc(queue[1+%s].docID, %s, fields);' % (dest, src, s)) + + def readerInit(self): + w = self.w + if self.valueType is not None: + w('// TODO: support custom parser') + w('final %s[] docValues = ExtendedFieldCache.EXT_DEFAULT.get%ss(r, sortFieldID);' % \ + (self.valueType, self.upperValueType(True))) + elif self.comp is not None: + self.comp.writePerReader() + else: + w('comp.setNextReader(r, docBase, hitCount>topN?topN:hitCount);') + + def writeTopClass(self): + w = self.w + w('final private static class Entry {') + if self.comp is not None: + self.comp.writeEntryClass() + elif self.valueType is not None: + w(' // local inlined value') + w(' %s value;' % self.valueType) + else: + w(' // value by reference') + w(' final int slot;') + w(' int docID;') + if self.doTrackScores: + w(' float score;') + w('}') + + if self.comp is not None: + self.comp.writeTopClass() + + + def topInit(self): + BasePQCollector.topInit(self) + w = self.w + if self.doMaxScore: + self.w('float maxScore = Float.NEGATIVE_INFINITY;') + self.w('final SortField sortField = sort.getSort()[0];') + self.w('final String sortFieldID = sortField.getField();') + self.w('final Entry[] queue = new Entry[1+topN];') + if self.comp is not None: + self.comp.writeTop() + elif self.valueType is not None: + w('// pre-fill queue with "bottom"') + w('final %s sentinel;' % self.valueType) + w('if (sortField.getReverse()) {') + w(' sentinel = %s.MIN_VALUE;' % self.upperValueType()) + w('} else {') + w(' sentinel = %s.MAX_VALUE;' % self.upperValueType()) + w('}') + w('// queue[0] is never used') + + w('for (int x=1;x<=topN;x++) {') + w(' final Entry e = queue[x] = new Entry();') + w(' e.docID = Integer.MAX_VALUE;') + if self.doTrackScores: + w(' e.score = Float.NEGATIVE_INFINITY;') + if self.comp is not None: + self.comp.initSingleEntryQueue() + elif self.valueType is not None: + w(' e.value = sentinel;') + else: + w(' e.slot = i-1;') + w('}') + + w('Entry bottom = queue[1];') + if self.valueType is None: + w('final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false);') + else: + w('%s bottomValue = sentinel;' % self.valueType) + if not self.docsAlwaysInOrder: + w('int bottomDoc = Integer.MAX_VALUE;') + + def currentGreaterThanBreak(self, v, docsInOrder=True): + w = self.w + if self.comp is not None: + self.comp.currentGreaterThanBreak(v, docsInOrder) + elif self.valueType is None: + if docsInOrder: + w('if (comp.compare(queue[%s].slot, bottom.slot) <= 0) {' % v) + w(' break;') + w('}') + else: + w('final int c = comp.compare(queue[%s].slot, bottom.slot);' % v) + w('if (c == 0) {') + w(' // Must break tie by docID') + w(' if (queue[%s].docID < bottom.docID) {' % v) + w(' break;') + w(' }') + w('} else if (c < 0) {') + w(' break;') + w('}') + else: + self.w('if (queue[%s].value == bottomValue) {' % v) + w(' // Must break tie by docID') + w(' if (queue[%s].docID < bottom.docID) {' % v) + w(' break;') + w(' }') + w('} else if (queue[%s].value < bottomValue) {' % v) + w(' break;') + w('}') + + def lessThan(self, a, b, v): + w = self.w + c = w.getVar('c') + w('final boolean %s;'% v) + if self.comp is not None: + w('final int %s = compareOrdVal(queue[%s], queue[%s]);' % (c, a, b)) + w('if (%s == 0) {' % c) + elif self.valueType is None: + w('final int %s = comp.compare(queue[%s].slot, queue[%s].slot);' % (c, a, b)) + w('if (%s == 0) {' % c) + else: + w('if (queue[%s].value == queue[%s].value) {' % (a, b)) + w(' // Must break tie by docID') + w(' %s = queue[%s].docID > queue[%s].docID;' % (v, a, b)) + w('} else {') + if self.comp is not None or self.valueType is None: + w(' %s = %s > 0;' % (v, c)) + else: + w(' %s = queue[%s].value > queue[%s].value;' % (v, a, b)) + w('}') + w.releaseVar(c) + + def copy(self, src, dest): + self.w('queue[%s] = queue[%s];' % (dest, src)) + + def installBottom(self, dest): + self.w('queue[%s] = bottom;' % dest) + + def copyCurrentToBottom(self): + self.w('bottom.docID = fullDoc;') + if self.doTrackScores: + self.w('bottom.score = score;') + if self.comp is not None: + self.comp.copyCurrentToBottom() + elif self.valueType is not None: + self.w('bottomValue = bottom.value = docValues[doc];') + else: + if self.doTrackScores: + s = 'score' + else: + s = 'Float.NaN' + self.w('comp.copy(bottom.slot, doc, %s);' % s) + + def endInsert(self): + self.w('bottom = queue[1];') + if self.comp is not None: + self.comp.endInsert() + elif self.valueType is not None: + self.w('bottomValue = bottom.value;') + else: + self.w('comp.setBottom(bottom.slot);') + + def writeCompetes(self, q, docsInOrder=True): + w = self.w + + if self.doMaxScore: + q.writeScore(self) + w(' if (score > maxScore) {') + w(' maxScore = score;') + w(' }') + + if self.comp is not None: + self.comp.writeCompetes(q, docsInOrder) + elif self.valueType is None: + w(' final int cmp = comp.compareBottom(doc, Float.NaN);') + w(' if (cmp > 0) {') + elif docsInOrder: + w(' if (docValues[doc] < bottomValue) {') + else: + w(' if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) {') + + if self.doTrackScores: + q.writeScore(self) + + if DEBUG: + w(' System.out.println(" does compete bottom");') + + def swap(self, i, j): + w = self.w + w('final Entry tmp = queue[%s];' % i) + w('queue[%s] = queue[%s];' % (i, j)) + w('queue[%s] = tmp;' % j) + + def createTopDocs(self): + if self.doMaxScore: + x = 'maxScore' + else: + x = 'Float.NaN' + self.w('final TopDocs results = new TopFieldDocs(hitCount, hits, sort.getSort(), %s);' % x) + +class Query: + + def var(self, name): + return '%s%s%s' % (self.id, name[0].upper(), name[1:]) + + def pushFilters(self, doFilter, doDeletes): + self.doFilter = doFilter + self.doDeletes = doDeletes + for query in self.getSubQueries(): + query.pushFilters(doFilter, doDeletes) + + def setVars(self, docVar, scoreVar): + self.docVar = docVar + self.scoreVar = scoreVar + for query in self.getSubQueries(): + query.setVars(query.var('doc'), + query.var('score')) + +class TwoClauseOrQuery(Query): + + def __init__(self, q1, q2): + self.q1 = q1 + self.q2 = q2 + + def getSubQueries(self): + return (self.q1, self.q2) + + def writeTopClass(self, c): + w = self.w + self.c = c + c.docsAlwaysInOrder = False + w('private static final class Bucket {') + w(' int doc = -1;') + if c.doTrackScores or c.doMaxScore: + w(' float score;') + w(' int coord;') + #w(' int bits;') + w(' Bucket next;') + w('}') + w('private final Bucket FIRST_BUCKET = new Bucket();') + + def setWriter(self, w): + self.w = w + self.id = w.getID() + self.q1.setWriter(w) + self.q2.setWriter(w) + + def writeScore(self, c): + pass + + def writeTop(self, c, qVar): + w = self.w + w('final BooleanClause[] clauses = ((BooleanQuery) q).getClauses();') + w('final Query q1 = clauses[0].getQuery();') + w('final Query q2 = clauses[1].getQuery();') + if c.doTrackScores or c.doMaxScore: + w('final Weight %s = ((BooleanQuery.BooleanWeight) %s).subWeight(0);' % \ + (self.q1.var('weight'), self.var('weight'))) + w('final Weight %s = ((BooleanQuery.BooleanWeight) %s).subWeight(1);' % \ + (self.q2.var('weight'), self.var('weight'))) + self.q1.writeTop(c, 'q1') + self.q2.writeTop(c, 'q2') + w('final Bucket[] buckets = new Bucket[%d];' % self.CHUNK) + w('final int MASK = %d;' % (self.CHUNK-1)) + if c.doTrackScores or c.doMaxScore: + w('final float coordFactors[] = new float[3];') + for i in range(3): + w('coordFactors[%d] = sim.coord(%d, 2);' % (i, i)) + + def writePerReader(self, c): + self.q1.writePerReader(c) + self.q2.writePerReader(c) + self.w('int limit = 0;') + self.q1.next() + self.q2.next() + + CHUNK = 1024 + + def writeOneSubCollect(self, q): + w = self.w + w('while(%s < limit) {' % q.docVar) + w(' final int x = %s & MASK;' % q.docVar) + w(' Bucket b = buckets[x];') + w(' if (b == null) {') + w(' b = buckets[x] = new Bucket();') + w(' }') + if self.c.doTrackScores or self.c.doMaxScore: + # TODO: pass in b.score as scorevar + q.writeScore(self.c) + w(' if (b.doc != %s) {' % q.docVar) + w(' b.doc = %s;' % q.docVar) + if self.c.doTrackScores or self.c.doMaxScore: + w(' b.score = %s;' % q.scoreVar) + w(' b.coord = 1;') + w(' lastBucket.next = b;') + w(' lastBucket = b;') + if self.c.doTrackScores or self.c.doMaxScore: + w(' } else {') + w(' b.score += %s;' % q.scoreVar) + w(' b.coord++;') + w(' }') + q.next() + w('}') + + def writeTopIter(self, c): + w = self.w + w('while(limit < maxDoc) { // loop for all hits') + w(' limit += %d;' % self.CHUNK) + w(' if (limit > maxDoc) {') + w(' limit = maxDoc;') + w(' }') + w('Bucket lastBucket = FIRST_BUCKET;') + w('// loop for q1 chunk') + self.writeOneSubCollect(self.q1) + w('// loop for q2 chunk') + self.writeOneSubCollect(self.q2) + w(' lastBucket.next = null;') + w(' // now collect') + w(' Bucket b = FIRST_BUCKET.next;') + w(' while (b != null) {') + w(' final int doc = b.doc;') + if c.doTrackScores or c.doMaxScore: + w(' final float score = b.score * coordFactors[b.coord];') + c.collectOne(self, False, False) + w(' b = b.next;') + w(' }') + w(' if (limit == r.maxDoc()) {') + w(' break;') + w(' }') + w('}') + +class TermQuery(Query): + + SCORE_CACHE_SIZE = 32 + BLOCK_SIZE = 32 + + didScore = False + + def setWriter(self, w): + self.w = w + self.id = w.getID() + + def getSubQueries(self): + return () + + def writeTopClass(self, c): + pass + + def releaseVar(self, v): + self.w.releaseVar(v) + + def writeScore(self, c): + w = self.w + if not self.didScore: + self.didScore = True + w(' final float %s = (%s < %d ? %s[%s] : sim.tf(%s)*%s) * normDecoder[%s[%s] & 0xFF];' % \ + (self.scoreVar, + self.var('freq'), + self.SCORE_CACHE_SIZE, + self.var('scoreCache'), + self.var('freq'), + self.var('freq'), + self.var('weightValue'), + self.var('norms'), + self.docVar)) + + def writeTop(self, c, qVar): + w = self.w + w('final Term %s = ((TermQuery) %s).getTerm();' % (self.var('t'), qVar)) + + if c.needsScores(): + w('final float[] %s = new float[%s];' % (self.var('scoreCache'), self.SCORE_CACHE_SIZE)) + w('final float %s = %s.getValue();' % \ + (self.var('weightValue'), self.var('weight'))) + w('for(int i=0;i<%s;i++) {' % self.SCORE_CACHE_SIZE) + w(' %s[i] = sim.tf(i) * %s;' % (self.var('scoreCache'), self.var('weightValue'))) + w('}') + + def writePerReader(self, c): + w = self.w + if c.needsScores(): + w('final byte[] %s = r.norms(%s.field());' % (self.var('norms'), self.var('t'))) + w('int %s = 0;' % self.docVar) + w('int %s = 0;' % self.var('freq')) + w('// only used to get the raw freqStream & limit') + w('final TermDocs %s = r.termDocs(%s);' % (self.var('TD'), self.var('t'))) + w('final IndexInput %s = ((SegmentTermDocs) %s).getFreqStream();' % (self.var('freqStream'), + self.var('TD'))) + w('final int %s = ((SegmentTermDocs ) %s).getTermFreq();' % (self.var('limit'), + self.var('TD'))) + w('int %s = 0;' % self.var('count')) + + def next(self): + w = self.w + if self.doFilter or self.doDeletes: + w('while(true) { // until we find a non-deleted & non-filtered-out doc') + w('if (++%s > %s) {' % (self.var('count'), self.var('limit'))) + w(' %s = %s;' % (self.docVar, END_DOC)) + if self.doFilter or self.doDeletes: + w(' break;') + w('} else {') + w(' final int %s = %s.readVInt();' % (self.var('x'), self.var('freqStream'))) + w(' %s += %s>>>1;' % (self.docVar, self.var('x'))) + if self.doFilter: + w(' // Filter has pre-folded deletes in') + w(' if (!filterBits.fastGet(%s)) {' % self.docVar) + w(' if ((%s & 1) == 0) {' % self.var('x')) + w(' // Skip freq') + w(' %s.readVInt();' % self.var('freqStream')) + w(' }') + w(' continue;') + w(' } else {') + w(' if ((%s&1) != 0) {' % self.var('x')) + w(' %s = 1;' % self.var('freq')) + w(' } else {') + w(' %s = %s.readVInt();' % (self.var('freq'), self.var('freqStream'))) + w(' }') + w(' break;') + w(' }') + elif self.doDeletes: + w(' if (deletedDocs != null && deletedDocs.get(%s)) {' % self.docVar) + w(' if ((%s & 1) == 0) {' % self.var('x')) + w(' // Skip freq') + w(' %s.readVInt();' % self.var('freqStream')) + w(' }') + w(' continue;') + w(' } else {') + w(' if ((%s&1) != 0) {' % self.var('x')) + w(' %s = 1;' % self.var('freq')) + w(' } else {') + w(' %s = %s.readVInt();' % (self.var('freq'), self.var('freqStream'))) + w(' }') + w(' break;') + w(' }') + else: + w(' if ((%s&1) != 0) {' % self.var('x')) + w(' %s = 1;' % self.var('freq')) + w(' } else {') + w(' %s = %s.readVInt();' % (self.var('freq'), self.var('freqStream'))) + w(' }') + w(' }') + if self.doFilter or self.doDeletes: + w(' }') + +DEBUG = '-verbose' in sys.argv + +def writeTopIter(q, c): + w = q.w + w('while(true) { // until we are done collecting hits from this reader') + q.next() + c.collectOne(q) + w('}') + + +def gen(w, query, c, doFilter, doDeletes, fileName): + + query.setWriter(w) + query.setVars('doc', 'score') + + w('package org.apache.lucene.search;') + + w('import org.apache.lucene.util.*;') + w('import org.apache.lucene.store.*;') + w('import org.apache.lucene.search.FieldCache.StringIndex;') + w('import org.apache.lucene.index.*;') + w('import java.io.IOException;') + w('import java.util.Arrays;') + + className = os.path.splitext(os.path.split(fileName)[1])[0] + + w('final class %s extends SpecSearch {' % className) + + c.writeTopClass() + query.writeTopClass(c) + + w(' public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException {') + + c.topInit() + + w(' final float[] normDecoder = Similarity.getNormDecoder();') + w(' final Similarity sim = searcher.getSimilarity();') + w(' final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders();') + w(' final int[] docBases = new int[subReaders.length];') + w(' {') + w(' int docBase = 0;') + w(' for(int rx=0;rx compiletop.log 2>&1') != 0: + raise RuntimeError('compile failed (see compiletop.log)') + +if 1: + print 'gen...' + import genall + genall.main() + +os.chdir('../benchmark') + +if 1: + if '-nocompile' not in sys.argv: + print 'compile...' + if os.system('ant compile > compile.log 2>&1') != 0: + print open('compile.log').read() + raise RuntimeError('compile failed (see compile.log)') + +if windows: + RESULTS = 'results.win64' +else: + RESULTS = 'results' + +VERIFY = '-verify' in sys.argv + +ALG = ''' +analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer +directory=FSDirectory +work.dir = $INDEX$ +search.num.hits = 10 +query.maker=org.apache.lucene.benchmark.byTask.feeds.FileBasedQueryMaker +file.query.maker.file = queries.txt +log.queries=true +filter.pct = $FILT$ +search.spec = $SEARCH_SPEC$ + +OpenReader +{"XSearchWarm" $SEARCH$} +$ROUNDS$ +CloseReader +RepSumByPrefRound XSearch +''' + +if os.path.exists('searchlogs'): + shutil.rmtree('searchlogs') + +os.makedirs('searchlogs') + +open('%s.txt' % RESULTS, 'wb').write('||Query||Sort||Filt|Deletes||Scoring||Hits||QPS (base)||QPS (new)||%||\n') + +numHit = 10 +counter = 0 + +if '-delindex' in sys.argv: + i = sys.argv.index('-delindex') + DEL_INDEX = sys.argv[1+i] + del sys.argv[i:i+2] + if False and not os.path.exists(DEL_INDEX): + raise RuntimeError('index "%s" does not exist' % DEL_INDEX) +else: + DEL_INDEX = None + +if '-nodelindex' in sys.argv: + i = sys.argv.index('-nodelindex') + NO_DEL_INDEX = sys.argv[1+i] + del sys.argv[i:i+2] + if False and not os.path.exists(NO_DEL_INDEX): + raise RuntimeError('index "%s" does not exist' % NO_DEL_INDEX) +else: + NO_DEL_INDEX = None + +if DEL_INDEX is None and NO_DEL_INDEX is None: + raise RuntimeError('you must specify at least one of -delindex or -nodelindex') + +def boolToYesNo(b): + if b: + return 'true' + else: + return 'false' + +def run(new, query, sortField, doScore, filt, delP): + global counter + + t0 = time.time() + + s = ALG + + if not VERIFY: + s = s.replace('$ROUNDS$', +''' +{ "Rounds" + { "Run" + { "TestSearchSpeed" + { "XSearchReal" $SEARCH$ > : 3.0s + } + NewRound + } : $NROUND$ +} +''') + nround = 5 + s = s.replace('$NROUND$', str(nround)) + else: + s = s.replace('$ROUNDS$', '') + + if linux: + prefix = '/big/scratch/lucene' + else: + prefix = '/lucene' + + if delP is None: + index = NO_DEL_INDEX + else: + index = DEL_INDEX + + s = s.replace('$INDEX$', index) + + open('queries.txt', 'wb').write(query + '\n') + + if filt == None: + f = '0.0' + else: + f = str(filt) + s = s.replace('$FILT$', f) + + if doScore == 'both': + doTrackScores = True + doMaxScore = True + elif doScore == 'track': + doTrackScores = True + doMaxScore = False + elif doScore == 'no': + doTrackScores = False + doMaxScore = False + + s = s.replace('$SEARCH_SPEC$', boolToYesNo(new)) + + l = [] + if not doMaxScore: + l.append('nomaxscore') + if not doTrackScores: + l.append('noscore') + + if len(l) > 0: + sv = ',%s' % (','.join(l)) + else: + sv = '' + + if sortField == 'score': + search = 'Search' + elif sortField == 'doctitle': + search = 'SearchWithSort(doctitle:string%s)' % sv + elif sortField == 'docdate': + search = 'SearchWithSort(docdate:long%s)' % sv + else: + raise RuntimeError("no") + + s = s.replace('$SEARCH$', search) + fileOut = 'searchlogs/%d' % counter + counter += 1 + + if 0: + fileOut = 'searchlogs/query_%s_%s_%s_%s_%s_%s' % \ + (query.replace(' ', '_').replace('"', ''), + sortField, filt, doScore, new, delP) + + open('tmp.alg', 'wb').write(s) + + if windows: + command = 'java -Xms1024M -Xmx1024M -Xbatch -server -cp "../../build/classes/java;../../build/classes/demo;../../build/contrib/highlighter/classes/java;../../build/contrib/spec/classes/java;../../contrib/benchmark/lib/commons-digester-1.7.jar;../../contrib/benchmark/lib/commons-collections-3.1.jar;../../contrib/benchmark/lib/commons-logging-1.0.4.jar;../../contrib/benchmark/lib/commons-beanutils-1.7.0.jar;../../contrib/benchmark/lib/xerces-2.9.0.jar;../../contrib/benchmark/lib/xml-apis-2.9.0.jar;../../build/contrib/benchmark/classes/java" org.apache.lucene.benchmark.byTask.Benchmark tmp.alg > %s' % fileOut + else: + command = 'java -Xms1024M -Xmx1024M -Xbatch -server -cp ../../build/classes/java:../../build/classes/demo:../../build/contrib/highlighter/classes/java:../../build/contrib/spec/classes/java:../../contrib/benchmark/lib/commons-digester-1.7.jar:../../contrib/benchmark/lib/commons-collections-3.1.jar:../../contrib/benchmark/lib/commons-logging-1.0.4.jar:../../contrib/benchmark/lib/commons-beanutils-1.7.0.jar:../../contrib/benchmark/lib/xerces-2.9.0.jar:../../contrib/benchmark/lib/xml-apis-2.9.0.jar:../../build/contrib/benchmark/classes/java org.apache.lucene.benchmark.byTask.Benchmark tmp.alg > %s' % fileOut + + print ' %s' % fileOut + + res = os.system(command) + + if res != 0: + raise RuntimeError('FAILED') + + best = None + count = 0 + nhits = None + warmTime = None + meths = [] + r = re.compile('^ ([0-9]+): (.*)$') + topN = [] + sawSpec = False + + for line in open(fileOut, 'rb').readlines(): + m = r.match(line.rstrip()) + if m is not None: + topN.append(m.group(2)) + if line.find('SPEC search') != -1: + sawSpec = True + if line.startswith('NUMHITS='): + nhits = int(line[8:].strip()) + if line.startswith('XSearchWarm'): + v = line.strip().split() + warmTime = float(v[5]) + if line.startswith('XSearchReal'): + v = line.strip().split() + # print len(v), v + upto = 0 + i = 0 + qps = None + while i < len(v): + if v[i] == '-': + i += 1 + continue + else: + upto += 1 + i += 1 + if upto == 5: + #print 'GOT: %s' % v[i-1] + qps = float(v[i-1].replace(',', '')) + break + + if qps is None: + raise RuntimeError('did not find qps') + + count += 1 + if best is None or qps > best: + best = qps + + if sawSpec != new: + raise RuntimeError('spec did not kick in properly') + + if not VERIFY: + if count != nround: + raise RuntimeError('did not find %s rounds (got %s)' % (nround, count)) + + if warmTime is None: + raise RuntimeError('did not find warm time') + + if nhits is None: + raise RuntimeError('did not see NUMHITS=line') + + # print ' NHIT: %s' % nhits + + # print ' %.1f qps; %.1f sec' % (best, time.time()-t0) + all.append((new, query, sortBy, filt, nhits, warmTime, best)) + else: + best = 1.0 + + return nhits, best, topN + +def cleanScores(l): + for i in range(len(l)): + pos = l[i].find(' score=') + l[i] = l[i][:pos].strip() + +all = [] + +if VERIFY: + filts = (10.0, None, 25.0) +else: + filts = (None, 25.0) + +queries = ('1 OR 2',) + +if VERIFY: + #queries = ('1147',) + #queries = ('1', '1 OR 2') + queries = ('1 OR 2', '1') +else: + queries = ('1 OR 2') + +if VERIFY: + sort = ('doctitle', 'docdate', 'score') +else: + sort = ('score', 'docdate', 'doctitle') + +deletes = (None, 5) + +if VERIFY: + doScores = ('no', 'both', 'track') +else: + doScores = ('no', 'track') + +for query in queries: + for sortBy in sort: + + if sortBy == 'score': + doScores0 = ('both',) + else: + doScores0 = doScores + + for doScore in doScores0: + for filt in filts: + for delP in deletes: + + if delP is None and NO_DEL_INDEX is None: + continue + if delP is not None and DEL_INDEX is None: + continue + + print + print 'RUN: query=%s sort=%s scores=%s filt=%s deletes=%s [%s]' % (query, sortBy, doScore, filt, delP, datetime.datetime.now()) + print ' new...' + nhits1, qps1, topN1 = run(True, query, sortBy, doScore, filt, delP) + print ' qps %.2f' % qps1 + print ' old...' + nhits2, qps2, topN2 = run(False, query, sortBy, doScore, filt, delP) + print ' qps %.2f' % qps2 + print ' %d hits' % nhits1 + print ' %.1f%%' % (100.*(qps1-qps2)/qps2) + + f = open('%s.pk' % RESULTS, 'wb') + cPickle.dump(all, f) + f.close() + + if nhits1 != nhits2: + raise RuntimeError('hits differ: %s vs %s' % (nhits1, nhits2)) + + if len(topN1) != numHit: + raise RuntimeError('not enough hits: %s vs %s' % (len(topN1), nhits1)) + + if topN1 != topN2: + if doScore == 'no': + cleanScores(topN1) + cleanScores(topN2) + if topN1 != topN2: + raise RuntimeError('results differ') + else: + raise RuntimeError('results differ') + + if sortBy == 'score': + s0 = 'Relevance' + elif sortBy == 'doctitle': + s0 = 'Title (string)' + elif sortBy == 'docdate': + s0 = 'Date (long)' + + if filt == None: + f = 'no' + else: + f = '%d%%' % filt + + if delP == None: + d = 'no' + else: + d = '%d%%' % delP + + if doScore == 'both': + s = 'Track,Max' + elif doScore == 'track': + s = 'Track' + else: + s = 'no' + + pct = (qps1-qps2)/qps2 + if pct <= 0.0: + color = 'red' + else: + color = 'green' + p = '{color:%s}%.1f%%{color}' % (color, 100.*pct) + + open('%s.txt' % RESULTS, 'ab').write('|%s|%s|%s|%s|%s|%d|%.1f|%.1f|%s|\n' % \ + (query, s0, f, d, s, nhits1, qps2, qps1, p)) Index: contrib/spec/verify.cmd =================================================================== --- contrib/spec/verify.cmd (revision 0) +++ contrib/spec/verify.cmd (revision 0) @@ -0,0 +1 @@ +python -u bench.py -delindex /lucene/work.wikifull.8seg.5pdel -nodelindex /lucene/work.wikifull.8seg -verify Index: contrib/spec/src/java/org/apache/lucene/search/Spec_QueryTwoClauseOr_SortDouble_FilterNo_DeletesYes_TrackScoresNo_MaxScoreNo.java =================================================================== --- contrib/spec/src/java/org/apache/lucene/search/Spec_QueryTwoClauseOr_SortDouble_FilterNo_DeletesYes_TrackScoresNo_MaxScoreNo.java (revision 0) +++ contrib/spec/src/java/org/apache/lucene/search/Spec_QueryTwoClauseOr_SortDouble_FilterNo_DeletesYes_TrackScoresNo_MaxScoreNo.java (revision 0) @@ -0,0 +1,307 @@ +package org.apache.lucene.search; +import org.apache.lucene.util.*; +import org.apache.lucene.store.*; +import org.apache.lucene.search.FieldCache.StringIndex; +import org.apache.lucene.index.*; +import java.io.IOException; +import java.util.Arrays; +final class Spec_QueryTwoClauseOr_SortDouble_FilterNo_DeletesYes_TrackScoresNo_MaxScoreNo extends SpecSearch { + final private static class Entry { + // local inlined value + double value; + int docID; + } + private static final class Bucket { + int doc = -1; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // pre-fill queue with "bottom" + final double sentinel; + if (sortField.getReverse()) { + sentinel = Double.MIN_VALUE; + } else { + sentinel = Double.MAX_VALUE; + } + // queue[0] is never used + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.value = sentinel; + } + Entry bottom = queue[1]; + double bottomValue = sentinel; + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > bottomScore || (score == bottomScore && fullDoc < bottomDoc)) { + + queueDocs[1] = fullDoc; + queueScores[1] = score; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queueScores[j0] > score || (queueScores[j0] == score && queueDocs[j0] < fullDoc)) { + break; + } + queueDocs[i0] = queueDocs[j0]; + queueScores[i0] = queueScores[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + } + queueDocs[i0] = fullDoc; + queueScores[i0] = score; + bottomScore = queueScores[1]; + bottomDoc = queueDocs[1]; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + final float maxScore = queueScores[1]; + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt = queueScores[i] < queueScores[j] || (queueScores[i] == queueScores[j] && queueDocs[i] > queueDocs[j]); + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final int itmp = queueDocs[i]; + queueDocs[i] = queueDocs[j]; + queueDocs[j] = itmp; + final float ftmp = queueScores[i]; + queueScores[i] = queueScores[j]; + queueScores[j] = ftmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > bottomScore) { + + final int fullDoc = doc + docBase; + queueDocs[1] = fullDoc; + queueScores[1] = score; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queueScores[j0] >= score) { + break; + } + queueDocs[i0] = queueDocs[j0]; + queueScores[i0] = queueScores[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + } + queueDocs[i0] = fullDoc; + queueScores[i0] = score; + bottomScore = queueScores[1]; + } + } + } + + final float maxScore = queueScores[1]; + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt = queueScores[i] < queueScores[j] || (queueScores[i] == queueScores[j] && queueDocs[i] > queueDocs[j]); + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final int itmp = queueDocs[i]; + queueDocs[i] = queueDocs[j]; + queueDocs[j] = itmp; + final float ftmp = queueScores[i]; + queueScores[i] = queueScores[j]; + queueScores[j] = ftmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > bottomScore || (score == bottomScore && fullDoc < bottomDoc)) { + + queueDocs[1] = fullDoc; + queueScores[1] = score; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queueScores[j0] > score || (queueScores[j0] == score && queueDocs[j0] < fullDoc)) { + break; + } + queueDocs[i0] = queueDocs[j0]; + queueScores[i0] = queueScores[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + } + queueDocs[i0] = fullDoc; + queueScores[i0] = score; + bottomScore = queueScores[1]; + bottomDoc = queueDocs[1]; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + final float maxScore = queueScores[1]; + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt = queueScores[i] < queueScores[j] || (queueScores[i] == queueScores[j] && queueDocs[i] > queueDocs[j]); + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final int itmp = queueDocs[i]; + queueDocs[i] = queueDocs[j]; + queueDocs[j] = itmp; + final float ftmp = queueScores[i]; + queueScores[i] = queueScores[j]; + queueScores[j] = ftmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > bottomScore) { + + final int fullDoc = doc + docBase; + queueDocs[1] = fullDoc; + queueScores[1] = score; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queueScores[j0] >= score) { + break; + } + queueDocs[i0] = queueDocs[j0]; + queueScores[i0] = queueScores[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + } + queueDocs[i0] = fullDoc; + queueScores[i0] = score; + bottomScore = queueScores[1]; + } + } + } + + final float maxScore = queueScores[1]; + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt = queueScores[i] < queueScores[j] || (queueScores[i] == queueScores[j] && queueDocs[i] > queueDocs[j]); + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final int itmp = queueDocs[i]; + queueDocs[i] = queueDocs[j]; + queueDocs[j] = itmp; + final float ftmp = queueScores[i]; + queueScores[i] = queueScores[j]; + queueScores[j] = ftmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > bottomScore) { + + final int fullDoc = doc + docBase; + queueDocs[1] = fullDoc; + queueScores[1] = score; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queueScores[j0] >= score) { + break; + } + queueDocs[i0] = queueDocs[j0]; + queueScores[i0] = queueScores[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + } + queueDocs[i0] = fullDoc; + queueScores[i0] = score; + bottomScore = queueScores[1]; + } + } + } + + final float maxScore = queueScores[1]; + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt = queueScores[i] < queueScores[j] || (queueScores[i] == queueScores[j] && queueDocs[i] > queueDocs[j]); + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final int itmp = queueDocs[i]; + queueDocs[i] = queueDocs[j]; + queueDocs[j] = itmp; + final float ftmp = queueScores[i]; + queueScores[i] = queueScores[j]; + queueScores[j] = ftmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + float score; + int coord; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + private static final class Bucket { + int doc = -1; + Bucket next; + } + private final Bucket FIRST_BUCKET = new Bucket(); + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + int bottomDoc = Integer.MAX_VALUE; + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + final int cx = competes(bottom, order[doc], lookup[order[doc]]); + if (cx > 0 || (cx == 0 && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c < 0 || (c == 0 && queue[j0].docID < bottom.docID)) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > bottomScore || (score == bottomScore && fullDoc < bottomDoc)) { + + queueDocs[1] = fullDoc; + queueScores[1] = score; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queueScores[j0] > score || (queueScores[j0] == score && queueDocs[j0] < fullDoc)) { + break; + } + queueDocs[i0] = queueDocs[j0]; + queueScores[i0] = queueScores[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt = queueScores[k0] < queueScores[j0] || (queueScores[k0] == queueScores[j0] && queueDocs[k0] > queueDocs[j0]); + if (lt) { + j0 = k0; + } + } + } + queueDocs[i0] = fullDoc; + queueScores[i0] = score; + bottomScore = queueScores[1]; + bottomDoc = queueDocs[1]; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + final float maxScore = queueScores[1]; + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt = queueScores[i] < queueScores[j] || (queueScores[i] == queueScores[j] && queueDocs[i] > queueDocs[j]); + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final int itmp = queueDocs[i]; + queueDocs[i] = queueDocs[j]; + queueDocs[j] = itmp; + final float ftmp = queueScores[i]; + queueScores[i] = queueScores[j]; + queueScores[j] = ftmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + float maxScore = Float.NEGATIVE_INFINITY; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.score = Float.NEGATIVE_INFINITY; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if (deletedDocs != null && deletedDocs.get(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.score = score; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + final float score = (q0Freq < 32 ? q0ScoreCache[q0Freq] : sim.tf(q0Freq)*q0WeightValue) * normDecoder[q0Norms[doc] & 0xFF]; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q1Doc) { + b.doc = q1Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if (deletedDocs != null && deletedDocs.get(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + if (b.doc != q2Doc) { + b.doc = q2Doc; + lastBucket.next = b; + lastBucket = b; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if (deletedDocs != null && deletedDocs.get(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i>> 1; + String midVal = a[mid]; + int cmp; + if (midVal != null) { + cmp = midVal.compareTo(key); + } else { + cmp = -1; + } + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; + } + return -(low + 1); + } + public TopDocs search(final IndexSearcher searcher, final Query q, final Filter filter, final Sort sort, final int topN) throws IOException { + int hitCount = 0; + final SortField sortField = sort.getSort()[0]; + final String sortFieldID = sortField.getField(); + final Entry[] queue = new Entry[1+topN]; + // U+FFFF is not a valid unicode char, so this is a safe sentinel + final String sentinel = new String("\uFFFF"); + for (int x=1;x<=topN;x++) { + final Entry e = queue[x] = new Entry(); + e.docID = Integer.MAX_VALUE; + e.ord = Integer.MAX_VALUE; + e.val = sentinel; + } + Entry bottom = queue[1]; + final FieldComparator comp = sort.getSort()[0].getComparator(topN, 0, false); + final float[] normDecoder = Similarity.getNormDecoder(); + final Similarity sim = searcher.getSimilarity(); + final IndexReader[] subReaders = searcher.getIndexReader().getSequentialSubReaders(); + final int[] docBases = new int[subReaders.length]; + { + int docBase = 0; + for(int rx=0;rx q0Limit) { + doc = 2147483647; + break; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(doc)) { + if ((q0X & 1) == 0) { + // Skip freq + q0FreqStream.readVInt(); + } + continue; + } else { + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + break; + } + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (competes(bottom, order[doc], lookup[order[doc]]) > 0) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottom.ord = order[doc]; + bottom.val = lookup[bottom.ord]; + bottom.readerGen = rx; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + final int c = compareOrdVal(queue[j0], bottom); + if (c <= 0) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + final int c0 = compareOrdVal(queue[k0], queue[j0]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = c0 > 0; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + if (bottom.readerGen != rx) { + if (bottom.val != null) { + final int index = binarySearch(lookup, bottom.val); + if (index < 0) { + bottom.ord = -index-2; + } else { + bottom.ord = index; + } + } else { + bottom.ord = 0; + } + bottom.readerGen = rx; + } + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + final int c0 = compareOrdVal(queue[i], queue[j]); + if (c0 == 0) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = c0 > 0; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q0Limit) { + doc = 2147483647; + } else { + final int q0X = q0FreqStream.readVInt(); + doc += q0X>>>1; + if ((q0X&1) != 0) { + q0Freq = 1; + } else { + q0Freq = q0FreqStream.readVInt(); + } + } + if (doc == 2147483647) { + break; + } + hitCount++; + if (docValues[doc] < bottomValue) { + + final int fullDoc = doc + docBase; + bottom.docID = fullDoc; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + while(limit < maxDoc) { // loop for all hits + limit += 1024; + if (limit > maxDoc) { + limit = maxDoc; + } + Bucket lastBucket = FIRST_BUCKET; + // loop for q1 chunk + while(q1Doc < limit) { + final int x = q1Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q1Score = (q1Freq < 32 ? q1ScoreCache[q1Freq] : sim.tf(q1Freq)*q1WeightValue) * normDecoder[q1Norms[q1Doc] & 0xFF]; + if (b.doc != q1Doc) { + b.doc = q1Doc; + b.score = q1Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q1Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q1Count > q1Limit) { + q1Doc = 2147483647; + break; + } else { + final int q1X = q1FreqStream.readVInt(); + q1Doc += q1X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q1Doc)) { + if ((q1X & 1) == 0) { + // Skip freq + q1FreqStream.readVInt(); + } + continue; + } else { + if ((q1X&1) != 0) { + q1Freq = 1; + } else { + q1Freq = q1FreqStream.readVInt(); + } + break; + } + } + } + } + // loop for q2 chunk + while(q2Doc < limit) { + final int x = q2Doc & MASK; + Bucket b = buckets[x]; + if (b == null) { + b = buckets[x] = new Bucket(); + } + final float q2Score = (q2Freq < 32 ? q2ScoreCache[q2Freq] : sim.tf(q2Freq)*q2WeightValue) * normDecoder[q2Norms[q2Doc] & 0xFF]; + if (b.doc != q2Doc) { + b.doc = q2Doc; + b.score = q2Score; + b.coord = 1; + lastBucket.next = b; + lastBucket = b; + } else { + b.score += q2Score; + b.coord++; + } + while(true) { // until we find a non-deleted & non-filtered-out doc + if (++q2Count > q2Limit) { + q2Doc = 2147483647; + break; + } else { + final int q2X = q2FreqStream.readVInt(); + q2Doc += q2X>>>1; + // Filter has pre-folded deletes in + if (!filterBits.fastGet(q2Doc)) { + if ((q2X & 1) == 0) { + // Skip freq + q2FreqStream.readVInt(); + } + continue; + } else { + if ((q2X&1) != 0) { + q2Freq = 1; + } else { + q2Freq = q2FreqStream.readVInt(); + } + break; + } + } + } + } + lastBucket.next = null; + // now collect + Bucket b = FIRST_BUCKET.next; + while (b != null) { + final int doc = b.doc; + final float score = b.score * coordFactors[b.coord]; + hitCount++; + final int fullDoc = doc + docBase; + if (score > maxScore) { + maxScore = score; + } + if (docValues[doc] < bottomValue || (docValues[doc] == bottomValue && fullDoc < bottom.docID)) { + + bottom.docID = fullDoc; + bottom.score = score; + bottomValue = bottom.value = docValues[doc]; + + // downheap + int i0 = 1; + int j0 = i0 << 1; + int k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + while(j0 <= topN) { + if (queue[j0].value == bottomValue) { + // Must break tie by docID + if (queue[j0].docID < bottom.docID) { + break; + } + } else if (queue[j0].value < bottomValue) { + break; + } + queue[i0] = queue[j0]; + i0 = j0; + j0 = i0 << 1; + k0 = j0+1; + if (k0 <= topN) { + final boolean lt; + if (queue[k0].value == queue[j0].value) { + // Must break tie by docID + lt = queue[k0].docID > queue[j0].docID; + } else { + lt = queue[k0].value > queue[j0].value; + } + if (lt) { + j0 = k0; + } + } + } + queue[i0] = bottom; + bottom = queue[1]; + bottomValue = bottom.value; + } + b = b.next; + } + if (limit == r.maxDoc()) { + break; + } + } + } + + // Build results -- sort pqueue entries + final SorterTemplate sorter = new SorterTemplate() { + protected int compare(int i, int j) { + final boolean lt; + if (queue[i].value == queue[j].value) { + // Must break tie by docID + lt = queue[i].docID > queue[j].docID; + } else { + lt = queue[i].value > queue[j].value; + } + if (lt) { + return 1; + } else { + // pq entries are never equal + return -1; + } + } + protected void swap(int i, int j) { + final Entry tmp = queue[i]; + queue[i] = queue[j]; + queue[j] = tmp; + } + }; + // Extract results + final int numHits = hitCount > topN ? topN : hitCount; + sorter.quickSort(1, numHits); + final ScoreDoc[] hits = new ScoreDoc[numHits]; + for(int i=0;i + + + + + + + Fast source-code specialized search + + + +