lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jpou...@apache.org
Subject [2/3] lucene-solr:master: LUCENE-8142: Make postings APIs expose raw impacts rather than scores.
Date Wed, 02 May 2018 13:12:44 GMT
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/index/SlowImpactsEnum.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/index/SlowImpactsEnum.java b/lucene/core/src/java/org/apache/lucene/index/SlowImpactsEnum.java
index 9ba27e2..6177ea4 100644
--- a/lucene/core/src/java/org/apache/lucene/index/SlowImpactsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/SlowImpactsEnum.java
@@ -17,23 +17,45 @@
 package org.apache.lucene.index;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 
+import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.util.BytesRef;
 
 /**
  * {@link ImpactsEnum} that doesn't index impacts but implements the API in a
- * legal way. This should typically be used for short postings that do not need
+ * legal way. This is typically used for short postings that do not need
  * skipping.
  */
 public final class SlowImpactsEnum extends ImpactsEnum {
 
+  private static final Impacts DUMMY_IMPACTS = new Impacts() {
+
+    private final List<Impact> impacts = Collections.singletonList(new Impact(Integer.MAX_VALUE, 1L));
+
+    @Override
+    public int numLevels() {
+      return 1;
+    }
+
+    @Override
+    public int getDocIdUpTo(int level) {
+      return DocIdSetIterator.NO_MORE_DOCS;
+    }
+
+    @Override
+    public List<Impact> getImpacts(int level) {
+      return impacts;
+    }
+
+  };
+
   private final PostingsEnum delegate;
-  private final float maxScore;
 
   /** Wrap the given {@link PostingsEnum}. */
-  public SlowImpactsEnum(PostingsEnum delegate, float maxScore) {
+  public SlowImpactsEnum(PostingsEnum delegate) {
     this.delegate = delegate;
-    this.maxScore = maxScore;
   }
 
   @Override
@@ -82,13 +104,10 @@ public final class SlowImpactsEnum extends ImpactsEnum {
   }
 
   @Override
-  public int advanceShallow(int target) {
-    return NO_MORE_DOCS;
-  }
+  public void advanceShallow(int target) {}
 
   @Override
-  public float getMaxScore(int maxDoc) {
-    return maxScore;
+  public Impacts getImpacts() {
+    return DUMMY_IMPACTS;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java b/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java
index 70d4387..5fe9a0d 100644
--- a/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java
@@ -19,7 +19,6 @@ package org.apache.lucene.index;
 
 import java.io.IOException;
 
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.BytesRefBuilder;
 
@@ -111,7 +110,7 @@ class SortedDocValuesTermsEnum extends TermsEnum {
   }
 
   @Override
-  public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+  public ImpactsEnum impacts(int flags) throws IOException {
     throw new UnsupportedOperationException();
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesTermsEnum.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesTermsEnum.java b/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesTermsEnum.java
index 9099ac8..bbeb5c2 100644
--- a/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesTermsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesTermsEnum.java
@@ -17,7 +17,6 @@
 package org.apache.lucene.index;
 
 
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.BytesRefBuilder;
 
@@ -111,7 +110,7 @@ class SortedSetDocValuesTermsEnum extends TermsEnum {
   }
 
   @Override
-  public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+  public ImpactsEnum impacts(int flags) throws IOException {
     throw new UnsupportedOperationException();
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/index/TermsEnum.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/index/TermsEnum.java b/lucene/core/src/java/org/apache/lucene/index/TermsEnum.java
index 983bd9c..e1e48ef 100644
--- a/lucene/core/src/java/org/apache/lucene/index/TermsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/TermsEnum.java
@@ -19,7 +19,6 @@ package org.apache.lucene.index;
 
 import java.io.IOException;
 
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.AttributeSource;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.BytesRefIterator;
@@ -171,10 +170,10 @@ public abstract class TermsEnum implements BytesRefIterator {
   public abstract PostingsEnum postings(PostingsEnum reuse, int flags) throws IOException;
 
   /**
-   * Return a {@link ImpactsEnum} that computes impacts with {@code scorer}.
+   * Return a {@link ImpactsEnum}.
    * @see #postings(PostingsEnum, int)
    */
-  public abstract ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException;
+  public abstract ImpactsEnum impacts(int flags) throws IOException;
   
   /**
    * Expert: Returns the TermsEnums internal state to position the TermsEnum
@@ -236,7 +235,7 @@ public abstract class TermsEnum implements BytesRefIterator {
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+    public ImpactsEnum impacts(int flags) throws IOException {
       throw new IllegalStateException("this method should never be called");
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionScorer.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionScorer.java b/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionScorer.java
index 070b6c4..bb5d99c 100644
--- a/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionScorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionScorer.java
@@ -38,6 +38,9 @@ final class BlockMaxConjunctionScorer extends Scorer {
   BlockMaxConjunctionScorer(Weight weight, Collection<Scorer> scorersList) throws IOException {
     super(weight);
     this.scorers = scorersList.toArray(new Scorer[scorersList.size()]);
+    for (Scorer scorer : scorers) {
+      scorer.advanceShallow(0);
+    }
     this.maxScorePropagator = new MaxScoreSumPropagator(scorersList);
 
     // Put scorers with the higher max scores first

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java b/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java
index 72f9473..375d3c2 100644
--- a/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java
@@ -23,7 +23,6 @@ import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermState;
 import org.apache.lucene.index.Terms;
 import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.Attribute;
 import org.apache.lucene.util.AttributeImpl;
 import org.apache.lucene.util.AttributeReflector;
@@ -275,8 +274,8 @@ public final class FuzzyTermsEnum extends TermsEnum {
   }
   
   @Override
-  public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
-    return actualEnum.impacts(scorer, flags);
+  public ImpactsEnum impacts(int flags) throws IOException {
+    return actualEnum.impacts(flags);
   }
   
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/search/MaxScoreCache.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/MaxScoreCache.java b/lucene/core/src/java/org/apache/lucene/search/MaxScoreCache.java
new file mode 100644
index 0000000..719bc14
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/search/MaxScoreCache.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.search;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.lucene.index.Impact;
+import org.apache.lucene.index.Impacts;
+import org.apache.lucene.index.ImpactsEnum;
+import org.apache.lucene.search.similarities.Similarity.SimScorer;
+import org.apache.lucene.util.ArrayUtil;
+
+/**
+ * Compute maximum scores based on {@link Impacts} and keep them in a cache in
+ * order not to run expensive similarity score computations multiple times on
+ * the same data.
+ */
+public final class MaxScoreCache {
+
+  private final ImpactsEnum impactsEnum;
+  private final SimScorer scorer;
+  private final float globalMaxScore;
+  private float[] maxScoreCache;
+  private int[] maxScoreCacheUpTo;
+
+  /**
+   * Sole constructor.
+   */
+  public MaxScoreCache(ImpactsEnum impactsEnum, SimScorer scorer) {
+    this.impactsEnum = impactsEnum;
+    this.scorer = scorer;
+    globalMaxScore = scorer.score(Integer.MAX_VALUE, 1L);
+    maxScoreCache = new float[0];
+    maxScoreCacheUpTo = new int[0];
+  }
+
+  private void ensureCacheSize(int size) {
+    if (maxScoreCache.length < size) {
+      int oldLength = maxScoreCache.length;
+      maxScoreCache = ArrayUtil.grow(maxScoreCache, size);
+      maxScoreCacheUpTo = Arrays.copyOf(maxScoreCacheUpTo, maxScoreCache.length);
+      Arrays.fill(maxScoreCacheUpTo, oldLength, maxScoreCacheUpTo.length, -1);
+    }
+  }
+
+  private float computeMaxScore(List<Impact> impacts) {
+    float maxScore = 0;
+    for (Impact impact : impacts) {
+      maxScore = Math.max(scorer.score(impact.freq, impact.norm), maxScore);
+    }
+    return maxScore;
+  }
+
+  /**
+   * Return the first level that includes all doc IDs up to {@code upTo},
+   * or -1 if there is no such level.
+   */
+  private int getLevel(int upTo) throws IOException {
+    final Impacts impacts = impactsEnum.getImpacts();
+    for (int level = 0, numLevels = impacts.numLevels(); level < numLevels; ++level) {
+      final int impactsUpTo = impacts.getDocIdUpTo(level);
+      if (upTo <= impactsUpTo) {
+        return level;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Return the maximum score for the given {@code level}.
+   */
+  float getMaxScoreForLevel(int level) throws IOException {
+    final Impacts impacts = impactsEnum.getImpacts();
+    ensureCacheSize(level + 1);
+    final int levelUpTo = impacts.getDocIdUpTo(level);
+    if (maxScoreCacheUpTo[level] < levelUpTo) {
+      maxScoreCache[level] = computeMaxScore(impacts.getImpacts(level));
+      maxScoreCacheUpTo[level] = levelUpTo;
+    }
+    return maxScoreCache[level];
+  }
+
+  /**
+   * Return the maximum level at which scores are all less than {@code minScore},
+   * or -1 if none.
+   */
+  int getSkipLevel(float minScore) throws IOException {
+    final Impacts impacts = impactsEnum.getImpacts();
+    final int numLevels = impacts.numLevels();
+    for (int level = 0; level < numLevels; ++level) {
+      if (getMaxScoreForLevel(level) >= minScore) {
+        return level - 1;
+      }
+    }
+    return numLevels - 1;
+  }
+
+  /**
+   * Implement the contract of {@link Scorer#advanceShallow(int)} based on the
+   * wrapped {@link ImpactsEnum}.
+   * @see Scorer#advanceShallow(int)
+   */
+  public int advanceShallow(int target) throws IOException {
+    impactsEnum.advanceShallow(target);
+    Impacts impacts = impactsEnum.getImpacts();
+    return impacts.getDocIdUpTo(0);
+  }
+
+  /**
+   * Implement the contract of {@link Scorer#getMaxScore(int)} based on the
+   * wrapped {@link ImpactsEnum} and {@link Scorer}.
+   * @see Scorer#getMaxScore(int)
+   */
+  public float getMaxScore(int upTo) throws IOException {
+    final int level = getLevel(upTo);
+    if (level == -1) {
+      return globalMaxScore;
+    } else {
+      return getMaxScoreForLevel(level);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/search/Scorer.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/Scorer.java b/lucene/core/src/java/org/apache/lucene/search/Scorer.java
index 81624cc..9a48840 100644
--- a/lucene/core/src/java/org/apache/lucene/search/Scorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/Scorer.java
@@ -161,8 +161,8 @@ public abstract class Scorer {
    * Advance to the block of documents that contains {@code target} in order to
    * get scoring information about this block. This method is implicitly called
    * by {@link DocIdSetIterator#advance(int)} and
-   * {@link DocIdSetIterator#nextDoc()}. Calling this method doesn't modify the
-   * current {@link DocIdSetIterator#docID()}.
+   * {@link DocIdSetIterator#nextDoc()} on the returned doc ID. Calling this
+   * method doesn't modify the current {@link DocIdSetIterator#docID()}.
    * It returns a number that is greater than or equal to all documents
    * contained in the current block, but less than any doc IDS of the next block.
    * {@code target} must be &gt;= {@link #docID()} as well as all targets that

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/search/TermScorer.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/TermScorer.java b/lucene/core/src/java/org/apache/lucene/search/TermScorer.java
index d51626f..66cf833 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TermScorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TermScorer.java
@@ -19,6 +19,7 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 
+import org.apache.lucene.index.Impacts;
 import org.apache.lucene.index.ImpactsEnum;
 import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.SlowImpactsEnum;
@@ -31,6 +32,7 @@ final class TermScorer extends Scorer {
   private final ImpactsEnum impactsEnum;
   private final DocIdSetIterator iterator;
   private final LeafSimScorer docScorer;
+  private final MaxScoreCache maxScoreCache;
   private float minCompetitiveScore;
 
   /**
@@ -47,7 +49,8 @@ final class TermScorer extends Scorer {
     super(weight);
     this.docScorer = docScorer;
     if (scoreMode == ScoreMode.TOP_SCORES) {
-      impactsEnum = te.impacts(docScorer.getSimScorer(), PostingsEnum.FREQS);
+      impactsEnum = te.impacts(PostingsEnum.FREQS);
+      maxScoreCache = new MaxScoreCache(impactsEnum, docScorer.getSimScorer());
       postingsEnum = impactsEnum;
       iterator = new DocIdSetIterator() {
 
@@ -61,8 +64,10 @@ final class TermScorer extends Scorer {
           }
 
           if (target > upTo) {
-            upTo = impactsEnum.advanceShallow(target);
-            maxScore = impactsEnum.getMaxScore(upTo);
+            impactsEnum.advanceShallow(target);
+            Impacts impacts = impactsEnum.getImpacts();
+            upTo = impacts.getDocIdUpTo(0);
+            maxScore = maxScoreCache.getMaxScoreForLevel(0);
           }
 
           while (true) {
@@ -76,10 +81,23 @@ final class TermScorer extends Scorer {
               return NO_MORE_DOCS;
             }
 
-            target = upTo + 1;
-
-            upTo = impactsEnum.advanceShallow(target);
-            maxScore = impactsEnum.getMaxScore(upTo);
+            impactsEnum.advanceShallow(upTo + 1);
+            Impacts impacts = impactsEnum.getImpacts();
+            final int level = maxScoreCache.getSkipLevel(minCompetitiveScore);
+            if (level >= 0) {
+              // we can skip more docs
+              int newUpTo = impacts.getDocIdUpTo(level);
+              if (newUpTo == NO_MORE_DOCS) {
+                return NO_MORE_DOCS;
+              }
+              target = newUpTo + 1;
+              impactsEnum.advanceShallow(target);
+              impacts = impactsEnum.getImpacts();
+            } else {
+              target = upTo + 1;
+            }
+            upTo = impacts.getDocIdUpTo(0);
+            maxScore = maxScoreCache.getMaxScoreForLevel(0);
           }
         }
 
@@ -105,7 +123,8 @@ final class TermScorer extends Scorer {
       };
     } else {
       postingsEnum = te.postings(null, scoreMode.needsScores() ? PostingsEnum.FREQS : PostingsEnum.NONE);
-      impactsEnum = new SlowImpactsEnum(postingsEnum, docScorer.getSimScorer().score(Float.MAX_VALUE, 1));
+      impactsEnum = new SlowImpactsEnum(postingsEnum);
+      maxScoreCache = new MaxScoreCache(impactsEnum, docScorer.getSimScorer());
       iterator = postingsEnum;
     }
   }
@@ -132,12 +151,12 @@ final class TermScorer extends Scorer {
 
   @Override
   public int advanceShallow(int target) throws IOException {
-    return impactsEnum.advanceShallow(target);
+    return maxScoreCache.advanceShallow(target);
   }
 
   @Override
   public float getMaxScore(int upTo) throws IOException {
-    return impactsEnum.getMaxScore(upTo);
+    return maxScoreCache.getMaxScore(upTo);
   }
 
   @Override
@@ -148,4 +167,5 @@ final class TermScorer extends Scorer {
   /** Returns a string representation of this <code>TermScorer</code>. */
   @Override
   public String toString() { return "scorer(" + weight + ")[" + super.toString() + "]"; }
+
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java b/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java
index f7a88f1..82b8044 100644
--- a/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java
@@ -139,6 +139,7 @@ final class WANDScorer extends Scorer {
 
     OptionalInt scalingFactor = OptionalInt.empty();
     for (Scorer scorer : scorers) {
+      scorer.advanceShallow(0);
       float maxScore = scorer.getMaxScore(DocIdSetIterator.NO_MORE_DOCS);
       if (maxScore != 0 && Float.isFinite(maxScore)) {
         // 0 and +Infty should not impact the scale

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/test/org/apache/lucene/codecs/TestCompetitiveFreqNormAccumulator.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/codecs/TestCompetitiveFreqNormAccumulator.java b/lucene/core/src/test/org/apache/lucene/codecs/TestCompetitiveFreqNormAccumulator.java
index 5743e64..f4d3e69 100644
--- a/lucene/core/src/test/org/apache/lucene/codecs/TestCompetitiveFreqNormAccumulator.java
+++ b/lucene/core/src/test/org/apache/lucene/codecs/TestCompetitiveFreqNormAccumulator.java
@@ -20,85 +20,85 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.apache.lucene.codecs.CompetitiveFreqNormAccumulator.FreqAndNorm;
+import org.apache.lucene.index.Impact;
 import org.apache.lucene.util.LuceneTestCase;
 
 public class TestCompetitiveFreqNormAccumulator extends LuceneTestCase {
 
   public void testBasics() {
-    CompetitiveFreqNormAccumulator acc = new CompetitiveFreqNormAccumulator();
-    Set<FreqAndNorm> expected = new HashSet<>();
+    CompetitiveImpactAccumulator acc = new CompetitiveImpactAccumulator();
+    Set<Impact> expected = new HashSet<>();
 
     acc.add(3, 5);
-    expected.add(new FreqAndNorm(3, 5));
+    expected.add(new Impact(3, 5));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(6, 11);
-    expected.add(new FreqAndNorm(6, 11));
+    expected.add(new Impact(6, 11));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(10, 13);
-    expected.add(new FreqAndNorm(10, 13));
+    expected.add(new Impact(10, 13));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
     
     acc.add(1, 2);
-    expected.add(new FreqAndNorm(1, 2));
+    expected.add(new Impact(1, 2));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(7, 9);
-    expected.remove(new FreqAndNorm(6, 11));
-    expected.add(new FreqAndNorm(7, 9));
+    expected.remove(new Impact(6, 11));
+    expected.add(new Impact(7, 9));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(8, 2);
     expected.clear();
-    expected.add(new FreqAndNorm(10, 13));
-    expected.add(new FreqAndNorm(8, 2));
+    expected.add(new Impact(10, 13));
+    expected.add(new Impact(8, 2));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
   }
 
   public void testExtremeNorms() {
-    CompetitiveFreqNormAccumulator acc = new CompetitiveFreqNormAccumulator();
-    Set<FreqAndNorm> expected = new HashSet<>();
+    CompetitiveImpactAccumulator acc = new CompetitiveImpactAccumulator();
+    Set<Impact> expected = new HashSet<>();
 
     acc.add(3, 5);
-    expected.add(new FreqAndNorm(3, 5));
+    expected.add(new Impact(3, 5));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(10, 10000);
-    expected.add(new FreqAndNorm(10, 10000));
+    expected.add(new Impact(10, 10000));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(5, 200);
-    expected.add(new FreqAndNorm(5, 200));
+    expected.add(new Impact(5, 200));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(20, -100);
-    expected.add(new FreqAndNorm(20, -100));
+    expected.add(new Impact(20, -100));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
 
     acc.add(30, -3);
-    expected.add(new FreqAndNorm(30, -3));
+    expected.add(new Impact(30, -3));
     assertEquals(expected, acc.getCompetitiveFreqNormPairs());
   }
 
   public void testOmitFreqs() {
-    CompetitiveFreqNormAccumulator acc = new CompetitiveFreqNormAccumulator();
+    CompetitiveImpactAccumulator acc = new CompetitiveImpactAccumulator();
 
     acc.add(1, 5);
     acc.add(1, 7);
     acc.add(1, 4);
 
-    assertEquals(Collections.singleton(new FreqAndNorm(1, 4)), acc.getCompetitiveFreqNormPairs());
+    assertEquals(Collections.singleton(new Impact(1, 4)), acc.getCompetitiveFreqNormPairs());
   }
 
   public void testOmitNorms() {
-    CompetitiveFreqNormAccumulator acc = new CompetitiveFreqNormAccumulator();
+    CompetitiveImpactAccumulator acc = new CompetitiveImpactAccumulator();
 
     acc.add(5, 1);
     acc.add(7, 1);
     acc.add(4, 1);
 
-    assertEquals(Collections.singleton(new FreqAndNorm(7, 1)), acc.getCompetitiveFreqNormPairs());
+    assertEquals(Collections.singleton(new Impact(7, 1)), acc.getCompetitiveFreqNormPairs());
   }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/test/org/apache/lucene/codecs/lucene50/TestBlockPostingsFormat.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/codecs/lucene50/TestBlockPostingsFormat.java b/lucene/core/src/test/org/apache/lucene/codecs/lucene50/TestBlockPostingsFormat.java
index d507b7b..dec5eca 100644
--- a/lucene/core/src/test/org/apache/lucene/codecs/lucene50/TestBlockPostingsFormat.java
+++ b/lucene/core/src/test/org/apache/lucene/codecs/lucene50/TestBlockPostingsFormat.java
@@ -18,19 +18,23 @@ package org.apache.lucene.codecs.lucene50;
 
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.lucene.analysis.MockAnalyzer;
 import org.apache.lucene.codecs.Codec;
-import org.apache.lucene.codecs.CompetitiveFreqNormAccumulator;
+import org.apache.lucene.codecs.CompetitiveImpactAccumulator;
 import org.apache.lucene.codecs.blocktree.FieldReader;
 import org.apache.lucene.codecs.blocktree.Stats;
+import org.apache.lucene.codecs.lucene50.Lucene50ScoreSkipReader.MutableImpactList;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.index.BasePostingsFormatTestCase;
 import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.Impact;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.ByteArrayDataInput;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.IOContext;
@@ -89,33 +93,43 @@ public class TestBlockPostingsFormat extends BasePostingsFormatTestCase {
 
   public void testImpactSerialization() throws IOException {
     // omit norms and omit freqs
-    doTestImpactSerialization(new int[] { 1 }, new long[] { 1L });
+    doTestImpactSerialization(Collections.singletonList(new Impact(1, 1L)));
 
     // omit freqs
-    doTestImpactSerialization(new int[] { 1 }, new long[] { 42L });
+    doTestImpactSerialization(Collections.singletonList(new Impact(1, 42L)));
     // omit freqs with very large norms
-    doTestImpactSerialization(new int[] { 1 }, new long[] { -100L });
+    doTestImpactSerialization(Collections.singletonList(new Impact(1, -100L)));
 
     // omit norms
-    doTestImpactSerialization(new int[] { 30 }, new long[] { 1L });
+    doTestImpactSerialization(Collections.singletonList(new Impact(30, 1L)));
     // omit norms with large freq
-    doTestImpactSerialization(new int[] { 500 }, new long[] { 1L });
+    doTestImpactSerialization(Collections.singletonList(new Impact(500, 1L)));
 
     // freqs and norms, basic
     doTestImpactSerialization(
-        new int[] { 1, 3, 7, 15, 20, 28 },
-        new long[] { 7L, 9L, 10L, 11L, 13L, 14L });
+        Arrays.asList(
+            new Impact(1, 7L),
+            new Impact(3, 9L),
+            new Impact(7, 10L),
+            new Impact(15, 11L),
+            new Impact(20, 13L),
+            new Impact(28, 14L)));
 
     // freqs and norms, high values
     doTestImpactSerialization(
-        new int[] { 2, 10, 12, 50, 1000, 1005 },
-        new long[] { 2L, 10L, 50L, -100L, -80L, -3L });
+        Arrays.asList(
+            new Impact(2, 2L),
+            new Impact(10, 10L),
+            new Impact(12, 50L),
+            new Impact(50, -100L),
+            new Impact(1000, -80L),
+            new Impact(1005, -3L)));
   }
 
-  private void doTestImpactSerialization(int[] freqs, long[] norms) throws IOException {
-    CompetitiveFreqNormAccumulator acc = new CompetitiveFreqNormAccumulator();
-    for (int i = 0; i < freqs.length; ++i) {
-      acc.add(freqs[i], norms[i]);
+  private void doTestImpactSerialization(List<Impact> impacts) throws IOException {
+    CompetitiveImpactAccumulator acc = new CompetitiveImpactAccumulator();
+    for (Impact impact : impacts) {
+      acc.add(impact.freq, impact.norm);
     }
     try(Directory dir = newDirectory()) {
       try (IndexOutput out = dir.createOutput("foo", IOContext.DEFAULT)) {
@@ -124,17 +138,8 @@ public class TestBlockPostingsFormat extends BasePostingsFormatTestCase {
       try (IndexInput in = dir.openInput("foo", IOContext.DEFAULT)) {
         byte[] b = new byte[Math.toIntExact(in.length())];
         in.readBytes(b, 0, b.length);
-        Lucene50ScoreSkipReader.readImpacts(new ByteArrayDataInput(b), new SimScorer("") {
-          int i = 0;
-
-          @Override
-          public float score(float freq, long norm) {
-            assert freq == freqs[i];
-            assert norm == norms[i];
-            i++;
-            return 0;
-          }
-        });
+        List<Impact> impacts2 = Lucene50ScoreSkipReader.readImpacts(new ByteArrayDataInput(b), new MutableImpactList());
+        assertEquals(impacts, impacts2);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/core/src/test/org/apache/lucene/index/TestCodecs.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestCodecs.java b/lucene/core/src/test/org/apache/lucene/index/TestCodecs.java
index efe4587..acc6506 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestCodecs.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestCodecs.java
@@ -34,7 +34,6 @@ import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field.Store;
 import org.apache.lucene.document.StringField;
 import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.IOUtils;
@@ -680,7 +679,7 @@ public class TestCodecs extends LuceneTestCase {
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+    public ImpactsEnum impacts(int flags) throws IOException {
       throw new UnsupportedOperationException();
     }
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java
----------------------------------------------------------------------
diff --git a/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java b/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java
index 16cc961..ff248c3 100644
--- a/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java
+++ b/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java
@@ -42,7 +42,6 @@ import org.apache.lucene.search.ScoreMode;
 import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.SimpleCollector;
 import org.apache.lucene.search.similarities.Similarity;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.RAMDirectory;
 import org.apache.lucene.util.ArrayUtil;
 import org.apache.lucene.util.Bits;
@@ -1429,8 +1428,8 @@ public class MemoryIndex {
       }
 
       @Override
-      public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
-        return new SlowImpactsEnum(postings(null, flags), scorer.score(Float.MAX_VALUE, 1L));
+      public ImpactsEnum impacts(int flags) throws IOException {
+        return new SlowImpactsEnum(postings(null, flags));
       }
 
       @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionPostingsReader.java
----------------------------------------------------------------------
diff --git a/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionPostingsReader.java b/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionPostingsReader.java
index 4203e07..e7f4c4c 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionPostingsReader.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionPostingsReader.java
@@ -21,11 +21,10 @@ import java.io.IOException;
 import org.apache.lucene.codecs.BlockTermState;
 import org.apache.lucene.codecs.CodecUtil;
 import org.apache.lucene.codecs.PostingsReaderBase;
-import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.FieldInfo;
 import org.apache.lucene.index.ImpactsEnum;
+import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.SegmentReadState;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.DataInput;
 import org.apache.lucene.store.IndexInput;
 
@@ -90,7 +89,7 @@ final class IDVersionPostingsReader extends PostingsReaderBase {
   }
 
   @Override
-  public ImpactsEnum impacts(FieldInfo fieldInfo, BlockTermState state, SimScorer scorer, int flags) throws IOException {
+  public ImpactsEnum impacts(FieldInfo fieldInfo, BlockTermState state, int flags) throws IOException {
     throw new UnsupportedOperationException("Should never be called, IDVersionSegmentTermsEnum implements impacts directly");
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionSegmentTermsEnum.java
----------------------------------------------------------------------
diff --git a/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionSegmentTermsEnum.java b/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionSegmentTermsEnum.java
index d5f51e0..b5e96ee 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionSegmentTermsEnum.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/codecs/idversion/IDVersionSegmentTermsEnum.java
@@ -25,7 +25,6 @@ import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.SlowImpactsEnum;
 import org.apache.lucene.index.TermState;
 import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.ByteArrayDataInput;
 import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.util.ArrayUtil;
@@ -1009,10 +1008,10 @@ public final class IDVersionSegmentTermsEnum extends TermsEnum {
   }
 
   @Override
-  public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+  public ImpactsEnum impacts(int flags) throws IOException {
     // Only one posting, the slow impl is fine
     // We could make this throw UOE but then CheckIndex is angry
-    return new SlowImpactsEnum(postings(null, flags), scorer.score(Float.MAX_VALUE, 1));
+    return new SlowImpactsEnum(postings(null, flags));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/test-framework/src/java/org/apache/lucene/codecs/ramonly/RAMOnlyPostingsFormat.java
----------------------------------------------------------------------
diff --git a/lucene/test-framework/src/java/org/apache/lucene/codecs/ramonly/RAMOnlyPostingsFormat.java b/lucene/test-framework/src/java/org/apache/lucene/codecs/ramonly/RAMOnlyPostingsFormat.java
index 37c078f..8a2b042 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/codecs/ramonly/RAMOnlyPostingsFormat.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/codecs/ramonly/RAMOnlyPostingsFormat.java
@@ -45,7 +45,6 @@ import org.apache.lucene.index.SegmentWriteState;
 import org.apache.lucene.index.SlowImpactsEnum;
 import org.apache.lucene.index.Terms;
 import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.store.IndexOutput;
 import org.apache.lucene.util.Accountable;
@@ -477,8 +476,8 @@ public final class RAMOnlyPostingsFormat extends PostingsFormat {
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
-      return new SlowImpactsEnum(postings(null, PostingsEnum.FREQS), scorer.score(Float.MAX_VALUE, 1));
+    public ImpactsEnum impacts(int flags) throws IOException {
+      return new SlowImpactsEnum(postings(null, PostingsEnum.FREQS));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/test-framework/src/java/org/apache/lucene/index/AssertingLeafReader.java
----------------------------------------------------------------------
diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/AssertingLeafReader.java b/lucene/test-framework/src/java/org/apache/lucene/index/AssertingLeafReader.java
index dfec1db..46beacb 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/index/AssertingLeafReader.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/index/AssertingLeafReader.java
@@ -18,12 +18,12 @@ package org.apache.lucene.index;
 
 import java.io.IOException;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Objects;
 
 import org.apache.lucene.index.PointValues.IntersectVisitor;
 import org.apache.lucene.index.PointValues.Relation;
 import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.StringHelper;
@@ -211,12 +211,12 @@ public class AssertingLeafReader extends FilterLeafReader {
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+    public ImpactsEnum impacts(int flags) throws IOException {
       assertThread("Terms enums", creationThread);
       assert state == State.POSITIONED: "docs(...) called on unpositioned TermsEnum";
       assert (flags & PostingsEnum.FREQS) != 0 : "Freqs should be requested on impacts";
 
-      return new AssertingImpactsEnum(super.impacts(scorer, flags));
+      return new AssertingImpactsEnum(super.impacts(flags));
     }
 
     // TODO: we should separately track if we are 'at the end' ?
@@ -454,7 +454,7 @@ public class AssertingLeafReader extends FilterLeafReader {
 
     private final AssertingPostingsEnum assertingPostings;
     private final ImpactsEnum in;
-    private int lastShallowTarget;
+    private int lastShallowTarget = -1;
 
     AssertingImpactsEnum(ImpactsEnum impacts) {
       in = impacts;
@@ -463,20 +463,19 @@ public class AssertingLeafReader extends FilterLeafReader {
     }
 
     @Override
-    public int advanceShallow(int target) throws IOException {
+    public void advanceShallow(int target) throws IOException {
       assert target >= lastShallowTarget : "called on decreasing targets: target = " + target + " < last target = " + lastShallowTarget;
       assert target >= docID() : "target = " + target + " < docID = " + docID();
-      int upTo = in.advanceShallow(target);
-      assert upTo >= target : "upTo = " + upTo + " < target = " + target;
       lastShallowTarget = target;
-      return upTo;
+      in.advanceShallow(target);
     }
 
     @Override
-    public float getMaxScore(int upTo) throws IOException {
-      assert upTo >= lastShallowTarget : "uTo = " + upTo + " < last shallow target = " + lastShallowTarget;
-      float maxScore = in.getMaxScore(upTo);
-      return maxScore;
+    public Impacts getImpacts() throws IOException {
+      assert docID() >= 0 || lastShallowTarget >= 0 : "Cannot get impacts until the iterator is positioned or advanceShallow has been called";
+      Impacts impacts = in.getImpacts();
+      CheckIndex.checkImpacts(impacts, Math.max(docID(), lastShallowTarget));
+      return new AssertingImpacts(impacts, this);
     }
 
     @Override
@@ -527,6 +526,38 @@ public class AssertingLeafReader extends FilterLeafReader {
     }
   }
 
+  static class AssertingImpacts extends Impacts {
+
+    private final Impacts in;
+    private final AssertingImpactsEnum impactsEnum;
+    private final int validFor;
+
+    AssertingImpacts(Impacts in, AssertingImpactsEnum impactsEnum) {
+      this.in = in;
+      this.impactsEnum = impactsEnum;
+      validFor = Math.max(impactsEnum.docID(), impactsEnum.lastShallowTarget);
+    }
+
+    @Override
+    public int numLevels() {
+      assert validFor == Math.max(impactsEnum.docID(), impactsEnum.lastShallowTarget) : "Cannot reuse impacts after advancing the iterator";
+      return in.numLevels();
+    }
+
+    @Override
+    public int getDocIdUpTo(int level) {
+      assert validFor == Math.max(impactsEnum.docID(), impactsEnum.lastShallowTarget) : "Cannot reuse impacts after advancing the iterator";
+      return in.getDocIdUpTo(level);
+    }
+
+    @Override
+    public List<Impact> getImpacts(int level) {
+      assert validFor == Math.max(impactsEnum.docID(), impactsEnum.lastShallowTarget) : "Cannot reuse impacts after advancing the iterator";
+      return in.getImpacts(level);
+    }
+
+  }
+
   /** Wraps a NumericDocValues but with additional asserts */
   public static class AssertingNumericDocValues extends NumericDocValues {
     private final Thread creationThread = Thread.currentThread();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/test-framework/src/java/org/apache/lucene/index/RandomPostingsTester.java
----------------------------------------------------------------------
diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/RandomPostingsTester.java b/lucene/test-framework/src/java/org/apache/lucene/index/RandomPostingsTester.java
index 278f4b2..29962e6 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/index/RandomPostingsTester.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/index/RandomPostingsTester.java
@@ -16,11 +16,18 @@
  */
 package org.apache.lucene.index;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -33,13 +40,13 @@ import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.function.IntToLongFunction;
+import java.util.stream.Collectors;
 
 import org.apache.lucene.codecs.Codec;
 import org.apache.lucene.codecs.FieldsConsumer;
 import org.apache.lucene.codecs.FieldsProducer;
 import org.apache.lucene.codecs.NormsProducer;
 import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.FlushInfo;
 import org.apache.lucene.store.IOContext;
@@ -55,12 +62,6 @@ import org.apache.lucene.util.automaton.AutomatonTestUtil;
 import org.apache.lucene.util.automaton.AutomatonTestUtil.RandomAcceptedStrings;
 import org.apache.lucene.util.automaton.CompiledAutomaton;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
 /** Helper class extracted from BasePostingsFormatTestCase to exercise a postings format. */
 public class RandomPostingsTester {
 
@@ -608,7 +609,7 @@ public class RandomPostingsTester {
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
+    public ImpactsEnum impacts(int flags) throws IOException {
       throw new UnsupportedOperationException();
     }
   }
@@ -1055,126 +1056,146 @@ public class RandomPostingsTester {
       } else {
         docToNorm = doc -> 1L;
       }
-      for (int s = 0; s < 3; ++s) {
-        final int scoreMode = s;
-        SimScorer scorer = new SimScorer(field) {
-          @Override
-          public float score(float freq, long norm) {
-            switch (scoreMode) {
-              case 0:
-                return freq; // make sure the postings record the best freq
-              case 1:
-                return 1f / norm; // make sure the postings record the best norm
-              default:
-                return freq - norm + MAX_NORM; // now a combination that could make intermediate pairs more competitive
-            }
-          }
-        };
-
-        // First check max scores and block uptos
-        int max = -1;
-        float maxScore = 0;
-        int flags = PostingsEnum.FREQS;
-        if (doCheckPositions) {
-          flags |= PostingsEnum.POSITIONS;
+
+      // First check impacts and block uptos
+      int max = -1;
+      List<Impact> impactsCopy = null;
+      int flags = PostingsEnum.FREQS;
+      if (doCheckPositions) {
+        flags |= PostingsEnum.POSITIONS;
+        if (doCheckOffsets) {
+          flags |= PostingsEnum.OFFSETS;
+        }
+        if (doCheckPayloads) {
+          flags |= PostingsEnum.PAYLOADS;
+        }
+      }
+
+      ImpactsEnum impactsEnum = termsEnum.impacts(flags);
+      PostingsEnum postings = termsEnum.postings(null, flags);
+      for (int doc = impactsEnum.nextDoc(); ; doc = impactsEnum.nextDoc()) {
+        assertEquals(postings.nextDoc(), doc);
+        if (doc == DocIdSetIterator.NO_MORE_DOCS) {
+          break;
+        }
+        int freq = postings.freq();
+        assertEquals("freq is wrong", freq, impactsEnum.freq());
+        for (int i = 0; i < freq; ++i) {
+          int pos = postings.nextPosition();
+          assertEquals("position is wrong", pos, impactsEnum.nextPosition());
           if (doCheckOffsets) {
-            flags |= PostingsEnum.OFFSETS;
+            assertEquals("startOffset is wrong", postings.startOffset(), impactsEnum.startOffset());
+            assertEquals("endOffset is wrong", postings.endOffset(), impactsEnum.endOffset());
           }
           if (doCheckPayloads) {
-            flags |= PostingsEnum.PAYLOADS;
+            assertEquals("payload is wrong", postings.getPayload(), impactsEnum.getPayload());
           }
         }
+        if (doc > max) {
+          impactsEnum.advanceShallow(doc);
+          Impacts impacts = impactsEnum.getImpacts();
+          CheckIndex.checkImpacts(impacts, doc);
+          impactsCopy = impacts.getImpacts(0)
+              .stream()
+              .map(i -> new Impact(i.freq, i.norm))
+              .collect(Collectors.toList());
+        }
+        freq = impactsEnum.freq();
+        long norm = docToNorm.applyAsLong(doc);
+        int idx = Collections.binarySearch(impactsCopy, new Impact(freq, norm), Comparator.comparing(i -> i.freq));
+        if (idx < 0) {
+          idx = -1 - idx;
+        }
+        assertTrue("Got " + new Impact(freq, norm) + " in postings, but no impact triggers equal or better scores in " + impactsCopy,
+            idx <= impactsCopy.size() && impactsCopy.get(idx).norm <= norm);
+      }
 
-        ImpactsEnum impacts = termsEnum.impacts(scorer, flags);
-        PostingsEnum postings = termsEnum.postings(null, flags);
-        for (int doc = impacts.nextDoc(); ; doc = impacts.nextDoc()) {
-          assertEquals(postings.nextDoc(), doc);
-          if (doc == DocIdSetIterator.NO_MORE_DOCS) {
-            break;
-          }
-          int freq = postings.freq();
-          assertEquals("freq is wrong", freq, impacts.freq());
-          for (int i = 0; i < freq; ++i) {
-            int pos = postings.nextPosition();
-            assertEquals("position is wrong", pos, impacts.nextPosition());
-            if (doCheckOffsets) {
-              assertEquals("startOffset is wrong", postings.startOffset(), impacts.startOffset());
-              assertEquals("endOffset is wrong", postings.endOffset(), impacts.endOffset());
-            }
-            if (doCheckPayloads) {
-              assertEquals("payload is wrong", postings.getPayload(), impacts.getPayload());
+      // Now check advancing
+      impactsEnum = termsEnum.impacts(flags);
+      postings = termsEnum.postings(postings, flags);
+
+      max = -1;
+      while (true) {
+        int doc = impactsEnum.docID();
+        boolean advance;
+        int target;
+        if (random.nextBoolean()) {
+          advance = false;
+          target = doc + 1;
+        } else {
+          advance = true;
+          int delta = Math.min(1 + random.nextInt(512), DocIdSetIterator.NO_MORE_DOCS - doc);
+          target = impactsEnum.docID() + delta;
+        }
+
+        if (target > max && random.nextBoolean()) {
+          int delta = Math.min(random.nextInt(512), DocIdSetIterator.NO_MORE_DOCS - target);
+          max = target + delta;
+          
+          impactsEnum.advanceShallow(target);
+          Impacts impacts = impactsEnum.getImpacts();
+          CheckIndex.checkImpacts(impacts, target);
+          impactsCopy = Collections.singletonList(new Impact(Integer.MAX_VALUE, 1L));
+          for (int level = 0; level < impacts.numLevels(); ++level) {
+            if (impacts.getDocIdUpTo(level) >= max) {
+              impactsCopy = impacts.getImpacts(level)
+                  .stream()
+                  .map(i -> new Impact(i.freq, i.norm))
+                  .collect(Collectors.toList());
+              break;
             }
           }
-          if (doc > max) {
-            max = impacts.advanceShallow(doc);
-            assertTrue(max >= doc);
-            maxScore = impacts.getMaxScore(max);
-          }
-          assertEquals(max, impacts.advanceShallow(doc));
-          assertTrue(scorer.score(impacts.freq(), docToNorm.applyAsLong(doc)) <= maxScore);
         }
 
-        // Now check advancing
-        impacts = termsEnum.impacts(scorer, flags);
-        postings = termsEnum.postings(postings, flags);
-
-        max = -1;
-        while (true) {
-          int doc = impacts.docID();
-          boolean advance;
-          int target;
-          if (random.nextBoolean()) {
-            advance = false;
-            target = doc + 1;
-          } else {
-            advance = true;
-            int delta = Math.min(1 + random.nextInt(512), DocIdSetIterator.NO_MORE_DOCS - doc);
-            target = impacts.docID() + delta;
-          }
+        if (advance) {
+          doc = impactsEnum.advance(target);
+        } else {
+          doc = impactsEnum.nextDoc();
+        }
 
-          if (target > max && random.nextBoolean()) {
-            int delta = Math.min(random.nextInt(512), DocIdSetIterator.NO_MORE_DOCS - target);
-            max = target + delta;
-            int m = impacts.advanceShallow(target);
-            assertTrue(m >= target);
-            maxScore = impacts.getMaxScore(max);
+        assertEquals(postings.advance(target), doc);
+        if (doc == DocIdSetIterator.NO_MORE_DOCS) {
+          break;
+        }
+        int freq = postings.freq();
+        assertEquals("freq is wrong", freq, impactsEnum.freq());
+        for (int i = 0; i < postings.freq(); ++i) {
+          int pos = postings.nextPosition();
+          assertEquals("position is wrong", pos, impactsEnum.nextPosition());
+          if (doCheckOffsets) {
+            assertEquals("startOffset is wrong", postings.startOffset(), impactsEnum.startOffset());
+            assertEquals("endOffset is wrong", postings.endOffset(), impactsEnum.endOffset());
           }
-
-          if (advance) {
-            doc = impacts.advance(target);
-          } else {
-            doc = impacts.nextDoc();
+          if (doCheckPayloads) {
+            assertEquals("payload is wrong", postings.getPayload(), impactsEnum.getPayload());
           }
+        }
 
-          assertEquals(postings.advance(target), doc);
-          if (doc == DocIdSetIterator.NO_MORE_DOCS) {
-            break;
-          }
-          int freq = postings.freq();
-          assertEquals("freq is wrong", freq, impacts.freq());
-          for (int i = 0; i < postings.freq(); ++i) {
-            int pos = postings.nextPosition();
-            assertEquals("position is wrong", pos, impacts.nextPosition());
-            if (doCheckOffsets) {
-              assertEquals("startOffset is wrong", postings.startOffset(), impacts.startOffset());
-              assertEquals("endOffset is wrong", postings.endOffset(), impacts.endOffset());
-            }
-            if (doCheckPayloads) {
-              assertEquals("payload is wrong", postings.getPayload(), impacts.getPayload());
+        if (doc > max) {
+          int delta = Math.min(1 + random.nextInt(512), DocIdSetIterator.NO_MORE_DOCS - doc);
+          max = doc + delta;
+          Impacts impacts = impactsEnum.getImpacts();
+          CheckIndex.checkImpacts(impacts, doc);
+          impactsCopy = Collections.singletonList(new Impact(Integer.MAX_VALUE, 1L));
+          for (int level = 0; level < impacts.numLevels(); ++level) {
+            if (impacts.getDocIdUpTo(level) >= max) {
+              impactsCopy = impacts.getImpacts(level)
+                  .stream()
+                  .map(i -> new Impact(i.freq, i.norm))
+                  .collect(Collectors.toList());
+              break;
             }
           }
+        }
 
-          if (doc > max) {
-            int delta = Math.min(1 + random.nextInt(512), DocIdSetIterator.NO_MORE_DOCS - doc);
-            max = doc + delta;
-            int m = impacts.advanceShallow(doc);
-            assertTrue(m >= doc);
-            maxScore = impacts.getMaxScore(max);
-          }
-
-          float score = scorer.score(impacts.freq(), docToNorm.applyAsLong(doc));
-          assertTrue(score <= maxScore);
+        freq = impactsEnum.freq();
+        long norm = docToNorm.applyAsLong(doc);
+        int idx = Collections.binarySearch(impactsCopy, new Impact(freq, norm), Comparator.comparing(i -> i.freq));
+        if (idx < 0) {
+          idx = -1 - idx;
         }
+        assertTrue("Got " + new Impact(freq, norm) + " in postings, but no impact triggers equal or better scores in " + impactsCopy,
+            idx <= impactsCopy.size() && impactsCopy.get(idx).norm <= norm);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java
----------------------------------------------------------------------
diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java
index 80cd4da..00aee41 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java
@@ -88,6 +88,7 @@ public class AssertingScorer extends Scorer {
   @Override
   public float getMaxScore(int upTo) throws IOException {
     assert upTo >= lastShallowTarget : "uTo = " + upTo + " < last target = " + lastShallowTarget;
+    assert docID() >= 0 || lastShallowTarget >= 0 : "Cannot get max scores until the iterator is positioned or advanceShallow has been called";
     float maxScore = in.getMaxScore(upTo);
     return maxScore;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java
----------------------------------------------------------------------
diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java b/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java
index a918078..784d3bb 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java
@@ -632,7 +632,7 @@ public class CheckHits {
           Assert.assertTrue(twoPhase1 == null || twoPhase1.matches());
           float score = s2.score();
           Assert.assertEquals(s1.score(), score);
-          Assert.assertTrue(score <= maxScore);
+          Assert.assertTrue(score + " > " + maxScore + " up to " + upTo, score <= maxScore);
 
           if (score >= minScore && random.nextInt(10) == 0) {
             // On some scorers, changing the min score changes the way that docs are iterated

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java b/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java
index 1b81c7f..53cddc3 100644
--- a/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java
+++ b/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java
@@ -43,7 +43,6 @@ import org.apache.lucene.search.ScoreMode;
 import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.Weight;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.AttributeSource;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.DocIdSetBuilder;
@@ -241,8 +240,8 @@ public final class SolrRangeQuery extends ExtendedQueryBase implements DocSetPro
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
-      return te.impacts(scorer, flags);
+    public ImpactsEnum impacts(int flags) throws IOException {
+      return te.impacts(flags);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/af680af7/solr/core/src/java/org/apache/solr/uninverting/DocTermOrds.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/uninverting/DocTermOrds.java b/solr/core/src/java/org/apache/solr/uninverting/DocTermOrds.java
index daaf00d..580a971 100644
--- a/solr/core/src/java/org/apache/solr/uninverting/DocTermOrds.java
+++ b/solr/core/src/java/org/apache/solr/uninverting/DocTermOrds.java
@@ -35,7 +35,6 @@ import org.apache.lucene.index.SortedSetDocValues;
 import org.apache.lucene.index.Terms;
 import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.similarities.Similarity.SimScorer;
 import org.apache.lucene.util.Accountable;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
@@ -609,8 +608,8 @@ public class DocTermOrds implements Accountable {
     }
 
     @Override
-    public ImpactsEnum impacts(SimScorer scorer, int flags) throws IOException {
-      return termsEnum.impacts(scorer, flags);
+    public ImpactsEnum impacts(int flags) throws IOException {
+      return termsEnum.impacts(flags);
     }
 
     @Override


Mime
View raw message