public MergeSortQueue(Sort sort, TopDocs[] shardHits) : base(shardHits.Length) { this.shardHits = new ScoreDoc[shardHits.Length][]; for (int shardIDX = 0; shardIDX < shardHits.Length; shardIDX++) { ScoreDoc[] shard = shardHits[shardIDX].ScoreDocs; //System.out.println(" init shardIdx=" + shardIDX + " hits=" + shard); if (shard != null) { this.shardHits[shardIDX] = shard; // Fail gracefully if API is misused: for (int hitIDX = 0; hitIDX < shard.Length; hitIDX++) { ScoreDoc sd = shard[hitIDX]; if (!(sd is FieldDoc)) { throw new System.ArgumentException("shard " + shardIDX + " was not sorted by the provided Sort (expected FieldDoc but got ScoreDoc)"); } FieldDoc fd = (FieldDoc)sd; if (fd.Fields == null) { throw new System.ArgumentException("shard " + shardIDX + " did not set sort field values (FieldDoc.fields is null); you must pass fillFields=true to IndexSearcher.search on each shard"); } } } } SortField[] sortFields = sort.GetSort(); comparers = new FieldComparer[sortFields.Length]; reverseMul = new int[sortFields.Length]; for (int compIDX = 0; compIDX < sortFields.Length; compIDX++) { SortField sortField = sortFields[compIDX]; comparers[compIDX] = sortField.GetComparer(1, compIDX); reverseMul[compIDX] = sortField.IsReverse ? -1 : 1; } }
public TopDocs Call() { TopDocs docs = searcher.Search(Arrays.AsList(slice.Leaves), weight, after, nDocs); ScoreDoc[] scoreDocs = docs.ScoreDocs; //it would be so nice if we had a thread-safe insert @lock.Lock(); try { for (int j = 0; j < scoreDocs.Length; j++) // merge scoreDocs into hq { ScoreDoc scoreDoc = scoreDocs[j]; if (scoreDoc == hq.InsertWithOverflow(scoreDoc)) { break; } } } finally { @lock.Unlock(); } return(docs); }
public SearcherCallableNoSort(ReentrantLock @lock, IndexSearcher searcher, LeafSlice slice, Weight weight, ScoreDoc after, int nDocs, HitQueue hq) { this.@lock = @lock; this.searcher = searcher; this.weight = weight; this.after = after; this.nDocs = nDocs; this.hq = hq; this.slice = slice; }
/// <summary> /// Expert: Low-level search implementation. Finds the top <code>n</code> /// hits for <c>query</c>. /// /// <para/>Applications should usually call <see cref="IndexSearcher.Search(Query,int)"/> or /// <see cref="IndexSearcher.Search(Query,Filter,int)"/> instead. </summary> /// <exception cref="BooleanQuery.TooManyClausesException"> If a query would exceed /// <see cref="BooleanQuery.MaxClauseCount"/> clauses. </exception> protected virtual TopDocs Search(IList <AtomicReaderContext> leaves, Weight weight, ScoreDoc after, int nDocs) { // single thread int limit = reader.MaxDoc; if (limit == 0) { limit = 1; } nDocs = Math.Min(nDocs, limit); TopScoreDocCollector collector = TopScoreDocCollector.Create(nDocs, after, !weight.ScoresDocsOutOfOrder); Search(leaves, weight, collector); return(collector.GetTopDocs()); }
/// <summary> /// Finds the top <paramref name="n"/> /// hits for <paramref name="query"/>, applying <paramref name="filter"/> if non-null, /// where all results are after a previous result (<paramref name="after"/>). /// <para/> /// By passing the bottom result from a previous page as <paramref name="after"/>, /// this method can be used for efficient 'deep-paging' across potentially /// large result sets. /// </summary> /// <exception cref="BooleanQuery.TooManyClausesException"> If a query would exceed /// <see cref="BooleanQuery.MaxClauseCount"/> clauses. </exception> public virtual TopDocs SearchAfter(ScoreDoc after, Query query, Filter filter, int n) { return(Search(CreateNormalizedWeight(WrapFilter(query, filter)), after, n)); }
/// <summary> /// Finds the top <paramref name="n"/> /// hits for top <paramref name="query"/> where all results are after a previous /// result (top <paramref name="after"/>). /// <para/> /// By passing the bottom result from a previous page as <paramref name="after"/>, /// this method can be used for efficient 'deep-paging' across potentially /// large result sets. /// </summary> /// <exception cref="BooleanQuery.TooManyClausesException"> If a query would exceed /// <see cref="BooleanQuery.MaxClauseCount"/> clauses. </exception> public virtual TopDocs SearchAfter(ScoreDoc after, Query query, int n) { return(Search(CreateNormalizedWeight(query), after, n)); }
internal InOrderPagingScoreDocCollector(ScoreDoc after, int numHits) : base(numHits) { this.after = after; }
public override TopDocs Rescore(IndexSearcher searcher, TopDocs firstPassTopDocs, int topN) { ScoreDoc[] hits = (ScoreDoc[])firstPassTopDocs.ScoreDocs.Clone(); Array.Sort(hits, Comparer <ScoreDoc> .Create((a, b) => a.Doc - b.Doc)); IList <AtomicReaderContext> leaves = searcher.IndexReader.Leaves; Weight weight = searcher.CreateNormalizedWeight(query); // Now merge sort docIDs from hits, with reader's leaves: int hitUpto = 0; int readerUpto = -1; int endDoc = 0; int docBase = 0; Scorer scorer = null; while (hitUpto < hits.Length) { ScoreDoc hit = hits[hitUpto]; int docID = hit.Doc; AtomicReaderContext readerContext = null; while (docID >= endDoc) { readerUpto++; readerContext = leaves[readerUpto]; endDoc = readerContext.DocBase + readerContext.Reader.MaxDoc; } if (readerContext != null) { // We advanced to another segment: docBase = readerContext.DocBase; scorer = weight.GetScorer(readerContext, null); } int targetDoc = docID - docBase; int actualDoc = scorer.DocID; if (actualDoc < targetDoc) { actualDoc = scorer.Advance(targetDoc); } if (actualDoc == targetDoc) { // Query did match this doc: hit.Score = Combine(hit.Score, true, scorer.GetScore()); } else { // Query did not match this doc: if (Debugging.AssertsEnabled) { Debugging.Assert(actualDoc > targetDoc); } hit.Score = Combine(hit.Score, false, 0.0f); } hitUpto++; } // TODO: we should do a partial sort (of only topN) // instead, but typically the number of hits is // smallish: Array.Sort(hits, Comparer <ScoreDoc> .Create((a, b) => { // Sort by score descending, then docID ascending: if (a.Score > b.Score) { return(-1); } else if (a.Score < b.Score) { return(1); } else { // this subtraction can't overflow int // because docIDs are >= 0: return(a.Doc - b.Doc); } })); if (topN < hits.Length) { ScoreDoc[] subset = new ScoreDoc[topN]; Array.Copy(hits, 0, subset, 0, topN); hits = subset; } return(new TopDocs(firstPassTopDocs.TotalHits, hits, hits[0].Score)); }
public static TopDocs Merge(Sort sort, int start, int size, TopDocs[] shardHits) { Util.PriorityQueue <ShardRef> queue; if (sort == null) { queue = new ScoreMergeSortQueue(shardHits); } else { queue = new MergeSortQueue(sort, shardHits); } int totalHitCount = 0; int availHitCount = 0; float maxScore = float.MinValue; for (int shardIDX = 0; shardIDX < shardHits.Length; shardIDX++) { TopDocs shard = shardHits[shardIDX]; // totalHits can be non-zero even if no hits were // collected, when searchAfter was used: totalHitCount += shard.TotalHits; if (shard.ScoreDocs != null && shard.ScoreDocs.Length > 0) { availHitCount += shard.ScoreDocs.Length; queue.Add(new ShardRef(shardIDX)); maxScore = Math.Max(maxScore, shard.MaxScore); //System.out.println(" maxScore now " + maxScore + " vs " + shard.getMaxScore()); } } if (availHitCount == 0) { maxScore = float.NaN; } ScoreDoc[] hits; if (availHitCount <= start) { hits = new ScoreDoc[0]; } else { hits = new ScoreDoc[Math.Min(size, availHitCount - start)]; int requestedResultWindow = start + size; int numIterOnHits = Math.Min(availHitCount, requestedResultWindow); int hitUpto = 0; while (hitUpto < numIterOnHits) { Debug.Assert(queue.Count > 0); ShardRef @ref = queue.Pop(); ScoreDoc hit = shardHits[@ref.ShardIndex].ScoreDocs[@ref.HitIndex++]; hit.ShardIndex = @ref.ShardIndex; if (hitUpto >= start) { hits[hitUpto - start] = hit; } //System.out.println(" hitUpto=" + hitUpto); //System.out.println(" doc=" + hits[hitUpto].doc + " score=" + hits[hitUpto].score); hitUpto++; if (@ref.HitIndex < shardHits[@ref.ShardIndex].ScoreDocs.Length) { // Not done with this these TopDocs yet: queue.Add(@ref); } } } if (sort == null) { return(new TopDocs(totalHitCount, hits, maxScore)); } else { return(new TopFieldDocs(totalHitCount, hits, sort.GetSort(), maxScore)); } }