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)); }
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]; 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 } } }
/// <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); }
/* * 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 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); } }
/// <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) { UpdateMaxScore(fdoc); return base.Insert(fdoc); }
// Update maxscore. private void UpdateMaxScore(FieldDoc fdoc) { maxscore = System.Math.Max(maxscore, fdoc.score); }
/* * 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); } } }
// 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)); }
// 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); }