lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sha...@apache.org
Subject [17/50] [abbrv] lucene-solr:jira/solr-11990: LUCENE-8412: TopFieldCollector no longer takes a trackDocScores option.
Date Sat, 28 Jul 2018 04:49:40 GMT
LUCENE-8412: TopFieldCollector no longer takes a trackDocScores option.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/55bfadbc
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/55bfadbc
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/55bfadbc

Branch: refs/heads/jira/solr-11990
Commit: 55bfadbce115a825a75686fe0bfe71406bc3ee44
Parents: 34686c0
Author: Adrien Grand <jpountz@gmail.com>
Authored: Mon Jul 23 09:05:02 2018 +0200
Committer: Adrien Grand <jpountz@gmail.com>
Committed: Mon Jul 23 09:06:49 2018 +0200

----------------------------------------------------------------------
 lucene/CHANGES.txt                              |   6 +-
 lucene/MIGRATE.txt                              |   7 +
 .../lucene/benchmark/byTask/tasks/ReadTask.java |   7 -
 .../byTask/tasks/SearchWithSortTask.java        |   9 -
 .../org/apache/lucene/search/IndexSearcher.java |   8 +-
 .../org/apache/lucene/search/SortRescorer.java  |  21 ++-
 .../apache/lucene/search/TopFieldCollector.java | 118 ++++++------
 .../apache/lucene/index/TestIndexSorting.java   |   4 +-
 .../org/apache/lucene/search/TestBoolean2.java  |   8 +-
 .../lucene/search/TestElevationComparator.java  |   2 +-
 .../apache/lucene/search/TestSortRandom.java    |   2 +-
 .../apache/lucene/search/TestTopDocsMerge.java  |   4 +-
 .../lucene/search/TestTopFieldCollector.java    | 179 +++++++++++--------
 .../TestTopFieldCollectorEarlyTermination.java  |   5 +-
 .../org/apache/lucene/facet/DrillSideways.java  |  16 +-
 .../apache/lucene/facet/FacetsCollector.java    |   4 +-
 .../search/grouping/BlockGroupingCollector.java |   2 +-
 .../lucene/search/grouping/GroupingSearch.java  |  17 +-
 .../search/grouping/TopGroupsCollector.java     |  11 +-
 .../lucene/search/grouping/TestGrouping.java    |  55 +++---
 .../analyzing/AnalyzingInfixSuggester.java      |   2 +-
 .../solr/handler/component/ExpandComponent.java |   4 +-
 .../solr/handler/component/QueryComponent.java  |   1 +
 .../java/org/apache/solr/search/Grouping.java   |  24 ++-
 .../org/apache/solr/search/ReRankCollector.java |  15 +-
 .../apache/solr/search/SolrIndexSearcher.java   |   9 +-
 .../apache/solr/search/grouping/Command.java    |   7 +
 .../solr/search/grouping/CommandHandler.java    |   4 +
 .../distributed/command/QueryCommand.java       |  14 +-
 .../command/TopGroupsFieldCommand.java          |  42 +++--
 .../test/org/apache/solr/search/TestSort.java   |   3 +-
 .../uninverting/TestFieldCacheSortRandom.java   |   4 +-
 32 files changed, 348 insertions(+), 266 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 3f74283..730e24c 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -60,9 +60,13 @@ API Changes
   no longer have an option to compute the maximum score when sorting by field.
   (Adrien Grand)
 
-* LUCENE-8411: TopFieldCollector no longer takes a fillFields options, it now
+* LUCENE-8411: TopFieldCollector no longer takes a fillFields option, it now
   always fills fields. (Adrien Grand)
 
+* LUCENE-8412: TopFieldCollector no longer takes a trackDocScores option. Scores
+  need to be set on top hits via TopFieldCollector#populateScores instead.
+  (Adrien Grand)
+
 Changes in Runtime Behavior
 
 * LUCENE-8333: Switch MoreLikeThis.setMaxDocFreqPct to use maxDoc instead of

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/MIGRATE.txt
----------------------------------------------------------------------
diff --git a/lucene/MIGRATE.txt b/lucene/MIGRATE.txt
index fb37a1c..4c14651 100644
--- a/lucene/MIGRATE.txt
+++ b/lucene/MIGRATE.txt
@@ -82,3 +82,10 @@ all matches.
 Because filling sort values doesn't have a significant overhead, the fillFields
 option has been removed from TopFieldCollector factory methods. Everything
 behaves as if it was set to true.
+
+## TopFieldCollector no longer takes a trackDocScores option ##
+
+Computing scores at collection time is less efficient than running a second
+request in order to only compute scores for documents that made it to the top
+hits. As a consequence, the trackDocScores option has been removed and can be
+replaced with the new TopFieldCollector#populateScores helper method.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java
----------------------------------------------------------------------
diff --git a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java
index ee06683..b05a429 100644
--- a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java
+++ b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java
@@ -112,7 +112,6 @@ public abstract class ReadTask extends PerfTask {
             // Weight public again, we can go back to
             // pulling the Weight ourselves:
             TopFieldCollector collector = TopFieldCollector.create(sort, numHits,
-                                                                   withScore(),
                                                                    withTotalHits());
             searcher.search(q, collector);
             hits = collector.topDocs();
@@ -208,12 +207,6 @@ public abstract class ReadTask extends PerfTask {
    */
   public abstract boolean withTraverse();
 
-  /** Whether scores should be computed (only useful with
-   *  field sort) */
-  public boolean withScore() {
-    return true;
-  }
-
   /** Whether totalHits should be computed (only useful with
    *  field sort) */
   public boolean withTotalHits() {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java
----------------------------------------------------------------------
diff --git a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java
index 6a17714..d27cfed 100644
--- a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java
+++ b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java
@@ -29,7 +29,6 @@ import org.apache.lucene.search.SortField;
  */
 public class SearchWithSortTask extends ReadTask {
 
-  private boolean doScore = true;
   private Sort sort;
 
   public SearchWithSortTask(PerfRunData runData) {
@@ -60,9 +59,6 @@ public class SearchWithSortTask extends ReadTask {
         sortField0 = SortField.FIELD_DOC;
       } else if (field.equals("score")) {
         sortField0 = SortField.FIELD_SCORE;
-      } else if (field.equals("noscore")) {
-        doScore = false;
-        continue;
       } else {
         int index = field.lastIndexOf(":");
         String fieldName;
@@ -115,11 +111,6 @@ public class SearchWithSortTask extends ReadTask {
   public boolean withWarm() {
     return false;
   }
-
-  @Override
-  public boolean withScore() {
-    return doScore;
-  }
   
   @Override
   public Sort getSort() {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
index d52e2f3..7d18d4f 100644
--- a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
+++ b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
@@ -513,7 +513,7 @@ public class IndexSearcher {
       @Override
       public TopFieldCollector newCollector() throws IOException {
         // TODO: don't pay the price for accurate hit counts by default
-        return TopFieldCollector.create(rewrittenSort, cappedNumHits, after, doDocScores, true);
+        return TopFieldCollector.create(rewrittenSort, cappedNumHits, after, true);
       }
 
       @Override
@@ -528,7 +528,11 @@ public class IndexSearcher {
 
     };
 
-    return search(query, manager);
+    TopFieldDocs topDocs = search(query, manager);
+    if (doDocScores) {
+      TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
+    }
+    return topDocs;
   }
 
  /**

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/java/org/apache/lucene/search/SortRescorer.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/SortRescorer.java b/lucene/core/src/java/org/apache/lucene/search/SortRescorer.java
index 93dd126..95f2982 100644
--- a/lucene/core/src/java/org/apache/lucene/search/SortRescorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/SortRescorer.java
@@ -44,17 +44,12 @@ public class SortRescorer extends Rescorer {
 
     // Copy ScoreDoc[] and sort by ascending docID:
     ScoreDoc[] hits = firstPassTopDocs.scoreDocs.clone();
-    Arrays.sort(hits,
-                new Comparator<ScoreDoc>() {
-                  @Override
-                  public int compare(ScoreDoc a, ScoreDoc b) {
-                    return a.doc - b.doc;
-                  }
-                });
+    Comparator<ScoreDoc> docIdComparator = Comparator.comparingInt(sd -> sd.doc);
+    Arrays.sort(hits, docIdComparator);
 
     List<LeafReaderContext> leaves = searcher.getIndexReader().leaves();
 
-    TopFieldCollector collector = TopFieldCollector.create(sort, topN, true, true);
+    TopFieldCollector collector = TopFieldCollector.create(sort, topN, true);
 
     // Now merge sort docIDs from hits, with reader's leaves:
     int hitUpto = 0;
@@ -90,7 +85,15 @@ public class SortRescorer extends Rescorer {
       hitUpto++;
     }
 
-    return collector.topDocs();
+    TopDocs rescoredDocs = collector.topDocs();
+    // set scores from the original score docs
+    assert hits.length == rescoredDocs.scoreDocs.length;
+    ScoreDoc[] rescoredDocsClone = rescoredDocs.scoreDocs.clone();
+    Arrays.sort(rescoredDocsClone, docIdComparator);
+    for (int i = 0; i < rescoredDocsClone.length; ++i) {
+      rescoredDocsClone[i].score = hits[i].score;
+    }
+    return rescoredDocs;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
index 7defdf9..f8a8ff7 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
@@ -19,16 +19,20 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
 
 import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.ReaderUtil;
 import org.apache.lucene.search.FieldValueHitQueue.Entry;
+import org.apache.lucene.util.FutureObjects;
 import org.apache.lucene.util.PriorityQueue;
 
 /**
  * A {@link Collector} that sorts by {@link SortField} using
  * {@link FieldComparator}s.
  * <p>
- * See the {@link #create(org.apache.lucene.search.Sort, int, boolean, boolean)} method
+ * See the {@link #create(org.apache.lucene.search.Sort, int, boolean)} method
  * for instantiating a TopFieldCollector.
  *
  * @lucene.experimental
@@ -44,10 +48,9 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
 
     final LeafFieldComparator comparator;
     final int reverseMul;
-    final boolean mayNeedScoresTwice;
     Scorer scorer;
 
-    MultiComparatorLeafCollector(LeafFieldComparator[] comparators, int[] reverseMul, boolean mayNeedScoresTwice) {
+    MultiComparatorLeafCollector(LeafFieldComparator[] comparators, int[] reverseMul) {
       if (comparators.length == 1) {
         this.reverseMul = reverseMul[0];
         this.comparator = comparators[0];
@@ -55,14 +58,10 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
         this.reverseMul = 1;
         this.comparator = new MultiLeafFieldComparator(comparators, reverseMul);
       }
-      this.mayNeedScoresTwice = mayNeedScoresTwice;
     }
 
     @Override
     public void setScorer(Scorer scorer) throws IOException {
-      if (mayNeedScoresTwice && scorer instanceof ScoreCachingWrappingScorer == false) {
-        scorer = new ScoreCachingWrappingScorer(scorer);
-      }
       comparator.setScorer(scorer);
       this.scorer = scorer;
     }
@@ -93,20 +92,12 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
 
     final Sort sort;
     final FieldValueHitQueue<Entry> queue;
-    final boolean trackDocScores;
-    final boolean mayNeedScoresTwice;
     final boolean trackTotalHits;
 
-    public SimpleFieldCollector(Sort sort, FieldValueHitQueue<Entry> queue, int numHits,
-        boolean trackDocScores, boolean trackTotalHits) {
-      super(queue, numHits, sort.needsScores() || trackDocScores);
+    public SimpleFieldCollector(Sort sort, FieldValueHitQueue<Entry> queue, int numHits, boolean trackTotalHits) {
+      super(queue, numHits, sort.needsScores());
       this.sort = sort;
       this.queue = queue;
-      this.trackDocScores = trackDocScores;
-      // If one of the sort fields needs scores, and if we also track scores, then
-      // we might call scorer.score() several times per doc so wrapping the scorer
-      // to cache scores would help
-      this.mayNeedScoresTwice = sort.needsScores() && trackDocScores;
       this.trackTotalHits = trackTotalHits;
     }
 
@@ -122,7 +113,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
           canEarlyTerminate(sort, indexSort);
       final int initialTotalHits = totalHits;
 
-      return new MultiComparatorLeafCollector(comparators, reverseMul, mayNeedScoresTwice) {
+      return new MultiComparatorLeafCollector(comparators, reverseMul) {
 
         @Override
         public void collect(int doc) throws IOException {
@@ -146,10 +137,6 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
               }
             }
 
-            if (trackDocScores) {
-              score = scorer.score();
-            }
-
             // This hit is competitive - replace bottom element in queue & adjustTop
             comparator.copy(bottom.slot, doc);
             updateBottom(doc, score);
@@ -158,10 +145,6 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
             // Startup transient: queue hasn't gathered numHits yet
             final int slot = totalHits - 1;
 
-            if (trackDocScores) {
-              score = scorer.score();
-            }
-
             // Copy hit into queue
             comparator.copy(slot, doc);
             add(slot, doc, score);
@@ -184,19 +167,15 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
     final Sort sort;
     int collectedHits;
     final FieldValueHitQueue<Entry> queue;
-    final boolean trackDocScores;
     final FieldDoc after;
-    final boolean mayNeedScoresTwice;
     final boolean trackTotalHits;
 
     public PagingFieldCollector(Sort sort, FieldValueHitQueue<Entry> queue, FieldDoc after, int numHits,
-                                boolean trackDocScores, boolean trackTotalHits) {
-      super(queue, numHits, trackDocScores || sort.needsScores());
+                                boolean trackTotalHits) {
+      super(queue, numHits, sort.needsScores());
       this.sort = sort;
       this.queue = queue;
-      this.trackDocScores = trackDocScores;
       this.after = after;
-      this.mayNeedScoresTwice = sort.needsScores() && trackDocScores;
       this.trackTotalHits = trackTotalHits;
 
       FieldComparator<?>[] comparators = queue.comparators;
@@ -217,7 +196,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
           indexSort != null &&
           canEarlyTerminate(sort, indexSort);
       final int initialTotalHits = totalHits;
-      return new MultiComparatorLeafCollector(queue.getComparators(context), queue.getReverseMul(), mayNeedScoresTwice) {
+      return new MultiComparatorLeafCollector(queue.getComparators(context), queue.getReverseMul()) {
 
         @Override
         public void collect(int doc) throws IOException {
@@ -256,10 +235,6 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
             // This hit is competitive - replace bottom element in queue & adjustTop
             comparator.copy(bottom.slot, doc);
 
-            // Compute score only if it is competitive.
-            if (trackDocScores) {
-              score = scorer.score();
-            }
             updateBottom(doc, score);
 
             comparator.setBottom(bottom.slot);
@@ -272,10 +247,6 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
             // Copy hit into queue
             comparator.copy(slot, doc);
 
-            // Compute score only if it is competitive.
-            if (trackDocScores) {
-              score = scorer.score();
-            }
             bottom = pq.add(new Entry(slot, docBase + doc, score));
             queueFull = collectedHits == numHits;
             if (queueFull) {
@@ -325,13 +296,6 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
    *          the sort criteria (SortFields).
    * @param numHits
    *          the number of results to collect.
-   * @param trackDocScores
-   *          specifies whether document scores should be tracked and set on the
-   *          results. Note that if set to false, then the results' scores will
-   *          be set to Float.NaN. Setting this to true affects performance, as
-   *          it incurs the score computation on each competitive result.
-   *          Therefore if document scores are not required by the application,
-   *          it is recommended to set it to false.
    * @param trackTotalHits
    *          specifies whether the total number of hits should be tracked. If
    *          set to false, the value of {@link TopFieldDocs#totalHits} will be
@@ -339,9 +303,8 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
    * @return a {@link TopFieldCollector} instance which will sort the results by
    *         the sort criteria.
    */
-  public static TopFieldCollector create(Sort sort, int numHits,
-      boolean trackDocScores, boolean trackTotalHits) {
-    return create(sort, numHits, null, trackDocScores, trackTotalHits);
+  public static TopFieldCollector create(Sort sort, int numHits, boolean trackTotalHits) {
+    return create(sort, numHits, null, trackTotalHits);
   }
 
   /**
@@ -358,14 +321,6 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
    *          the number of results to collect.
    * @param after
    *          only hits after this FieldDoc will be collected
-   * @param trackDocScores
-   *          specifies whether document scores should be tracked and set on the
-   *          results. Note that if set to false, then the results' scores will
-   *          be set to Float.NaN. Setting this to true affects performance, as
-   *          it incurs the score computation on each competitive result.
-   *          Therefore if document scores are not required by the application,
-   *          it is recommended to set it to false.
-   *          <code>trackDocScores</code> to true as well.
    * @param trackTotalHits
    *          specifies whether the total number of hits should be tracked. If
    *          set to false, the value of {@link TopFieldDocs#totalHits} will be
@@ -374,7 +329,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
    *         the sort criteria.
    */
   public static TopFieldCollector create(Sort sort, int numHits, FieldDoc after,
-      boolean trackDocScores, boolean trackTotalHits) {
+      boolean trackTotalHits) {
 
     if (sort.fields.length == 0) {
       throw new IllegalArgumentException("Sort must contain at least one field");
@@ -387,7 +342,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
     FieldValueHitQueue<Entry> queue = FieldValueHitQueue.create(sort.fields, numHits);
 
     if (after == null) {
-      return new SimpleFieldCollector(sort, queue, numHits, trackDocScores, trackTotalHits);
+      return new SimpleFieldCollector(sort, queue, numHits, trackTotalHits);
     } else {
       if (after.fields == null) {
         throw new IllegalArgumentException("after.fields wasn't set; you must pass fillFields=true for the previous search");
@@ -397,7 +352,46 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
         throw new IllegalArgumentException("after.fields has " + after.fields.length + " values but sort has " + sort.getSort().length);
       }
 
-      return new PagingFieldCollector(sort, queue, after, numHits, trackDocScores, trackTotalHits);
+      return new PagingFieldCollector(sort, queue, after, numHits, trackTotalHits);
+    }
+  }
+
+  /**
+   * Populate {@link ScoreDoc#score scores} of the given {@code topDocs}.
+   * @param topDocs   the top docs to populate
+   * @param searcher  the index searcher that has been used to compute {@code topDocs}
+   * @param query     the query that has been used to compute {@code topDocs}
+   * @throws IllegalArgumentException if there is evidence that {@code topDocs}
+   *             have been computed against a different searcher or a different query.
+   * @lucene.experimental
+   */
+  public static void populateScores(ScoreDoc[] topDocs, IndexSearcher searcher, Query query) throws IOException {
+    // Get the score docs sorted in doc id order
+    topDocs = topDocs.clone();
+    Arrays.sort(topDocs, Comparator.comparingInt(scoreDoc -> scoreDoc.doc));
+
+    final Weight weight = searcher.createWeight(searcher.rewrite(query), ScoreMode.COMPLETE, 1);
+    List<LeafReaderContext> contexts = searcher.getIndexReader().leaves();
+    LeafReaderContext currentContext = null;
+    Scorer currentScorer = null;
+    for (ScoreDoc scoreDoc : topDocs) {
+      if (currentContext == null || scoreDoc.doc >= currentContext.docBase + currentContext.reader().maxDoc()) {
+        FutureObjects.checkIndex(scoreDoc.doc, searcher.getIndexReader().maxDoc());
+        int newContextIndex = ReaderUtil.subIndex(scoreDoc.doc, contexts);
+        currentContext = contexts.get(newContextIndex);
+        final ScorerSupplier scorerSupplier = weight.scorerSupplier(currentContext);
+        if (scorerSupplier == null) {
+          throw new IllegalArgumentException("Doc id " + scoreDoc.doc + " doesn't match the query");
+        }
+        currentScorer = scorerSupplier.get(1); // random-access
+      }
+      final int leafDoc = scoreDoc.doc - currentContext.docBase;
+      assert leafDoc >= 0;
+      final int advanced = currentScorer.iterator().advance(leafDoc);
+      if (leafDoc != advanced) {
+        throw new IllegalArgumentException("Doc id " + scoreDoc.doc + " doesn't match the query");
+      }
+      scoreDoc.score = currentScorer.score();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
index f454d48..858a874 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
@@ -2324,11 +2324,11 @@ public class TestIndexSorting extends LuceneTestCase {
         System.out.println("TEST: iter=" + iter + " numHits=" + numHits);
       }
 
-      TopFieldCollector c1 = TopFieldCollector.create(sort, numHits, true, true);
+      TopFieldCollector c1 = TopFieldCollector.create(sort, numHits, true);
       s1.search(new MatchAllDocsQuery(), c1);
       TopDocs hits1 = c1.topDocs();
 
-      TopFieldCollector c2 = TopFieldCollector.create(sort, numHits, true, false);
+      TopFieldCollector c2 = TopFieldCollector.create(sort, numHits, false);
       s2.search(new MatchAllDocsQuery(), c2);
 
       TopDocs hits2 = c2.topDocs();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/search/TestBoolean2.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBoolean2.java b/lucene/core/src/test/org/apache/lucene/search/TestBoolean2.java
index 9485717..bc0531e 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestBoolean2.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestBoolean2.java
@@ -386,10 +386,10 @@ public class TestBoolean2 extends LuceneTestCase {
         }
 
         // check diff (randomized) scorers (from AssertingSearcher) produce the same results
-        TopFieldCollector collector = TopFieldCollector.create(sort, 1000, true, false);
+        TopFieldCollector collector = TopFieldCollector.create(sort, 1000, false);
         searcher.search(q1, collector);
         ScoreDoc[] hits1 = collector.topDocs().scoreDocs;
-        collector = TopFieldCollector.create(sort, 1000, true, false);
+        collector = TopFieldCollector.create(sort, 1000, false);
         searcher.search(q1, collector);
         ScoreDoc[] hits2 = collector.topDocs().scoreDocs;
         tot+=hits2.length;
@@ -402,10 +402,10 @@ public class TestBoolean2 extends LuceneTestCase {
         assertEquals(mulFactor*collector.totalHits + NUM_EXTRA_DOCS/2, hits4.totalHits);
 
         // test diff (randomized) scorers produce the same results on bigSearcher as well
-        collector = TopFieldCollector.create(sort, 1000 * mulFactor, true, false);
+        collector = TopFieldCollector.create(sort, 1000 * mulFactor, false);
         bigSearcher.search(q1, collector);
         hits1 = collector.topDocs().scoreDocs;
-        collector = TopFieldCollector.create(sort, 1000 * mulFactor, true, false);
+        collector = TopFieldCollector.create(sort, 1000 * mulFactor, false);
         bigSearcher.search(q1, collector);
         hits2 = collector.topDocs().scoreDocs;
         CheckHits.checkEqual(q1, hits1, hits2);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/search/TestElevationComparator.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestElevationComparator.java b/lucene/core/src/test/org/apache/lucene/search/TestElevationComparator.java
index 5d5488a..337bb36 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestElevationComparator.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestElevationComparator.java
@@ -86,7 +86,7 @@ public class TestElevationComparator extends LuceneTestCase {
         new SortField(null, SortField.Type.SCORE, reversed)
       );
 
-    TopDocsCollector<Entry> topCollector = TopFieldCollector.create(sort, 50, true, true);
+    TopDocsCollector<Entry> topCollector = TopFieldCollector.create(sort, 50, true);
     searcher.search(newq.build(), topCollector);
 
     TopDocs topDocs = topCollector.topDocs(0, 10);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java b/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java
index a96399e..d1a852f 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java
@@ -146,7 +146,7 @@ public class TestSortRandom extends LuceneTestCase {
       }
       final int hitCount = TestUtil.nextInt(random, 1, r.maxDoc() + 20);
       final RandomQuery f = new RandomQuery(random.nextLong(), random.nextFloat(), docValues);
-      hits = s.search(f, hitCount, sort, random.nextBoolean());
+      hits = s.search(f, hitCount, sort, false);
 
       if (VERBOSE) {
         System.out.println("\nTEST: iter=" + iter + " " + hits.totalHits + " hits; topN=" + hitCount + "; reverse=" + reverse + "; sortMissingLast=" + sortMissingLast + " sort=" + sort);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java
index 2174acf..8d6e9d5 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java
@@ -281,7 +281,7 @@ public class TestTopDocsMerge extends LuceneTestCase {
           topHits = searcher.search(query, numHits);
         }
       } else {
-        final TopFieldCollector c = TopFieldCollector.create(sort, numHits, true, true);
+        final TopFieldCollector c = TopFieldCollector.create(sort, numHits, true);
         searcher.search(query, c);
         if (useFrom) {
           from = TestUtil.nextInt(random(), 0, numHits - 1);
@@ -330,7 +330,7 @@ public class TestTopDocsMerge extends LuceneTestCase {
         if (sort == null) {
           subHits = subSearcher.search(w, numHits);
         } else {
-          final TopFieldCollector c = TopFieldCollector.create(sort, numHits, true, true);
+          final TopFieldCollector c = TopFieldCollector.create(sort, numHits, true);
           subSearcher.search(w, c);
           subHits = c.topDocs(0, numHits);
         }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
index 1b214b1..717d843 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
@@ -18,11 +18,14 @@ package org.apache.lucene.search;
 
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Comparator;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field.Store;
 import org.apache.lucene.document.NumericDocValuesField;
 import org.apache.lucene.document.StringField;
+import org.apache.lucene.document.TextField;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.RandomIndexWriter;
@@ -70,8 +73,7 @@ public class TestTopFieldCollector extends LuceneTestCase {
     Sort[] sort = new Sort[] { new Sort(SortField.FIELD_DOC), new Sort() };
     for(int i = 0; i < sort.length; i++) {
       Query q = new MatchAllDocsQuery();
-      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10,
-          false, true);
+      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10, true);
       
       is.search(q, tdc);
       
@@ -83,14 +85,13 @@ public class TestTopFieldCollector extends LuceneTestCase {
     }
   }
 
-  public void testSortWithoutScoreTracking() throws Exception {
+  public void testSort() throws Exception {
 
     // Two Sort criteria to instantiate the multi/single comparators.
     Sort[] sort = new Sort[] {new Sort(SortField.FIELD_DOC), new Sort() };
     for(int i = 0; i < sort.length; i++) {
       Query q = new MatchAllDocsQuery();
-      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10, false,
-          true);
+      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10, true);
       
       is.search(q, tdc);
       
@@ -110,10 +111,10 @@ public class TestTopFieldCollector extends LuceneTestCase {
       // the index is not sorted
       TopDocsCollector<Entry> tdc;
       if (i % 2 == 0) {
-        tdc =  TopFieldCollector.create(sort, 10, false, false);
+        tdc =  TopFieldCollector.create(sort, 10, false);
       } else {
         FieldDoc fieldDoc = new FieldDoc(1, Float.NaN, new Object[] { 1 });
-        tdc = TopFieldCollector.create(sort, 10, fieldDoc, false, false);
+        tdc = TopFieldCollector.create(sort, 10, fieldDoc, false);
       }
 
       is.search(q, tdc);
@@ -125,32 +126,13 @@ public class TestTopFieldCollector extends LuceneTestCase {
       }
     }
   }
-  
-  public void testSortWithScoreTracking() throws Exception {
-    
-    // Two Sort criteria to instantiate the multi/single comparators.
-    Sort[] sort = new Sort[] {new Sort(SortField.FIELD_DOC), new Sort() };
-    for(int i = 0; i < sort.length; i++) {
-      Query q = new MatchAllDocsQuery();
-      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10, true,
-          true);
-      
-      is.search(q, tdc);
-      
-      TopDocs td = tdc.topDocs();
-      ScoreDoc[] sd = td.scoreDocs;
-      for(int j = 0; j < sd.length; j++) {
-        assertTrue(!Float.isNaN(sd[j].score));
-      }
-    }
-  }
 
-  public void testSortWithScoreTrackingNoResults() throws Exception {
+  public void testSortNoResults() throws Exception {
     
     // Two Sort criteria to instantiate the multi/single comparators.
     Sort[] sort = new Sort[] {new Sort(SortField.FIELD_DOC), new Sort() };
     for(int i = 0; i < sort.length; i++) {
-      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10, true, true);
+      TopDocsCollector<Entry> tdc = TopFieldCollector.create(sort[i], 10, true);
       TopDocs td = tdc.topDocs();
       assertEquals(0, td.totalHits);
     }
@@ -182,59 +164,112 @@ public class TestTopFieldCollector extends LuceneTestCase {
         .build();
     final IndexSearcher searcher = new IndexSearcher(reader);
     for (Sort sort : new Sort[] {new Sort(SortField.FIELD_SCORE), new Sort(new SortField("f", SortField.Type.SCORE))}) {
-      for (boolean doDocScores : new boolean[] {false, true}) {
-        final TopFieldCollector topCollector = TopFieldCollector.create(sort, TestUtil.nextInt(random(), 1, 2), doDocScores, true);
-        final Collector assertingCollector = new Collector() {
-          @Override
-          public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
-            final LeafCollector in = topCollector.getLeafCollector(context);
-            return new FilterLeafCollector(in) {
-              @Override
-              public void setScorer(final Scorer scorer) throws IOException {
-                Scorer s = new Scorer(null) {
-
-                  int lastComputedDoc = -1;
-
-                  @Override
-                  public float score() throws IOException {
-                    if (lastComputedDoc == docID()) {
-                      throw new AssertionError("Score computed twice on " + docID());
-                    }
-                    lastComputedDoc = docID();
-                    return scorer.score();
-                  }
+      final TopFieldCollector topCollector = TopFieldCollector.create(sort, TestUtil.nextInt(random(), 1, 2), true);
+      final Collector assertingCollector = new Collector() {
+        @Override
+        public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
+          final LeafCollector in = topCollector.getLeafCollector(context);
+          return new FilterLeafCollector(in) {
+            @Override
+            public void setScorer(final Scorer scorer) throws IOException {
+              Scorer s = new Scorer(null) {
 
-                  @Override
-                  public float getMaxScore(int upTo) throws IOException {
-                    return scorer.getMaxScore(upTo);
-                  }
+                int lastComputedDoc = -1;
 
-                  @Override
-                  public int docID() {
-                    return scorer.docID();
+                @Override
+                public float score() throws IOException {
+                  if (lastComputedDoc == docID()) {
+                    throw new AssertionError("Score computed twice on " + docID());
                   }
+                  lastComputedDoc = docID();
+                  return scorer.score();
+                }
 
-                  @Override
-                  public DocIdSetIterator iterator() {
-                    return scorer.iterator();
-                  }
+                @Override
+                public float getMaxScore(int upTo) throws IOException {
+                  return scorer.getMaxScore(upTo);
+                }
 
-                };
-                super.setScorer(s);
-              }
-            };
-          }
-          @Override
-          public ScoreMode scoreMode() {
-            return topCollector.scoreMode();
-          }
-        };
-        searcher.search(query, assertingCollector);
-      }
+                @Override
+                public int docID() {
+                  return scorer.docID();
+                }
+
+                @Override
+                public DocIdSetIterator iterator() {
+                  return scorer.iterator();
+                }
+
+              };
+              super.setScorer(s);
+            }
+          };
+        }
+        @Override
+        public ScoreMode scoreMode() {
+          return topCollector.scoreMode();
+        }
+      };
+      searcher.search(query, assertingCollector);
     }
     reader.close();
     w.close();
     dir.close();
   }
 
+  public void testPopulateScores() throws IOException {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+    Document doc = new Document();
+    TextField field = new TextField("f", "foo bar", Store.NO);
+    doc.add(field);
+    NumericDocValuesField sortField = new NumericDocValuesField("sort", 0);
+    doc.add(sortField);
+    w.addDocument(doc);
+
+    field.setStringValue("");
+    sortField.setLongValue(3);
+    w.addDocument(doc);
+
+    field.setStringValue("foo foo bar");
+    sortField.setLongValue(2);
+    w.addDocument(doc);
+
+    w.flush();
+
+    field.setStringValue("foo");
+    sortField.setLongValue(2);
+    w.addDocument(doc);
+
+    field.setStringValue("bar bar bar");
+    sortField.setLongValue(0);
+    w.addDocument(doc);
+
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+
+    for (String queryText : new String[] { "foo", "bar" }) {
+      Query query = new TermQuery(new Term("f", queryText));
+      for (boolean reverse : new boolean[] {false, true}) {
+        ScoreDoc[] sortedByDoc = searcher.search(query, 10).scoreDocs;
+        Arrays.sort(sortedByDoc, Comparator.comparingInt(sd -> sd.doc));
+
+        Sort sort = new Sort(new SortField("sort", SortField.Type.LONG, reverse));
+        ScoreDoc[] sortedByField = searcher.search(query, 10, sort).scoreDocs;
+        ScoreDoc[] sortedByFieldClone = sortedByField.clone();
+        TopFieldCollector.populateScores(sortedByFieldClone, searcher, query);
+        for (int i = 0; i < sortedByFieldClone.length; ++i) {
+          assertEquals(sortedByFieldClone[i].doc, sortedByField[i].doc);
+          assertSame(((FieldDoc) sortedByFieldClone[i]).fields, ((FieldDoc) sortedByField[i]).fields);
+          assertEquals(sortedByFieldClone[i].score,
+              sortedByDoc[Arrays.binarySearch(sortedByDoc, sortedByFieldClone[i], Comparator.comparingInt(sd -> sd.doc))].score, 0f);
+        }
+      }
+    }
+
+    reader.close();
+    dir.close();
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java
index b910dd8..18eec9e 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java
@@ -136,9 +136,8 @@ public class TestTopFieldCollectorEarlyTermination extends LuceneTestCase {
         } else {
           after = null;
         }
-        final boolean trackDocScores = random().nextBoolean();
-        final TopFieldCollector collector1 = TopFieldCollector.create(sort, numHits, after, trackDocScores, true);
-        final TopFieldCollector collector2 = TopFieldCollector.create(sort, numHits, after, trackDocScores, false);
+        final TopFieldCollector collector1 = TopFieldCollector.create(sort, numHits, after, true);
+        final TopFieldCollector collector2 = TopFieldCollector.create(sort, numHits, after, false);
 
         final Query query;
         if (random().nextBoolean()) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java
----------------------------------------------------------------------
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java
index 861a4a3..a2631c3 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java
@@ -241,7 +241,7 @@ public class DrillSideways {
 
                   @Override
                   public TopFieldCollector newCollector() throws IOException {
-                    return TopFieldCollector.create(sort, fTopN, after, doDocScores, true);
+                    return TopFieldCollector.create(sort, fTopN, after, true);
                   }
 
                   @Override
@@ -255,14 +255,22 @@ public class DrillSideways {
 
                 };
         ConcurrentDrillSidewaysResult<TopFieldDocs> r = search(query, collectorManager);
-        return new DrillSidewaysResult(r.facets, r.collectorResult);
+        TopFieldDocs topDocs = r.collectorResult;
+        if (doDocScores) {
+          TopFieldCollector.populateScores(topDocs.scoreDocs, searcher, query);
+        }
+        return new DrillSidewaysResult(r.facets, topDocs);
 
       } else {
 
         final TopFieldCollector hitCollector =
-                TopFieldCollector.create(sort, fTopN, after, doDocScores, true);
+                TopFieldCollector.create(sort, fTopN, after, true);
         DrillSidewaysResult r = search(query, hitCollector);
-        return new DrillSidewaysResult(r.facets, hitCollector.topDocs());
+        TopFieldDocs topDocs = hitCollector.topDocs();
+        if (doDocScores) {
+          TopFieldCollector.populateScores(topDocs.scoreDocs, searcher, query);
+        }
+        return new DrillSidewaysResult(r.facets, topDocs);
       }
     } else {
       return search(after, query, topN);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
----------------------------------------------------------------------
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
index 94b5f41..4e8b2c9 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
@@ -230,7 +230,6 @@ public class FacetsCollector extends SimpleCollector implements Collector {
         }
         hitsCollector = TopFieldCollector.create(sort, n,
                                                  (FieldDoc) after,
-                                                 doDocScores,
                                                  true); // TODO: can we disable exact hit counts
       } else {
         hitsCollector = TopScoreDocCollector.create(n, after, true);
@@ -238,6 +237,9 @@ public class FacetsCollector extends SimpleCollector implements Collector {
       searcher.search(q, MultiCollector.wrap(hitsCollector, fc));
     
       topDocs = hitsCollector.topDocs();
+      if (doDocScores) {
+        TopFieldCollector.populateScores(topDocs.scoreDocs, searcher, q);
+      }
     }
     return topDocs;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java
----------------------------------------------------------------------
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java
index 80af1b8..200d5e7 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java
@@ -304,7 +304,7 @@ public class BlockGroupingCollector extends SimpleCollector {
         collector = TopScoreDocCollector.create(maxDocsPerGroup);
       } else {
         // Sort by fields
-        collector = TopFieldCollector.create(withinGroupSort, maxDocsPerGroup, needsScores, true); // TODO: disable exact counts?
+        collector = TopFieldCollector.create(withinGroupSort, maxDocsPerGroup, true); // TODO: disable exact counts?
       }
 
       float groupMaxScore = needsScores ? Float.NEGATIVE_INFINITY : Float.NaN;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java
----------------------------------------------------------------------
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java
index a1f4bf8..8388480 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java
@@ -50,7 +50,6 @@ public class GroupingSearch {
 
   private int groupDocsOffset;
   private int groupDocsLimit = 1;
-  private boolean includeScores = true;
   private boolean includeMaxScore = true;
 
   private Double maxCacheRAMMB;
@@ -153,8 +152,7 @@ public class GroupingSearch {
 
     int topNInsideGroup = groupDocsOffset + groupDocsLimit;
     TopGroupsCollector secondPassCollector
-        = new TopGroupsCollector(grouper, topSearchGroups, groupSort, sortWithinGroup, topNInsideGroup,
-                                         includeScores, includeMaxScore);
+        = new TopGroupsCollector(grouper, topSearchGroups, groupSort, sortWithinGroup, topNInsideGroup, includeMaxScore);
 
     if (cachedCollector != null && cachedCollector.isCached()) {
       cachedCollector.replay(secondPassCollector);
@@ -173,7 +171,7 @@ public class GroupingSearch {
     int topN = groupOffset + groupLimit;
     final Query endDocsQuery = searcher.rewrite(this.groupEndDocs);
     final Weight groupEndDocs = searcher.createWeight(endDocsQuery, ScoreMode.COMPLETE_NO_SCORES, 1);
-    BlockGroupingCollector c = new BlockGroupingCollector(groupSort, topN, includeScores, groupEndDocs);
+    BlockGroupingCollector c = new BlockGroupingCollector(groupSort, topN, groupSort.needsScores() || sortWithinGroup.needsScores(), groupEndDocs);
     searcher.search(query, c);
     int topNInsideGroup = groupDocsOffset + groupDocsLimit;
     return c.getTopGroups(sortWithinGroup, groupOffset, groupDocsOffset, topNInsideGroup);
@@ -269,17 +267,6 @@ public class GroupingSearch {
   }
 
   /**
-   * Whether to include the scores per doc inside a group.
-   *
-   * @param includeScores Whether to include the scores per doc inside a group
-   * @return <code>this</code>
-   */
-  public GroupingSearch setIncludeScores(boolean includeScores) {
-    this.includeScores = includeScores;
-    return this;
-  }
-
-  /**
    * Whether to include the score of the most relevant document per group.
    *
    * @param includeMaxScore Whether to include the score of the most relevant document per group

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroupsCollector.java
----------------------------------------------------------------------
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroupsCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroupsCollector.java
index 519bd89..16dcebb 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroupsCollector.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroupsCollector.java
@@ -54,13 +54,12 @@ public class TopGroupsCollector<T> extends SecondPassGroupingCollector<T> {
    * @param groupSort         the order in which groups are returned
    * @param withinGroupSort   the order in which documents are sorted in each group
    * @param maxDocsPerGroup   the maximum number of docs to collect for each group
-   * @param getScores         if true, record the scores of all docs in each group
    * @param getMaxScores      if true, record the maximum score for each group
    */
   public TopGroupsCollector(GroupSelector<T> groupSelector, Collection<SearchGroup<T>> groups, Sort groupSort, Sort withinGroupSort,
-                            int maxDocsPerGroup, boolean getScores, boolean getMaxScores) {
+                            int maxDocsPerGroup, boolean getMaxScores) {
     super(groupSelector, groups,
-        new TopDocsReducer<>(withinGroupSort, maxDocsPerGroup, getScores, getMaxScores));
+        new TopDocsReducer<>(withinGroupSort, maxDocsPerGroup, getMaxScores));
     this.groupSort = Objects.requireNonNull(groupSort);
     this.withinGroupSort = Objects.requireNonNull(withinGroupSort);
     this.maxDocsPerGroup = maxDocsPerGroup;
@@ -114,13 +113,13 @@ public class TopGroupsCollector<T> extends SecondPassGroupingCollector<T> {
     private final boolean needsScores;
 
     TopDocsReducer(Sort withinGroupSort,
-                   int maxDocsPerGroup, boolean getScores, boolean getMaxScores) {
-      this.needsScores = getScores || getMaxScores || withinGroupSort.needsScores();
+                   int maxDocsPerGroup, boolean getMaxScores) {
+      this.needsScores = getMaxScores || withinGroupSort.needsScores();
       if (withinGroupSort == Sort.RELEVANCE) {
         supplier = () -> new TopDocsAndMaxScoreCollector(true, TopScoreDocCollector.create(maxDocsPerGroup), null);
       } else {
         supplier = () -> {
-          TopFieldCollector topDocsCollector = TopFieldCollector.create(withinGroupSort, maxDocsPerGroup, getScores, true); // TODO: disable exact counts?
+          TopFieldCollector topDocsCollector = TopFieldCollector.create(withinGroupSort, maxDocsPerGroup, true); // TODO: disable exact counts?
           MaxScoreCollector maxScoreCollector = getMaxScores ? new MaxScoreCollector() : null;
           return new TopDocsAndMaxScoreCollector(false, topDocsCollector, maxScoreCollector);
         };

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
----------------------------------------------------------------------
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
index bf36853..8415f6a 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
@@ -145,7 +145,7 @@ public class TestGrouping extends LuceneTestCase {
     final FirstPassGroupingCollector<?> c1 = createRandomFirstPassCollector(groupField, groupSort, 10);
     indexSearcher.search(new TermQuery(new Term("content", "random")), c1);
 
-    final TopGroupsCollector<?> c2 = createSecondPassCollector(c1, groupSort, Sort.RELEVANCE, 0, 5, true, true);
+    final TopGroupsCollector<?> c2 = createSecondPassCollector(c1, groupSort, Sort.RELEVANCE, 0, 5, true);
     indexSearcher.search(new TermQuery(new Term("content", "random")), c2);
 
     final TopGroups<?> groups = c2.getTopGroups(0);
@@ -218,11 +218,10 @@ public class TestGrouping extends LuceneTestCase {
                                                                        Sort sortWithinGroup,
                                                                        int groupOffset,
                                                                        int maxDocsPerGroup,
-                                                                       boolean getScores,
                                                                        boolean getMaxScores) throws IOException {
 
     Collection<SearchGroup<T>> searchGroups = firstPassGroupingCollector.getTopGroups(groupOffset);
-    return new TopGroupsCollector<>(firstPassGroupingCollector.getGroupSelector(), searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getScores, getMaxScores);
+    return new TopGroupsCollector<>(firstPassGroupingCollector.getGroupSelector(), searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getMaxScores);
   }
 
   // Basically converts searchGroups from MutableValue to BytesRef if grouping by ValueSource
@@ -233,11 +232,10 @@ public class TestGrouping extends LuceneTestCase {
                                                                    Sort groupSort,
                                                                    Sort sortWithinGroup,
                                                                    int maxDocsPerGroup,
-                                                                   boolean getScores,
                                                                    boolean getMaxScores) throws IOException {
     if (firstPassGroupingCollector.getGroupSelector().getClass().isAssignableFrom(TermGroupSelector.class)) {
       GroupSelector<BytesRef> selector = (GroupSelector<BytesRef>) firstPassGroupingCollector.getGroupSelector();
-      return new TopGroupsCollector<>(selector, searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup , getScores, getMaxScores);
+      return new TopGroupsCollector<>(selector, searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getMaxScores);
     } else {
       ValueSource vs = new BytesRefFieldSource(groupField);
       List<SearchGroup<MutableValue>> mvalSearchGroups = new ArrayList<>(searchGroups.size());
@@ -254,7 +252,7 @@ public class TestGrouping extends LuceneTestCase {
         mvalSearchGroups.add(sg);
       }
       ValueSourceGroupSelector selector = new ValueSourceGroupSelector(vs, new HashMap<>());
-      return new TopGroupsCollector<>(selector, mvalSearchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getScores, getMaxScores);
+      return new TopGroupsCollector<>(selector, mvalSearchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getMaxScores);
     }
   }
 
@@ -437,7 +435,6 @@ public class TestGrouping extends LuceneTestCase {
 
   private TopGroups<BytesRef> slowGrouping(GroupDoc[] groupDocs,
                                            String searchTerm,
-                                           boolean getScores,
                                            boolean getMaxScores,
                                            boolean doAllGroups,
                                            Sort groupSort,
@@ -507,7 +504,7 @@ public class TestGrouping extends LuceneTestCase {
         for(int docIDX=docOffset; docIDX < docIDXLimit; docIDX++) {
           final GroupDoc d = docs.get(docIDX);
           final FieldDoc fd;
-          fd = new FieldDoc(d.id, getScores ? d.score : Float.NaN, fillFields(d, docSort));
+          fd = new FieldDoc(d.id, Float.NaN, fillFields(d, docSort));
           hits[docIDX-docOffset] = fd;
         }
       } else  {
@@ -829,14 +826,11 @@ public class TestGrouping extends LuceneTestCase {
         }
         
         final String searchTerm = "real" + random().nextInt(3);
-        boolean getScores = random().nextBoolean();
         final boolean getMaxScores = random().nextBoolean();
         final Sort groupSort = getRandomSort();
         //final Sort groupSort = new Sort(new SortField[] {new SortField("sort1", SortField.STRING), new SortField("id", SortField.INT)});
         final Sort docSort = getRandomSort();
         
-        getScores |= (groupSort.needsScores() || docSort.needsScores());
-        
         final int topNGroups = TestUtil.nextInt(random(), 1, 30);
         //final int topNGroups = 10;
         final int docsPerGroup = TestUtil.nextInt(random(), 1, 50);
@@ -850,7 +844,7 @@ public class TestGrouping extends LuceneTestCase {
         final boolean doCache = random().nextBoolean();
         final boolean doAllGroups = random().nextBoolean();
         if (VERBOSE) {
-          System.out.println("TEST: groupSort=" + groupSort + " docSort=" + docSort + " searchTerm=" + searchTerm + " dF=" + r.docFreq(new Term("content", searchTerm))  +" dFBlock=" + rBlocks.docFreq(new Term("content", searchTerm)) + " topNGroups=" + topNGroups + " groupOffset=" + groupOffset + " docOffset=" + docOffset + " doCache=" + doCache + " docsPerGroup=" + docsPerGroup + " doAllGroups=" + doAllGroups + " getScores=" + getScores + " getMaxScores=" + getMaxScores);
+          System.out.println("TEST: groupSort=" + groupSort + " docSort=" + docSort + " searchTerm=" + searchTerm + " dF=" + r.docFreq(new Term("content", searchTerm))  +" dFBlock=" + rBlocks.docFreq(new Term("content", searchTerm)) + " topNGroups=" + topNGroups + " groupOffset=" + groupOffset + " docOffset=" + docOffset + " doCache=" + doCache + " docsPerGroup=" + docsPerGroup + " doAllGroups=" + doAllGroups + " getMaxScores=" + getMaxScores);
         }
         
         String groupField = "group";
@@ -935,7 +929,7 @@ public class TestGrouping extends LuceneTestCase {
         // Get 1st pass top groups using shards
         
         final TopGroups<BytesRef> topGroupsShards = searchShards(s, shards.subSearchers, query, groupSort, docSort,
-            groupOffset, topNGroups, docOffset, docsPerGroup, getScores, getMaxScores, true, true);
+            groupOffset, topNGroups, docOffset, docsPerGroup, getMaxScores, true, true);
         final TopGroupsCollector<?> c2;
         if (topGroups != null) {
           
@@ -946,7 +940,7 @@ public class TestGrouping extends LuceneTestCase {
             }
           }
           
-          c2 = createSecondPassCollector(c1, groupSort, docSort, groupOffset, docOffset + docsPerGroup, getScores, getMaxScores);
+          c2 = createSecondPassCollector(c1, groupSort, docSort, groupOffset, docOffset + docsPerGroup, getMaxScores);
           if (doCache) {
             if (cCache.isCached()) {
               if (VERBOSE) {
@@ -977,7 +971,7 @@ public class TestGrouping extends LuceneTestCase {
           }
         }
         
-        final TopGroups<BytesRef> expectedGroups = slowGrouping(groupDocs, searchTerm, getScores, getMaxScores, doAllGroups, groupSort, docSort, topNGroups, docsPerGroup, groupOffset, docOffset);
+        final TopGroups<BytesRef> expectedGroups = slowGrouping(groupDocs, searchTerm, getMaxScores, doAllGroups, groupSort, docSort, topNGroups, docsPerGroup, groupOffset, docOffset);
         
         if (VERBOSE) {
           if (expectedGroups == null) {
@@ -1023,17 +1017,16 @@ public class TestGrouping extends LuceneTestCase {
           }
         }
         
-        assertEquals(docIDToID, expectedGroups, groupsResult, true, true, getScores, true);
+        assertEquals(docIDToID, expectedGroups, groupsResult, true, true, true);
         
         // Confirm merged shards match:
-        assertEquals(docIDToID, expectedGroups, topGroupsShards, true, false, getScores, true);
+        assertEquals(docIDToID, expectedGroups, topGroupsShards, true, false, true);
         if (topGroupsShards != null) {
           verifyShards(shards.docStarts, topGroupsShards);
         }
-        
-        final boolean needsScores = getScores || getMaxScores || docSort == null;
-        final BlockGroupingCollector c3 = new BlockGroupingCollector(groupSort, groupOffset+topNGroups, needsScores,
-            sBlocks.createWeight(sBlocks.rewrite(lastDocInBlock), ScoreMode.COMPLETE_NO_SCORES, 1));
+
+        final BlockGroupingCollector c3 = new BlockGroupingCollector(groupSort, groupOffset+topNGroups,
+            groupSort.needsScores() || docSort.needsScores(), sBlocks.createWeight(sBlocks.rewrite(lastDocInBlock), ScoreMode.COMPLETE_NO_SCORES, 1));
         final AllGroupsCollector<BytesRef> allGroupsCollector2;
         final Collector c4;
         if (doAllGroups) {
@@ -1079,7 +1072,7 @@ public class TestGrouping extends LuceneTestCase {
         
         // Get shard'd block grouping result:
         final TopGroups<BytesRef> topGroupsBlockShards = searchShards(sBlocks, shardsBlocks.subSearchers, query,
-            groupSort, docSort, groupOffset, topNGroups, docOffset, docsPerGroup, getScores, getMaxScores, false, false);
+            groupSort, docSort, groupOffset, topNGroups, docOffset, docsPerGroup, getMaxScores, false, false);
         
         if (expectedGroups != null) {
           // Fixup scores for reader2
@@ -1122,8 +1115,8 @@ public class TestGrouping extends LuceneTestCase {
           }
         }
         
-        assertEquals(docIDToIDBlocks, expectedGroups, groupsResultBlocks, false, true, getScores, false);
-        assertEquals(docIDToIDBlocks, expectedGroups, topGroupsBlockShards, false, false, getScores, false);
+        assertEquals(docIDToIDBlocks, expectedGroups, groupsResultBlocks, false, true, false);
+        assertEquals(docIDToIDBlocks, expectedGroups, topGroupsBlockShards, false, false, false);
       }
       
       r.close();
@@ -1146,7 +1139,7 @@ public class TestGrouping extends LuceneTestCase {
   }
 
   private TopGroups<BytesRef> searchShards(IndexSearcher topSearcher, ShardSearcher[] subSearchers, Query query, Sort groupSort, Sort docSort, int groupOffset, int topNGroups, int docOffset,
-                                           int topNDocs, boolean getScores, boolean getMaxScores, boolean canUseIDV, boolean preFlex) throws Exception {
+                                           int topNDocs, boolean getMaxScores, boolean canUseIDV, boolean preFlex) throws Exception {
 
     // TODO: swap in caching, all groups collector hereassertEquals(expected.totalHitCount, actual.totalHitCount);
     // too...
@@ -1154,7 +1147,7 @@ public class TestGrouping extends LuceneTestCase {
       System.out.println("TEST: " + subSearchers.length + " shards: " + Arrays.toString(subSearchers) + " canUseIDV=" + canUseIDV);
     }
     // Run 1st pass collector to get top groups per shard
-    final Weight w = topSearcher.createWeight(topSearcher.rewrite(query), getScores || getMaxScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES, 1);
+    final Weight w = topSearcher.createWeight(topSearcher.rewrite(query), groupSort.needsScores() || docSort.needsScores() || getMaxScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES, 1);
     final List<Collection<SearchGroup<BytesRef>>> shardGroups = new ArrayList<>();
     List<FirstPassGroupingCollector<?>> firstPassGroupingCollectors = new ArrayList<>();
     FirstPassGroupingCollector<?> firstPassCollector = null;
@@ -1208,7 +1201,7 @@ public class TestGrouping extends LuceneTestCase {
       final TopGroups<BytesRef>[] shardTopGroups = new TopGroups[subSearchers.length];
       for(int shardIDX=0;shardIDX<subSearchers.length;shardIDX++) {
         final TopGroupsCollector<?> secondPassCollector = createSecondPassCollector(firstPassGroupingCollectors.get(shardIDX),
-            groupField, mergedTopGroups, groupSort, docSort, docOffset + topNDocs, getScores, getMaxScores);
+            groupField, mergedTopGroups, groupSort, docSort, docOffset + topNDocs, getMaxScores);
         subSearchers[shardIDX].search(w, secondPassCollector);
         shardTopGroups[shardIDX] = getTopGroups(secondPassCollector, 0);
         if (VERBOSE) {
@@ -1232,7 +1225,7 @@ public class TestGrouping extends LuceneTestCase {
     }
   }
 
-  private void assertEquals(int[] docIDtoID, TopGroups<BytesRef> expected, TopGroups<BytesRef> actual, boolean verifyGroupValues, boolean verifyTotalGroupCount, boolean testScores, boolean idvBasedImplsUsed) {
+  private void assertEquals(int[] docIDtoID, TopGroups<BytesRef> expected, TopGroups<BytesRef> actual, boolean verifyGroupValues, boolean verifyTotalGroupCount, boolean idvBasedImplsUsed) {
     if (expected == null) {
       assertNull(actual);
       return;
@@ -1279,12 +1272,6 @@ public class TestGrouping extends LuceneTestCase {
         final FieldDoc actualFD = (FieldDoc) actualFDs[docIDX];
         //System.out.println("  actual doc=" + docIDtoID[actualFD.doc] + " score=" + actualFD.score);
         assertEquals(expectedFD.doc, docIDtoID[actualFD.doc]);
-        if (testScores) {
-          assertEquals(expectedFD.score, actualFD.score, 0.1);
-        } else {
-          // TODO: too anal for now
-          //assertEquals(Float.NaN, actualFD.score);
-        }
         assertArrayEquals(expectedFD.fields, actualFD.fields);
       }
     }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java
----------------------------------------------------------------------
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java
index 35cb3df..07180e3 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java
@@ -647,7 +647,7 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
     //System.out.println("finalQuery=" + finalQuery);
 
     // Sort by weight, descending:
-    TopFieldCollector c = TopFieldCollector.create(SORT, num, false, false);
+    TopFieldCollector c = TopFieldCollector.create(SORT, num, false);
     List<LookupResult> results = null;
     SearcherManager mgr;
     IndexSearcher searcher;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
index 3b81914..1354ea8 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
@@ -535,7 +535,7 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia
       DocIdSetIterator iterator = new BitSetIterator(groupBits, 0); // cost is not useful here
       int group;
       while ((group = iterator.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
-        Collector collector = (sort == null) ? TopScoreDocCollector.create(limit) : TopFieldCollector.create(sort, limit, false, true);
+        Collector collector = (sort == null) ? TopScoreDocCollector.create(limit) : TopFieldCollector.create(sort, limit, true);
         groups.put(group, collector);
       }
 
@@ -619,7 +619,7 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia
       Iterator<LongCursor> iterator = groupSet.iterator();
       while (iterator.hasNext()) {
         LongCursor cursor = iterator.next();
-        Collector collector = (sort == null) ? TopScoreDocCollector.create(limit) : TopFieldCollector.create(sort, limit, false, true);
+        Collector collector = (sort == null) ? TopScoreDocCollector.create(limit) : TopFieldCollector.create(sort, limit, true);
         groups.put(cursor.value, collector);
       }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
index 1a34b58..2ec8cc4 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
@@ -1327,6 +1327,7 @@ public class QueryComponent extends SearchComponent
 
       secondPhaseBuilder.addCommandField(
           new TopGroupsFieldCommand.Builder()
+              .setQuery(cmd.getQuery())
               .setField(schemaField)
               .setGroupSort(groupingSpec.getGroupSort())
               .setSortWithinGroup(groupingSpec.getSortWithinGroup())

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/Grouping.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/Grouping.java b/solr/core/src/java/org/apache/solr/search/Grouping.java
index ba8f4cd..cb7dccd 100644
--- a/solr/core/src/java/org/apache/solr/search/Grouping.java
+++ b/solr/core/src/java/org/apache/solr/search/Grouping.java
@@ -590,6 +590,14 @@ public class Grouping {
       return null;
     }
 
+    protected void populateScoresIfNecessary() throws IOException {
+      if (needScores) {
+        for (GroupDocs<?> groups : result.groups) {
+          TopFieldCollector.populateScores(groups.scoreDocs, searcher, query);
+        }
+      }
+    }
+
     protected NamedList commonResponse() {
       NamedList groupResult = new SimpleOrderedMap();
       grouped.add(key, groupResult);  // grouped={ key={
@@ -747,7 +755,7 @@ public class Grouping {
       groupedDocsToCollect = Math.max(groupedDocsToCollect, 1);
       Sort withinGroupSort = this.withinGroupSort != null ? this.withinGroupSort : Sort.RELEVANCE;
       secondPass = new TopGroupsCollector<>(new TermGroupSelector(groupBy),
-          topGroups, groupSort, withinGroupSort, groupedDocsToCollect, needScores, needScores
+          topGroups, groupSort, withinGroupSort, groupedDocsToCollect, needScores
       );
 
       if (totalCount == TotalCount.grouped) {
@@ -766,7 +774,10 @@ public class Grouping {
 
     @Override
     protected void finish() throws IOException {
-      result = secondPass != null ? secondPass.getTopGroups(0) : null;
+      if (secondPass != null) {
+        result = secondPass.getTopGroups(0);
+        populateScoresIfNecessary();
+      }
       if (main) {
         mainResult = createSimpleResponse();
         return;
@@ -850,7 +861,7 @@ public class Grouping {
       if (withinGroupSort == null || withinGroupSort.equals(Sort.RELEVANCE)) {
         subCollector = topCollector = TopScoreDocCollector.create(groupDocsToCollect);
       } else {
-        topCollector = TopFieldCollector.create(searcher.weightSort(withinGroupSort), groupDocsToCollect, needScores, true);
+        topCollector = TopFieldCollector.create(searcher.weightSort(withinGroupSort), groupDocsToCollect, true);
         if (needScores) {
           maxScoreCollector = new MaxScoreCollector();
           subCollector = MultiCollector.wrap(topCollector, maxScoreCollector);
@@ -952,7 +963,7 @@ public class Grouping {
       groupdDocsToCollect = Math.max(groupdDocsToCollect, 1);
       Sort withinGroupSort = this.withinGroupSort != null ? this.withinGroupSort : Sort.RELEVANCE;
       secondPass = new TopGroupsCollector<>(newSelector(),
-          topGroups, groupSort, withinGroupSort, groupdDocsToCollect, needScores, needScores
+          topGroups, groupSort, withinGroupSort, groupdDocsToCollect, needScores
       );
 
       if (totalCount == TotalCount.grouped) {
@@ -971,7 +982,10 @@ public class Grouping {
 
     @Override
     protected void finish() throws IOException {
-      result = secondPass != null ? secondPass.getTopGroups(0) : null;
+      if (secondPass != null) {
+        result = secondPass.getTopGroups(0);
+        populateScoresIfNecessary();
+      }
       if (main) {
         mainResult = createSimpleResponse();
         return;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/ReRankCollector.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ReRankCollector.java b/solr/core/src/java/org/apache/solr/search/ReRankCollector.java
index 6b2588b..0888f79 100644
--- a/solr/core/src/java/org/apache/solr/search/ReRankCollector.java
+++ b/solr/core/src/java/org/apache/solr/search/ReRankCollector.java
@@ -27,6 +27,7 @@ import com.carrotsearch.hppc.IntIntHashMap;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.LeafCollector;
+import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Rescorer;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.ScoreMode;
@@ -49,6 +50,8 @@ public class ReRankCollector extends TopDocsCollector {
   final private int length;
   final private Set<BytesRef> boostedPriority; // order is the "priority"
   final private Rescorer reRankQueryRescorer;
+  final private Sort sort;
+  final private Query query;
 
 
   public ReRankCollector(int reRankDocs,
@@ -61,13 +64,15 @@ public class ReRankCollector extends TopDocsCollector {
     this.reRankDocs = reRankDocs;
     this.length = length;
     this.boostedPriority = boostedPriority;
+    this.query = cmd.getQuery();
     Sort sort = cmd.getSort();
     if(sort == null) {
+      this.sort = null;
       this.mainCollector = TopScoreDocCollector.create(Math.max(this.reRankDocs, length));
     } else {
-      sort = sort.rewrite(searcher);
+      this.sort = sort = sort.rewrite(searcher);
       //scores are needed for Rescorer (regardless of whether sort needs it)
-      this.mainCollector = TopFieldCollector.create(sort, Math.max(this.reRankDocs, length), true, true);
+      this.mainCollector = TopFieldCollector.create(sort, Math.max(this.reRankDocs, length), true);
     }
     this.searcher = searcher;
     this.reRankQueryRescorer = reRankQueryRescorer;
@@ -84,7 +89,7 @@ public class ReRankCollector extends TopDocsCollector {
 
   @Override
   public ScoreMode scoreMode() {
-    return ScoreMode.COMPLETE; // since the scores will be needed by Rescorer as input regardless of mainCollector
+    return sort == null || sort.needsScores() ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES;
   }
 
   public TopDocs topDocs(int start, int howMany) {
@@ -97,6 +102,10 @@ public class ReRankCollector extends TopDocsCollector {
         return mainDocs;
       }
 
+      if (sort != null) {
+        TopFieldCollector.populateScores(mainDocs.scoreDocs, searcher, query);
+      }
+
       ScoreDoc[] mainScoreDocs = mainDocs.scoreDocs;
       ScoreDoc[] reRankScoreDocs = new ScoreDoc[Math.min(mainScoreDocs.length, reRankDocs)];
       System.arraycopy(mainScoreDocs, 0, reRankScoreDocs, 0, reRankScoreDocs.length);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index 30b0942..6cbcd0d 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -1532,12 +1532,11 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       return TopScoreDocCollector.create(len);
     } else {
       // we have a sort
-      final boolean needScores = (cmd.getFlags() & GET_SCORES) != 0;
       final Sort weightedSort = weightSort(cmd.getSort());
       final CursorMark cursor = cmd.getCursorMark();
 
       final FieldDoc searchAfter = (null != cursor ? cursor.getSearchAfterFieldDoc() : null);
-      return TopFieldCollector.create(weightedSort, len, searchAfter, needScores, true);
+      return TopFieldCollector.create(weightedSort, len, searchAfter, true);
     }
   }
 
@@ -1624,6 +1623,9 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
 
       totalHits = topCollector.getTotalHits();
       TopDocs topDocs = topCollector.topDocs(0, len);
+      if (cmd.getSort() != null && query instanceof RankQuery == false && (cmd.getFlags() & GET_SCORES) != 0) {
+        TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
+      }
       populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
 
       maxScore = totalHits > 0 ? (maxScoreCollector == null ? Float.NaN : maxScoreCollector.getMaxScore()) : 0.0f;
@@ -1732,6 +1734,9 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       assert (totalHits == set.size());
 
       TopDocs topDocs = topCollector.topDocs(0, len);
+      if (cmd.getSort() != null && query instanceof RankQuery == false && (cmd.getFlags() & GET_SCORES) != 0) {
+        TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
+      }
       populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
       maxScore = totalHits > 0 ? (maxScoreCollector == null ? Float.NaN : maxScoreCollector.getMaxScore()) : 0.0f;
       nDocsReturned = topDocs.scoreDocs.length;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/grouping/Command.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/Command.java b/solr/core/src/java/org/apache/solr/search/grouping/Command.java
index 7391df6..9d64755 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/Command.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/Command.java
@@ -17,6 +17,7 @@
 package org.apache.solr.search.grouping;
 
 import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Sort;
 import java.io.IOException;
 import java.util.List;
@@ -40,6 +41,12 @@ public interface Command<T> {
   List<Collector> create() throws IOException;
 
   /**
+   * Run post-collection steps.
+   * @throws IOException If I/O related errors occur
+   */
+  default void postCollect(IndexSearcher searcher) throws IOException {}
+
+  /**
    * Returns the results that the collectors created
    * by {@link #create()} contain after a search has been executed.
    *

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/grouping/CommandHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/CommandHandler.java b/solr/core/src/java/org/apache/solr/search/grouping/CommandHandler.java
index 4ec01db..ec421e4 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/CommandHandler.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/CommandHandler.java
@@ -163,6 +163,10 @@ public class CommandHandler {
     } else {
       searchWithTimeLimiter(query, filter, null);
     }
+
+    for (Command command : commands) {
+      command.postCollect(searcher);
+    }
   }
 
   private DocSet computeGroupedDocSet(Query query, ProcessedFilter filter, List<Collector> collectors) throws IOException {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java
index f88f170..93b55b1 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/QueryCommand.java
@@ -114,6 +114,7 @@ public class QueryCommand implements Command<QueryCommandResult> {
   private TopDocsCollector topDocsCollector;
   private FilterCollector filterCollector;
   private MaxScoreCollector maxScoreCollector;
+  private TopDocs topDocs;
 
   private QueryCommand(Sort sort, Query query, int docsToCollect, boolean needScores, DocSet docSet, String queryString) {
     this.sort = sort;
@@ -130,7 +131,7 @@ public class QueryCommand implements Command<QueryCommandResult> {
     if (sort == null || sort.equals(Sort.RELEVANCE)) {
       subCollector = topDocsCollector = TopScoreDocCollector.create(docsToCollect);
     } else {
-      topDocsCollector = TopFieldCollector.create(sort, docsToCollect, needScores, true);
+      topDocsCollector = TopFieldCollector.create(sort, docsToCollect, true);
       if (needScores) {
         maxScoreCollector = new MaxScoreCollector();
         subCollector = MultiCollector.wrap(topDocsCollector, maxScoreCollector);
@@ -143,8 +144,15 @@ public class QueryCommand implements Command<QueryCommandResult> {
   }
 
   @Override
-  public QueryCommandResult result() {
-    TopDocs topDocs = topDocsCollector.topDocs();
+  public void postCollect(IndexSearcher searcher) throws IOException {
+    topDocs = topDocsCollector.topDocs();
+    if (needScores) {
+      TopFieldCollector.populateScores(topDocs.scoreDocs, searcher, query);
+    }
+  }
+
+  @Override
+  public QueryCommandResult result() throws IOException {
     float maxScore;
     if (sort == null) {
       maxScore = topDocs.scoreDocs.length == 0 ? Float.NaN : topDocs.scoreDocs[0].score;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/55bfadbc/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java
index 157e10d..3902841 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java
@@ -25,7 +25,10 @@ import java.util.List;
 
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.TopFieldCollector;
 import org.apache.lucene.search.grouping.GroupDocs;
 import org.apache.lucene.search.grouping.SearchGroup;
 import org.apache.lucene.search.grouping.TermGroupSelector;
@@ -45,6 +48,7 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
 
   public static class Builder {
 
+    private Query query;
     private SchemaField field;
     private Sort groupSort;
     private Sort withinGroupSort;
@@ -53,6 +57,11 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
     private boolean needScores = false;
     private boolean needMaxScore = false;
 
+    public Builder setQuery(Query query) {
+      this.query = query;
+      return this;
+    }
+
     public Builder setField(SchemaField field) {
       this.field = field;
       return this;
@@ -89,16 +98,17 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
     }
 
     public TopGroupsFieldCommand build() {
-      if (field == null || groupSort == null ||  withinGroupSort == null || firstPhaseGroups == null ||
+      if (query == null || field == null || groupSort == null ||  withinGroupSort == null || firstPhaseGroups == null ||
           maxDocPerGroup == null) {
         throw new IllegalStateException("All required fields must be set");
       }
 
-      return new TopGroupsFieldCommand(field, groupSort, withinGroupSort, firstPhaseGroups, maxDocPerGroup, needScores, needMaxScore);
+      return new TopGroupsFieldCommand(query, field, groupSort, withinGroupSort, firstPhaseGroups, maxDocPerGroup, needScores, needMaxScore);
     }
 
   }
 
+  private final Query query;
   private final SchemaField field;
   private final Sort groupSort;
   private final Sort withinGroupSort;
@@ -107,14 +117,17 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
   private final boolean needScores;
   private final boolean needMaxScore;
   private TopGroupsCollector secondPassCollector;
+  private TopGroups<BytesRef> topGroups;
 
-  private TopGroupsFieldCommand(SchemaField field,
+  private TopGroupsFieldCommand(Query query,
+                                SchemaField field,
                                 Sort groupSort,
                                 Sort withinGroupSort,
                                 Collection<SearchGroup<BytesRef>> firstPhaseGroups,
                                 int maxDocPerGroup,
                                 boolean needScores,
                                 boolean needMaxScore) {
+    this.query = query;
     this.field = field;
     this.groupSort = groupSort;
     this.withinGroupSort = withinGroupSort;
@@ -136,11 +149,11 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
       ValueSource vs = fieldType.getValueSource(field, null);
       Collection<SearchGroup<MutableValue>> v = GroupConverter.toMutable(field, firstPhaseGroups);
       secondPassCollector = new TopGroupsCollector<>(new ValueSourceGroupSelector(vs, new HashMap<>()),
-          v, groupSort, withinGroupSort, maxDocPerGroup, needScores, needMaxScore
+          v, groupSort, withinGroupSort, maxDocPerGroup, needMaxScore
       );
     } else {
       secondPassCollector = new TopGroupsCollector<>(new TermGroupSelector(field.getName()),
-          firstPhaseGroups, groupSort, withinGroupSort, maxDocPerGroup, needScores, needMaxScore
+          firstPhaseGroups, groupSort, withinGroupSort, maxDocPerGroup, needMaxScore
       );
     }
     collectors.add(secondPassCollector);
@@ -148,21 +161,30 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
   }
 
   @Override
-  @SuppressWarnings("unchecked")
-  public TopGroups<BytesRef> result() {
+  public void postCollect(IndexSearcher searcher) throws IOException {
     if (firstPhaseGroups.isEmpty()) {
-      return new TopGroups<>(groupSort.getSort(), withinGroupSort.getSort(), 0, 0, new GroupDocs[0], Float.NaN);
+      topGroups = new TopGroups<>(groupSort.getSort(), withinGroupSort.getSort(), 0, 0, new GroupDocs[0], Float.NaN);
+      return;
     }
 
     FieldType fieldType = field.getType();
     if (fieldType.getNumberType() != null) {
-      return GroupConverter.fromMutable(field, secondPassCollector.getTopGroups(0));
+      topGroups = GroupConverter.fromMutable(field, secondPassCollector.getTopGroups(0));
     } else {
-      return secondPassCollector.getTopGroups(0);
+      topGroups = secondPassCollector.getTopGroups(0);
+    }
+    for (GroupDocs<?> group : topGroups.groups) {
+      TopFieldCollector.populateScores(group.scoreDocs, searcher, query);
     }
   }
 
   @Override
+  @SuppressWarnings("unchecked")
+  public TopGroups<BytesRef> result() throws IOException {
+    return topGroups;
+  }
+
+  @Override
   public String getKey() {
     return field.getName();
   }


Mime
View raw message