/// <summary> /// Returns the grouped results. Returns null if the /// number of groups collected is <= groupOffset. /// /// <para> /// <b>NOTE</b>: This collector is unable to compute /// the groupValue per group so it will always be null. /// This is normally not a problem, as you can obtain the /// value just like you obtain other values for each /// matching document (eg, via stored fields, via /// FieldCache, etc.) /// </para> /// </summary> /// <typeparam name="TGroupValue">The expected return type for group value</typeparam> /// <param name="withinGroupSort"> /// The <see cref="Sort"/> used to sort /// documents within each group. Passing null is /// allowed, to sort by relevance. /// </param> /// <param name="groupOffset">Which group to start from</param> /// <param name="withinGroupOffset"> /// Which document to start from within each group /// </param> /// <param name="maxDocsPerGroup"> /// How many top documents to keep within each group. /// </param> /// <param name="fillSortFields"> /// If true then the Comparable values for the sort fields will be set /// </param> public virtual ITopGroups <TGroupValue> GetTopGroups <TGroupValue>(Sort withinGroupSort, int groupOffset, int withinGroupOffset, int maxDocsPerGroup, bool fillSortFields) { //if (queueFull) { //System.out.println("getTopGroups groupOffset=" + groupOffset + " topNGroups=" + topNGroups); //} if (subDocUpto != 0) { ProcessGroup(); } if (groupOffset >= groupQueue.Count) { return(null); } int totalGroupedHitCount = 0; FakeScorer fakeScorer = new FakeScorer(); float maxScore = float.Epsilon; // LUCENENET: Epsilon in .NET is the same as MIN_VALUE in Java GroupDocs <TGroupValue>[] groups = new GroupDocs <TGroupValue> [groupQueue.Count - groupOffset]; for (int downTo = groupQueue.Count - groupOffset - 1; downTo >= 0; downTo--) { OneGroup og = groupQueue.Pop(); // At this point we hold all docs w/ in each group, // unsorted; we now sort them: ITopDocsCollector collector; if (withinGroupSort == null) { // Sort by score if (!needsScores) { throw new ArgumentException("cannot sort by relevance within group: needsScores=false"); } collector = TopScoreDocCollector.Create(maxDocsPerGroup, true); } else { // Sort by fields collector = TopFieldCollector.Create(withinGroupSort, maxDocsPerGroup, fillSortFields, needsScores, needsScores, true); } collector.SetScorer(fakeScorer); collector.SetNextReader(og.readerContext); for (int docIDX = 0; docIDX < og.count; docIDX++) { int doc = og.docs[docIDX]; fakeScorer.doc = doc; if (needsScores) { fakeScorer.score = og.scores[docIDX]; } collector.Collect(doc); } totalGroupedHitCount += og.count; object[] groupSortValues; if (fillSortFields) { groupSortValues = new IComparable[comparers.Length]; for (int sortFieldIDX = 0; sortFieldIDX < comparers.Length; sortFieldIDX++) { groupSortValues[sortFieldIDX] = comparers[sortFieldIDX][og.comparerSlot]; } } else { groupSortValues = null; } TopDocs topDocs = collector.GetTopDocs(withinGroupOffset, maxDocsPerGroup); // TODO: we could aggregate scores across children // by Sum/Avg instead of passing NaN: groups[downTo] = new GroupDocs <TGroupValue>(float.NaN, topDocs.MaxScore, og.count, topDocs.ScoreDocs,
/// <summary> /// Returns the grouped results. Returns null if the /// number of groups collected is <= groupOffset. /// /// <para> /// <b>NOTE</b>: This collector is unable to compute /// the groupValue per group so it will always be null. /// This is normally not a problem, as you can obtain the /// value just like you obtain other values for each /// matching document (eg, via stored fields, via /// FieldCache, etc.) /// </para> /// </summary> /// <typeparam name="TGroupValue">The expected return type for group value</typeparam> /// <<param name="withinGroupSort"> /// The <see cref="Sort"/> used to sort /// documents within each group. Passing null is /// allowed, to sort by relevance. /// </param> /// <param name="groupOffset">Which group to start from</param> /// <param name="withinGroupOffset"> /// Which document to start from within each group /// </param> /// <param name="maxDocsPerGroup"> /// How many top documents to keep within each group. /// </param> /// <param name="fillSortFields"> /// If true then the Comparable values for the sort fields will be set /// </param> public virtual ITopGroups <TGroupValue> GetTopGroups <TGroupValue>(Sort withinGroupSort, int groupOffset, int withinGroupOffset, int maxDocsPerGroup, bool fillSortFields) { //if (queueFull) { //System.out.println("getTopGroups groupOffset=" + groupOffset + " topNGroups=" + topNGroups); //} if (subDocUpto != 0) { ProcessGroup(); } if (groupOffset >= groupQueue.Size()) { return(null); } int totalGroupedHitCount = 0; FakeScorer fakeScorer = new FakeScorer(); float maxScore = float.MinValue; GroupDocs <TGroupValue>[] groups = new GroupDocs <TGroupValue> [groupQueue.Size() - groupOffset]; for (int downTo = groupQueue.Size() - groupOffset - 1; downTo >= 0; downTo--) { OneGroup og = groupQueue.Pop(); // At this point we hold all docs w/ in each group, // unsorted; we now sort them: ITopDocsCollector collector; if (withinGroupSort == null) { // Sort by score if (!needsScores) { throw new ArgumentException("cannot sort by relevance within group: needsScores=false"); } collector = TopScoreDocCollector.Create(maxDocsPerGroup, true); } else { // Sort by fields collector = TopFieldCollector.Create(withinGroupSort, maxDocsPerGroup, fillSortFields, needsScores, needsScores, true); } collector.Scorer = fakeScorer; collector.NextReader = og.readerContext; for (int docIDX = 0; docIDX < og.count; docIDX++) { int doc = og.docs[docIDX]; fakeScorer.doc = doc; if (needsScores) { fakeScorer.score = og.scores[docIDX]; } collector.Collect(doc); } totalGroupedHitCount += og.count; object[] groupSortValues; if (fillSortFields) { groupSortValues = new IComparable[comparators.Length]; for (int sortFieldIDX = 0; sortFieldIDX < comparators.Length; sortFieldIDX++) { groupSortValues[sortFieldIDX] = comparators[sortFieldIDX].Value(og.comparatorSlot); } } else { groupSortValues = null; } TopDocs topDocs = collector.TopDocs(withinGroupOffset, maxDocsPerGroup); // TODO: we could aggregate scores across children // by Sum/Avg instead of passing NaN: groups[downTo] = new GroupDocs <TGroupValue>(float.NaN, topDocs.MaxScore, og.count, topDocs.ScoreDocs, default(TGroupValue), groupSortValues); maxScore = Math.Max(maxScore, topDocs.MaxScore); } /* * while (groupQueue.size() != 0) { * final OneGroup og = groupQueue.pop(); * //System.out.println(" leftover: og ord=" + og.groupOrd + " count=" + og.count); * totalGroupedHitCount += og.count; * } */ return(new TopGroups <TGroupValue>(new TopGroups <TGroupValue>(groupSort.GetSort(), withinGroupSort == null ? null : withinGroupSort.GetSort(), totalHitCount, totalGroupedHitCount, groups, maxScore), totalGroupCount)); }