private void Compare(TopDocs oldHits, TopDocs newHits) { Assert.AreEqual(oldHits.totalHits, newHits.totalHits); Assert.AreEqual(oldHits.scoreDocs.Length, newHits.scoreDocs.Length); ScoreDoc[] oldDocs = oldHits.scoreDocs; ScoreDoc[] newDocs = newHits.scoreDocs; for (int i = 0; i < oldDocs.Length; i++) { if (oldDocs[i] is FieldDoc) { System.Diagnostics.Debug.Assert(newDocs[i] is FieldDoc); FieldDoc oldHit = (FieldDoc)oldDocs[i]; FieldDoc newHit = (FieldDoc)newDocs[i]; Assert.AreEqual(oldHit.doc, newHit.doc, "hit " + i + " of " + oldDocs.Length + " differs: oldDoc=" + oldHit.doc + " vs newDoc=" + newHit.doc + " oldFields=" + _TestUtil.ArrayToString(oldHit.fields) + " newFields=" + _TestUtil.ArrayToString(newHit.fields)); Assert.AreEqual(oldHit.score, newHit.score, 0.00001); Assert.IsTrue(SupportClass.CollectionsHelper.Equals(oldHit.fields, newHit.fields)); } else { ScoreDoc oldHit = oldDocs[i]; ScoreDoc newHit = newDocs[i]; Assert.AreEqual(oldHit.doc, newHit.doc); Assert.AreEqual(oldHit.score, newHit.score, 0.00001); } } }
public override Explanation Explain(IndexSearcher searcher, Explanation firstPassExplanation, int docID) { TopDocs oneHit = new TopDocs(1, new ScoreDoc[] { new ScoreDoc(docID, firstPassExplanation.Value) }); TopDocs hits = Rescore(searcher, oneHit, 1); Debug.Assert(hits.TotalHits == 1); // TODO: if we could ask the Sort to explain itself then // we wouldn't need the separate ExpressionRescorer... Explanation result = new Explanation(0.0f, "sort field values for sort=" + sort.ToString()); // Add first pass: Explanation first = new Explanation(firstPassExplanation.Value, "first pass score"); first.AddDetail(firstPassExplanation); result.AddDetail(first); FieldDoc fieldDoc = (FieldDoc)hits.ScoreDocs[0]; // Add sort values: SortField[] sortFields = sort.GetSort(); for (int i = 0; i < sortFields.Length; i++) { result.AddDetail(new Explanation(0.0f, "sort field " + sortFields[i].ToString() + " value=" + fieldDoc.Fields[i])); } return(result); }
override public void Run() { try { docs = (sort == null)?searchable.Search(weight, filter, nDocs):searchable.Search(weight, filter, nDocs, sort); } // Store the IOException for later use by the caller of this thread catch (System.Exception e) { this.ioe = e; } if (this.ioe == null) { // if we are sorting by fields, we need to tell the field sorted hit queue // the actual type of fields, in case the original list contained AUTO. // if the searchable returns null for fields, we'll have problems. if (sort != null) { TopFieldDocs docsFields = (TopFieldDocs)docs; // If one of the Sort fields is FIELD_DOC, need to fix its values, so that // it will break ties by doc Id properly. Otherwise, it will compare to // 'relative' doc Ids, that belong to two different searchables. for (int j = 0; j < docsFields.fields.Length; j++) { if (docsFields.fields[j].GetType() == SortField.DOC) { // iterate over the score docs and change their fields value for (int j2 = 0; j2 < docs.ScoreDocs.Length; j2++) { FieldDoc fd = (FieldDoc)docs.ScoreDocs[j2]; //DIGY?? No unit test for the line below fd.fields[j] = (System.Int32)(((System.Int32)fd.fields[j]) + starts[i]); } break; } } ((FieldDocSortedHitQueue)hq).SetFields(docsFields.fields); } ScoreDoc[] scoreDocs = docs.ScoreDocs; for (int j = 0; j < scoreDocs.Length; j++) { // merge scoreDocs into hq ScoreDoc scoreDoc = scoreDocs[j]; scoreDoc.Doc += starts[i]; // convert doc //it would be so nice if we had a thread-safe insert lock (hq) { if (!hq.Insert(scoreDoc)) { break; } } // no more scores > minScore } } }
public override TopFieldDocs Search(Weight weight, Filter filter, int n, Sort sort) { FieldDocSortedHitQueue hq = null; int totalHits = 0; float maxScore = System.Single.NegativeInfinity; for (int i = 0; i < searchables.Length; i++) { // search each searcher TopFieldDocs docs = searchables[i].Search(weight, filter, n, sort); // If one of the Sort fields is FIELD_DOC, need to fix its values, so that // it will break ties by doc Id properly. Otherwise, it will compare to // 'relative' doc Ids, that belong to two different searchers. for (int j = 0; j < docs.fields.Length; j++) { if (docs.fields[j].GetType() == SortField.DOC) { // iterate over the score docs and change their fields value for (int j2 = 0; j2 < docs.scoreDocs.Length; j2++) { FieldDoc fd = (FieldDoc)docs.scoreDocs[j2]; fd.fields[j] = (System.Int32)(((System.Int32)fd.fields[j]) + starts[i]); } break; } } if (hq == null) { hq = new FieldDocSortedHitQueue(docs.fields, n); } totalHits += docs.totalHits; // update totalHits maxScore = System.Math.Max(maxScore, docs.GetMaxScore()); ScoreDoc[] scoreDocs = docs.scoreDocs; for (int j = 0; j < scoreDocs.Length; j++) { // merge scoreDocs into hq ScoreDoc scoreDoc = scoreDocs[j]; scoreDoc.doc += starts[i]; // convert doc if (!hq.Insert(scoreDoc)) { break; // no more scores > minScore } } } ScoreDoc[] scoreDocs2 = new ScoreDoc[hq.Size()]; for (int i = hq.Size() - 1; i >= 0; i--) { // put docs in array scoreDocs2[i] = (ScoreDoc)hq.Pop(); } return(new TopFieldDocs(totalHits, scoreDocs2, hq.GetFields(), maxScore)); }
/// <summary> Given a FieldDoc object, stores the values used /// to sort the given document. These values are not the raw /// values out of the index, but the internal representation /// of them. This is so the given search hit can be collated /// by a MultiSearcher with other search hits. /// </summary> /// <param name="doc"> The FieldDoc to store sort values into. /// </param> /// <returns> The same FieldDoc passed in. /// </returns> /// <seealso cref="Searchable.Search(Weight,Filter,int,Sort)"> /// </seealso> internal virtual FieldDoc FillFields(FieldDoc doc) { int n = comparators.Length; System.IComparable[] fields = new System.IComparable[n]; for (int i = 0; i < n; ++i) { fields[i] = comparators[i].SortValue(doc); } doc.fields = fields; //if (maxscore > 1.0f) doc.score /= maxscore; // normalize scores return(doc); }
public SearcherCallableWithSort(ReentrantLock @lock, IndexSearcher searcher, LeafSlice slice, Weight weight, FieldDoc after, int nDocs, TopFieldCollector hq, Sort sort, bool doDocScores, bool doMaxScore) { this.@lock = @lock; this.Searcher = searcher; this.Weight = weight; this.NDocs = nDocs; this.Hq = hq; this.Sort = sort; this.Slice = slice; this.After = after; this.DoDocScores = doDocScores; this.DoMaxScore = doMaxScore; }
/// <summary> /// Just like <seealso cref="#search(Weight, int, Sort, boolean, boolean)"/>, but you choose /// whether or not the fields in the returned <seealso cref="FieldDoc"/> instances should /// be set by specifying fillFields. /// </summary> protected internal virtual TopFieldDocs Search(Weight weight, FieldDoc after, int nDocs, Sort sort, bool fillFields, bool doDocScores, bool doMaxScore) { if (sort == null) { throw new System.NullReferenceException("Sort must not be null"); } int limit = Reader.MaxDoc; if (limit == 0) { limit = 1; } nDocs = Math.Min(nDocs, limit); if (Executor == null) { // use all leaves here! return(Search(LeafContexts, weight, after, nDocs, sort, fillFields, doDocScores, doMaxScore)); } else { TopFieldCollector topCollector = TopFieldCollector.Create(sort, nDocs, after, fillFields, doDocScores, doMaxScore, false); ReentrantLock @lock = new ReentrantLock(); ExecutionHelper <TopFieldDocs> runner = new ExecutionHelper <TopFieldDocs>(Executor); for (int i = 0; i < LeafSlices.Length; i++) // search each leaf slice { runner.Submit(new SearcherCallableWithSort(@lock, this, LeafSlices[i], weight, after, nDocs, topCollector, sort, doDocScores, doMaxScore)); } int totalHits = 0; float maxScore = float.NegativeInfinity; foreach (TopFieldDocs topFieldDocs in runner) { if (topFieldDocs.TotalHits != 0) { totalHits += topFieldDocs.TotalHits; maxScore = Math.Max(maxScore, topFieldDocs.MaxScore); } } TopFieldDocs topDocs = (TopFieldDocs)topCollector.TopDocs(); return(new TopFieldDocs(totalHits, topDocs.ScoreDocs, topDocs.Fields, topDocs.MaxScore)); } }
// Returns true if first is < second protected internal override bool LessThan(ShardRef first, ShardRef second) { Debug.Assert(first != second); FieldDoc firstFD = (FieldDoc)shardHits[first.ShardIndex][first.HitIndex]; FieldDoc secondFD = (FieldDoc)shardHits[second.ShardIndex][second.HitIndex]; //System.out.println(" lessThan:\n first=" + first + " doc=" + firstFD.doc + " score=" + firstFD.score + "\n second=" + second + " doc=" + secondFD.doc + " score=" + secondFD.score); for (int compIDX = 0; compIDX < comparers.Length; compIDX++) { FieldComparer comp = comparers[compIDX]; //System.out.println(" cmp idx=" + compIDX + " cmp1=" + firstFD.fields[compIDX] + " cmp2=" + secondFD.fields[compIDX] + " reverse=" + reverseMul[compIDX]); int cmp = reverseMul[compIDX] * comp.CompareValues(firstFD.Fields[compIDX], secondFD.Fields[compIDX]); if (cmp != 0) { //System.out.println(" return " + (cmp < 0)); return(cmp < 0); } } // Tie break: earlier shard wins if (first.ShardIndex < second.ShardIndex) { //System.out.println(" return tb true"); return(true); } else if (first.ShardIndex > second.ShardIndex) { //System.out.println(" return tb false"); return(false); } else { // Tie break in same shard: resolve however the // shard had resolved it: //System.out.println(" return tb " + (first.hitIndex < second.hitIndex)); Debug.Assert(first.HitIndex != second.HitIndex); return(first.HitIndex < second.HitIndex); } }
/* * Only the following callback methods need to be overridden since * topDocs(int, int) calls them to return the results. */ protected internal override void PopulateResults(ScoreDoc[] results, int howMany) { if (fillFields) { // avoid casting if unnecessary. FieldValueHitQueue queue = (FieldValueHitQueue)pq; for (int i = howMany - 1; i >= 0; i--) { results[i] = queue.FillFields((Entry)queue.Pop()); } } else { for (int i = howMany - 1; i >= 0; i--) { Entry entry = (Entry)pq.Pop(); results[i] = new FieldDoc(entry.docID, entry.score); } } }
// javadoc inherited public override void Collect(int doc, float score) { if (score > 0.0f) { totalHits++; if (reusableFD == null) reusableFD = new FieldDoc(doc, score); else { // Whereas TopScoreDocCollector can skip this if the // score is not competitive, we cannot because the // comparators in the FieldSortedHitQueue.lessThan // aren't in general congruent with "higher score // wins" reusableFD.score = score; reusableFD.doc = doc; } reusableFD = (FieldDoc) hq.InsertWithOverflow(reusableFD); } }
// javadoc inherited public override void Collect(int doc, float score) { if (score > 0.0f) { totalHits++; if (reusableFD == null) { reusableFD = new FieldDoc(doc, score); } else { // Whereas TopDocCollector can skip this if the // score is not competitive, we cannot because the // comparators in the FieldSortedHitQueue.lessThan // aren't in general congruent with "higher score // wins" reusableFD.score = score; reusableFD.doc = doc; } reusableFD = (FieldDoc)hq.InsertWithOverflow(reusableFD); } }
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; } }
// The signature of this method takes a FieldDoc in order to avoid // the unneeded cast to retrieve the score. // inherit javadoc public virtual bool Insert(FieldDoc fdoc) { maxscore = System.Math.Max(maxscore, fdoc.score); return(base.Insert(fdoc)); }
// Update maxscore. private void UpdateMaxScore(FieldDoc fdoc) { maxscore = System.Math.Max(maxscore, fdoc.score); }
/// <summary> Given a FieldDoc object, stores the values used /// to sort the given document. These values are not the raw /// values out of the index, but the internal representation /// of them. This is so the given search hit can be collated /// by a MultiSearcher with other search hits. /// </summary> /// <param name="doc"> The FieldDoc to store sort values into. /// </param> /// <returns> The same FieldDoc passed in. /// </returns> /// <seealso cref="Searchable.Search(Weight,Filter,int,Sort)"> /// </seealso> internal virtual FieldDoc FillFields(FieldDoc doc) { int n = comparators.Length; System.IComparable[] fields = new System.IComparable[n]; for (int i = 0; i < n; ++i) fields[i] = comparators[i].SortValue(doc); doc.fields = fields; //if (maxscore > 1.0f) doc.score /= maxscore; // normalize scores return doc; }
// The signature of this method takes a FieldDoc in order to avoid // the unneeded cast to retrieve the score. // inherit javadoc public virtual bool Insert(FieldDoc fdoc) { maxscore = System.Math.Max(maxscore, fdoc.score); return base.Insert(fdoc); }
// The signature of this method takes a FieldDoc in order to avoid // the unneeded cast to retrieve the score. // inherit javadoc public virtual bool Insert(FieldDoc fdoc) { UpdateMaxScore(fdoc); return(base.Insert(fdoc)); }
/* * Only the following callback methods need to be overridden since * topDocs(int, int) calls them to return the results. */ protected internal override void PopulateResults(ScoreDoc[] results, int howMany) { if (fillFields) { // avoid casting if unnecessary. FieldValueHitQueue queue = (FieldValueHitQueue) pq; for (int i = howMany - 1; i >= 0; i--) { results[i] = queue.FillFields((Entry) queue.Pop()); } } else { for (int i = howMany - 1; i >= 0; i--) { Entry entry = (Entry) pq.Pop(); results[i] = new FieldDoc(entry.docID, entry.score); } } }
/// <summary> Returns whether <code>a</code> is less relevant than <code>b</code>.</summary> /// <param name="a">ScoreDoc /// </param> /// <param name="b">ScoreDoc /// </param> /// <returns> <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>. /// </returns> public override bool LessThan(System.Object a, System.Object b) { FieldDoc docA = (FieldDoc)a; FieldDoc docB = (FieldDoc)b; int n = fields.Length; int c = 0; for (int i = 0; i < n && c == 0; ++i) { int type = fields[i].GetSortType(); switch (type) { case SortField.SCORE: float r1 = (float)((System.Single)docA.fields[i]); float r2 = (float)((System.Single)docB.fields[i]); if (r1 > r2) { c = -1; } if (r1 < r2) { c = 1; } break; case SortField.DOC: case SortField.INT: int i1 = ((System.Int32)docA.fields[i]); int i2 = ((System.Int32)docB.fields[i]); if (i1 < i2) { c = -1; } if (i1 > i2) { c = 1; } break; case SortField.STRING: System.String s1 = (System.String)docA.fields[i]; System.String s2 = (System.String)docB.fields[i]; // null values need to be sorted first, because of how FieldCache.getStringIndex() // works - in that routine, any documents without a value in the given field are // put first. If both are null, the next SortField is used if (s1 == null) { c = (s2 == null)?0:-1; } else if (s2 == null) { c = 1; } // else if (fields[i].GetLocale() == null) { c = String.CompareOrdinal(s1, s2); } else { //UPGRADE_TODO: The equivalent in .NET for method 'java.text.Collator.compare' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" c = collators[i].Compare(s1.ToString(), s2.ToString()); } break; case SortField.FLOAT: //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" float f1 = (float)((System.Single)docA.fields[i]); //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" float f2 = (float)((System.Single)docB.fields[i]); if (f1 < f2) { c = -1; } if (f1 > f2) { c = 1; } break; case SortField.CUSTOM: c = docA.fields[i].CompareTo(docB.fields[i]); break; case SortField.AUTO: // we cannot handle this - even if we determine the type of object (Float or // Integer), we don't necessarily know how to compare them (both SCORE and // FLOAT contain floats, but are sorted opposite of each other). Before // we get here, each AUTO should have been replaced with its actual value. throw new System.SystemException("FieldDocSortedHitQueue cannot use an AUTO SortField"); default: throw new System.SystemException("invalid SortField type: " + type); } if (fields[i].GetReverse()) { c = -c; } } // avoid random sort order that could lead to duplicates (bug #31241): if (c == 0) { return(docA.doc > docB.doc); } return(c > 0); }
/// <summary> /// Search, sorting by <seealso cref="Sort"/>, and computing /// drill down and sideways counts. /// </summary> public virtual DrillSidewaysResult Search(DrillDownQuery query, Filter filter, FieldDoc after, int topN, Sort sort, bool doDocScores, bool doMaxScore) { if (filter != null) { query = new DrillDownQuery(config, filter, query); } if (sort != null) { int limit = searcher.IndexReader.MaxDoc; if (limit == 0) { limit = 1; // the collector does not alow numHits = 0 } topN = Math.Min(topN, limit); TopFieldCollector hitCollector = TopFieldCollector.Create(sort, topN, after, true, doDocScores, doMaxScore, true); DrillSidewaysResult r = Search(query, hitCollector); return new DrillSidewaysResult(r.Facets, hitCollector.TopDocs()); } else { return Search(after, query, topN); } }
public virtual void TestRandomStringSort() { Random random = new Random(Random().Next()); int NUM_DOCS = AtLeast(100); Directory dir = NewDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random, dir, Similarity, TimeZone); bool allowDups = random.NextBoolean(); HashSet <string> seen = new HashSet <string>(); int maxLength = TestUtil.NextInt(random, 5, 100); if (VERBOSE) { Console.WriteLine("TEST: NUM_DOCS=" + NUM_DOCS + " maxLength=" + maxLength + " allowDups=" + allowDups); } int numDocs = 0; IList <BytesRef> docValues = new List <BytesRef>(); // TODO: deletions while (numDocs < NUM_DOCS) { Document doc = new Document(); // 10% of the time, the document is missing the value: BytesRef br; if (Random().Next(10) != 7) { string s; if (random.NextBoolean()) { s = TestUtil.RandomSimpleString(random, maxLength); } else { s = TestUtil.RandomUnicodeString(random, maxLength); } if (!allowDups) { if (seen.Contains(s)) { continue; } seen.Add(s); } if (VERBOSE) { Console.WriteLine(" " + numDocs + ": s=" + s); } br = new BytesRef(s); if (DefaultCodecSupportsDocValues()) { doc.Add(new SortedDocValuesField("stringdv", br)); doc.Add(new NumericDocValuesField("id", numDocs)); } else { doc.Add(NewStringField("id", Convert.ToString(numDocs), Field.Store.NO)); } doc.Add(NewStringField("string", s, Field.Store.NO)); docValues.Add(br); } else { br = null; if (VERBOSE) { Console.WriteLine(" " + numDocs + ": <missing>"); } docValues.Add(null); if (DefaultCodecSupportsDocValues()) { doc.Add(new NumericDocValuesField("id", numDocs)); } else { doc.Add(NewStringField("id", Convert.ToString(numDocs), Field.Store.NO)); } } doc.Add(new StoredField("id", numDocs)); writer.AddDocument(doc); numDocs++; if (random.Next(40) == 17) { // force flush writer.Reader.Dispose(); } } IndexReader r = writer.Reader; writer.Dispose(); if (VERBOSE) { Console.WriteLine(" reader=" + r); } IndexSearcher idxS = NewSearcher(r, false, Similarity); int ITERS = AtLeast(100); for (int iter = 0; iter < ITERS; iter++) { bool reverse = random.NextBoolean(); TopFieldDocs hits; SortField sf; bool sortMissingLast; bool missingIsNull; if (DefaultCodecSupportsDocValues() && random.NextBoolean()) { sf = new SortField("stringdv", SortField.Type_e.STRING, reverse); // Can only use sort missing if the DVFormat // supports docsWithField: sortMissingLast = DefaultCodecSupportsDocsWithField() && Random().NextBoolean(); missingIsNull = DefaultCodecSupportsDocsWithField(); } else { sf = new SortField("string", SortField.Type_e.STRING, reverse); sortMissingLast = Random().NextBoolean(); missingIsNull = true; } if (sortMissingLast) { sf.MissingValue = SortField.STRING_LAST; } Sort sort; if (random.NextBoolean()) { sort = new Sort(sf); } else { sort = new Sort(sf, SortField.FIELD_DOC); } int hitCount = TestUtil.NextInt(random, 1, r.MaxDoc + 20); RandomFilter f = new RandomFilter(random, (float)random.NextDouble(), docValues); int queryType = random.Next(3); if (queryType == 0) { // force out of order BooleanQuery bq = new BooleanQuery(); // Add a Query with SHOULD, since bw.Scorer() returns BooleanScorer2 // which delegates to BS if there are no mandatory clauses. bq.Add(new MatchAllDocsQuery(), Occur.SHOULD); // Set minNrShouldMatch to 1 so that BQ will not optimize rewrite to return // the clause instead of BQ. bq.MinimumNumberShouldMatch = 1; hits = idxS.Search(bq, f, hitCount, sort, random.NextBoolean(), random.NextBoolean()); } else if (queryType == 1) { hits = idxS.Search(new ConstantScoreQuery(f), null, hitCount, sort, random.NextBoolean(), random.NextBoolean()); } else { hits = idxS.Search(new MatchAllDocsQuery(), f, hitCount, sort, random.NextBoolean(), random.NextBoolean()); } if (VERBOSE) { Console.WriteLine("\nTEST: iter=" + iter + " " + hits.TotalHits + " hits; topN=" + hitCount + "; reverse=" + reverse + "; sortMissingLast=" + sortMissingLast + " sort=" + sort); } // Compute expected results: var expected = f.MatchValues.ToList(); expected.Sort(new ComparatorAnonymousInnerClassHelper(this, sortMissingLast)); if (reverse) { expected.Reverse(); } if (VERBOSE) { Console.WriteLine(" expected:"); for (int idx = 0; idx < expected.Count; idx++) { BytesRef br = expected[idx]; if (br == null && missingIsNull == false) { br = new BytesRef(); } Console.WriteLine(" " + idx + ": " + (br == null ? "<missing>" : br.Utf8ToString())); if (idx == hitCount - 1) { break; } } } if (VERBOSE) { Console.WriteLine(" actual:"); for (int hitIDX = 0; hitIDX < hits.ScoreDocs.Length; hitIDX++) { FieldDoc fd = (FieldDoc)hits.ScoreDocs[hitIDX]; BytesRef br = (BytesRef)fd.Fields[0]; Console.WriteLine(" " + hitIDX + ": " + (br == null ? "<missing>" : br.Utf8ToString()) + " id=" + idxS.Doc(fd.Doc).Get("id")); } } for (int hitIDX = 0; hitIDX < hits.ScoreDocs.Length; hitIDX++) { FieldDoc fd = (FieldDoc)hits.ScoreDocs[hitIDX]; BytesRef br = expected[hitIDX]; if (br == null && missingIsNull == false) { br = new BytesRef(); } // Normally, the old codecs (that don't support // docsWithField via doc values) will always return // an empty BytesRef for the missing case; however, // if all docs in a given segment were missing, in // that case it will return null! So we must map // null here, too: BytesRef br2 = (BytesRef)fd.Fields[0]; if (br2 == null && missingIsNull == false) { br2 = new BytesRef(); } Assert.AreEqual(br, br2, "hit=" + hitIDX + " has wrong sort value"); } } r.Dispose(); dir.Dispose(); }
// Update maxscore. private void UpdateMaxScore(FieldDoc fdoc) { maxscore = System.Math.Max(maxscore, fdoc.score); }
/// <summary> Returns whether <code>a</code> is less relevant than <code>b</code>.</summary> /// <param name="a">ScoreDoc /// </param> /// <param name="b">ScoreDoc /// </param> /// <returns> <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>. /// </returns> public override bool LessThan(System.Object a, System.Object b) { FieldDoc docA = (FieldDoc)a; FieldDoc docB = (FieldDoc)b; int n = fields.Length; int c = 0; for (int i = 0; i < n && c == 0; ++i) { int type = fields[i].GetType(); switch (type) { case SortField.SCORE: { float r1 = (float)((System.Single)docA.fields[i]); float r2 = (float)((System.Single)docB.fields[i]); if (r1 > r2) { c = -1; } if (r1 < r2) { c = 1; } break; } case SortField.DOC: case SortField.INT: { int i1 = ((System.Int32)docA.fields[i]); int i2 = ((System.Int32)docB.fields[i]); if (i1 < i2) { c = -1; } if (i1 > i2) { c = 1; } break; } case SortField.LONG: { long l1 = (long)((System.Int64)docA.fields[i]); long l2 = (long)((System.Int64)docB.fields[i]); if (l1 < l2) { c = -1; } if (l1 > l2) { c = 1; } break; } case SortField.STRING: { System.String s1 = (System.String)docA.fields[i]; System.String s2 = (System.String)docB.fields[i]; // null values need to be sorted first, because of how FieldCache.getStringIndex() // works - in that routine, any documents without a value in the given field are // put first. If both are null, the next SortField is used if (s1 == null) { c = (s2 == null)?0:-1; } else if (s2 == null) { c = 1; } // else if (fields[i].GetLocale() == null) { c = String.CompareOrdinal(s1, s2); } else { c = collators[i].Compare(s1.ToString(), s2.ToString()); } break; } case SortField.FLOAT: { float f1 = (float)((System.Single)docA.fields[i]); float f2 = (float)((System.Single)docB.fields[i]); if (f1 < f2) { c = -1; } if (f1 > f2) { c = 1; } break; } case SortField.DOUBLE: { double d1 = ((System.Double)docA.fields[i]); double d2 = ((System.Double)docB.fields[i]); if (d1 < d2) { c = -1; } if (d1 > d2) { c = 1; } break; } case SortField.BYTE: { int i1 = (sbyte)((System.SByte)docA.fields[i]); int i2 = (sbyte)((System.SByte)docB.fields[i]); if (i1 < i2) { c = -1; } if (i1 > i2) { c = 1; } break; } case SortField.SHORT: { int i1 = (short)((System.Int16)docA.fields[i]); int i2 = (short)((System.Int16)docB.fields[i]); if (i1 < i2) { c = -1; } if (i1 > i2) { c = 1; } break; } case SortField.CUSTOM: { c = docA.fields[i].CompareTo(docB.fields[i]); break; } case SortField.AUTO: { // we cannot handle this - even if we determine the type of object (Float or // Integer), we don't necessarily know how to compare them (both SCORE and // FLOAT contain floats, but are sorted opposite of each other). Before // we get here, each AUTO should have been replaced with its actual value. throw new System.SystemException("FieldDocSortedHitQueue cannot use an AUTO SortField"); } default: { throw new System.SystemException("invalid SortField type: " + type); } } if (fields[i].GetReverse()) { c = -c; } } // avoid random sort order that could lead to duplicates (bug #31241): if (c == 0) { return(docA.doc > docB.doc); } return(c > 0); }
/// <summary> /// Just like <seealso cref="#search(Weight, int, Sort, boolean, boolean)"/>, but you choose /// whether or not the fields in the returned <seealso cref="FieldDoc"/> instances should /// be set by specifying fillFields. /// </summary> protected internal virtual TopFieldDocs Search(IList <AtomicReaderContext> leaves, Weight weight, FieldDoc after, int nDocs, Sort sort, bool fillFields, bool doDocScores, bool doMaxScore) { // single thread int limit = Reader.MaxDoc; if (limit == 0) { limit = 1; } nDocs = Math.Min(nDocs, limit); TopFieldCollector collector = TopFieldCollector.Create(sort, nDocs, after, fillFields, doDocScores, doMaxScore, !weight.ScoresDocsOutOfOrder()); Search(leaves, weight, collector); return((TopFieldDocs)collector.TopDocs()); }
// The signature of this method takes a FieldDoc in order to avoid // the unneeded cast to retrieve the score. // inherit javadoc public virtual bool Insert(FieldDoc fdoc) { UpdateMaxScore(fdoc); return base.Insert(fdoc); }