Index: lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadTermQuery.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadTermQuery.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadTermQuery.java	(working copy)
@@ -314,8 +314,8 @@
     //Make everything else 1 so we see the effect of the payload
     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     @Override 
-    public void computeNorm(FieldInvertState state, Norm norm) {
-      norm.setByte(encodeNormValue(state.getBoost()));
+    public float lengthNorm(FieldInvertState state) {
+      return state.getBoost();
     }
 
     @Override
Index: lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadNearQuery.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadNearQuery.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/search/payloads/TestPayloadNearQuery.java	(working copy)
@@ -324,8 +324,8 @@
     //Make everything else 1 so we see the effect of the payload
     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     @Override 
-    public void computeNorm(FieldInvertState state, Norm norm) {
-      norm.setByte(encodeNormValue(state.getBoost()));
+    public float lengthNorm(FieldInvertState state) {
+      return state.getBoost();
     }
 
     @Override 
Index: lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java	(working copy)
@@ -42,7 +42,7 @@
   public static class SimpleSimilarity extends DefaultSimilarity {
     public float queryNorm(float sumOfSquaredWeights) { return 1.0f; }
     public float coord(int overlap, int maxOverlap) { return 1.0f; }
-    @Override public void computeNorm(FieldInvertState state, Norm norm) { norm.setByte(encodeNormValue(state.getBoost())); }
+    @Override public float lengthNorm(FieldInvertState state) { return state.getBoost(); }
     @Override public float tf(float freq) { return freq; }
     @Override public float sloppyFreq(int distance) { return 2.0f; }
     @Override public float idf(long docFreq, long numDocs) { return 1.0f; }
Index: lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java	(working copy)
@@ -115,8 +115,8 @@
     }
 
     @Override
-    public void computeNorm(FieldInvertState state, Norm norm) {
-      norm.setByte(encodeNormValue(1f));
+    public float lengthNorm(FieldInvertState state) {
+      return 1f;
     }
 
     @Override
@@ -151,8 +151,8 @@
     }
     
     @Override
-    public void computeNorm(FieldInvertState state, Norm norm) {
-      norm.setByte(encodeNormValue(10f));
+    public float lengthNorm(FieldInvertState state) {
+      return 10f;
     }
 
     @Override
Index: lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java	(working copy)
@@ -69,9 +69,9 @@
     }
     
     @Override
-    public void computeNorm(FieldInvertState state, Norm norm) {
+    public float lengthNorm(FieldInvertState state) {
       // Disable length norm
-      norm.setByte(encodeNormValue(state.getBoost()));
+      return state.getBoost();
     }
     
     @Override
Index: lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java	(working copy)
@@ -109,8 +109,8 @@
     }
 
     @Override
-    public void computeNorm(FieldInvertState state, Norm norm) {
-      norm.setByte(encodeNormValue((float) state.getMaxTermFrequency()));
+    public float lengthNorm(FieldInvertState state) {
+      return state.getMaxTermFrequency();
     }
   }
 }
Index: lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java	(working copy)
@@ -39,7 +39,7 @@
   public static class SimpleSimilarity extends TFIDFSimilarity {
     public float queryNorm(float sumOfSquaredWeights) { return 1.0f; }
     public float coord(int overlap, int maxOverlap) { return 1.0f; }
-    @Override public void computeNorm(FieldInvertState state, Norm norm) { norm.setByte(encodeNormValue(state.getBoost())); }
+    @Override public float lengthNorm(FieldInvertState state) { return state.getBoost(); }
     @Override public float tf(float freq) { return freq; }
     @Override public float sloppyFreq(int distance) { return 2.0f; }
     @Override public float idf(long docFreq, long numDocs) { return 1.0f; }
Index: lucene/core/src/test/org/apache/lucene/index/TestCustomNorms.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestCustomNorms.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/index/TestCustomNorms.java	(working copy)
@@ -25,9 +25,14 @@
 import org.apache.lucene.document.TextField;
 import org.apache.lucene.index.DocValues.Source;
 import org.apache.lucene.index.DocValues.Type;
+import org.apache.lucene.search.CollectionStatistics;
+import org.apache.lucene.search.TermStatistics;
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper;
 import org.apache.lucene.search.similarities.Similarity;
+import org.apache.lucene.search.similarities.Similarity.ExactSimScorer;
+import org.apache.lucene.search.similarities.Similarity.SimWeight;
+import org.apache.lucene.search.similarities.Similarity.SloppySimScorer;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
@@ -192,16 +197,31 @@
     }
   }
 
-  public static class FloatEncodingBoostSimilarity extends DefaultSimilarity {
+  public static class FloatEncodingBoostSimilarity extends Similarity {
 
     @Override
     public void computeNorm(FieldInvertState state, Norm norm) {
       float boost = state.getBoost();
       norm.setFloat(boost);
     }
+    
+    @Override
+    public SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ExactSimScorer exactSimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SloppySimScorer sloppySimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
   }
 
-  public static class RandomTypeSimilarity extends DefaultSimilarity {
+  public static class RandomTypeSimilarity extends Similarity {
 
     private final Random random;
     
@@ -237,29 +257,50 @@
       }
 
     }
-  }
-  
-  class IllegalCustomEncodingSimilarity extends DefaultSimilarity {
-    
-    public boolean useByte = false;
+
     @Override
-    public byte encodeNormValue(float f) {
-      return (byte) f;
+    public SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {
+      throw new UnsupportedOperationException();
     }
-    
+
     @Override
-    public float decodeNormValue(byte b) {
-      return (float) b;
+    public ExactSimScorer exactSimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
     }
 
     @Override
+    public SloppySimScorer sloppySimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
+  }
+  
+  class IllegalCustomEncodingSimilarity extends Similarity {
+    
+    public boolean useByte = false;
+
+    @Override
     public void computeNorm(FieldInvertState state, Norm norm) {
       if (useByte) {
-        norm.setByte(encodeNormValue((float) state.getLength()));
+        norm.setByte((byte)state.getLength());
       } else {
         norm.setFloat((float)state.getLength());
       }
     }
+
+    @Override
+    public SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ExactSimScorer exactSimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SloppySimScorer sloppySimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
   }
 
 }
Index: lucene/core/src/test/org/apache/lucene/index/TestNorms.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestNorms.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/index/TestNorms.java	(working copy)
@@ -26,6 +26,8 @@
 import org.apache.lucene.document.TextField;
 import org.apache.lucene.index.DocValues.Source;
 import org.apache.lucene.index.DocValues.Type;
+import org.apache.lucene.search.CollectionStatistics;
+import org.apache.lucene.search.TermStatistics;
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper;
 import org.apache.lucene.search.similarities.Similarity;
@@ -57,8 +59,8 @@
     }
 
     @Override
-    public void computeNorm(FieldInvertState state, Norm norm) {
-      norm.setByte(encodeNormValue((float) state.getLength()));
+    public float lengthNorm(FieldInvertState state) {
+      return state.getLength();
     }
   }
   
@@ -232,7 +234,7 @@
   }
 
   
-  public static class ByteEncodingBoostSimilarity extends DefaultSimilarity {
+  public static class ByteEncodingBoostSimilarity extends Similarity {
 
     private boolean writeNorms;
 
@@ -247,5 +249,20 @@
         norm.setByte((byte) (0xFF & boost));
       }
     }
+
+    @Override
+    public SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ExactSimScorer exactSimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SloppySimScorer sloppySimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
   } 
 }
Index: lucene/core/src/test/org/apache/lucene/index/TestUniqueTermCount.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestUniqueTermCount.java	(revision 1406174)
+++ lucene/core/src/test/org/apache/lucene/index/TestUniqueTermCount.java	(working copy)
@@ -17,6 +17,7 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
 
@@ -24,7 +25,10 @@
 import org.apache.lucene.analysis.MockTokenizer;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
+import org.apache.lucene.search.CollectionStatistics;
+import org.apache.lucene.search.TermStatistics;
 import org.apache.lucene.search.similarities.DefaultSimilarity;
+import org.apache.lucene.search.similarities.Similarity;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util._TestUtil;
@@ -91,11 +95,26 @@
   /**
    * Simple similarity that encodes maxTermFrequency directly as a byte
    */
-  class TestSimilarity extends DefaultSimilarity {
+  class TestSimilarity extends Similarity {
 
     @Override
     public void computeNorm(FieldInvertState state, Norm norm) {
       norm.setByte((byte) state.getUniqueTermCount());
     }
+
+    @Override
+    public SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ExactSimScorer exactSimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SloppySimScorer sloppySimScorer(SimWeight weight, AtomicReaderContext context) throws IOException {
+      throw new UnsupportedOperationException();
+    }
   }
 }
Index: lucene/core/src/java/org/apache/lucene/search/similarities/DefaultSimilarity.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/similarities/DefaultSimilarity.java	(revision 1406174)
+++ lucene/core/src/java/org/apache/lucene/search/similarities/DefaultSimilarity.java	(working copy)
@@ -46,13 +46,13 @@
    *
    *  @lucene.experimental */
   @Override
-  public void computeNorm(FieldInvertState state, Norm norm) {
+  public float lengthNorm(FieldInvertState state) {
     final int numTerms;
     if (discountOverlaps)
       numTerms = state.getLength() - state.getNumOverlap();
     else
       numTerms = state.getLength();
-    norm.setByte(encodeNormValue(state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)))));
+   return state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
   }
 
   /** Implemented as <code>sqrt(freq)</code>. */
Index: lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java	(revision 1406174)
+++ lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java	(working copy)
@@ -22,6 +22,8 @@
 
 import org.apache.lucene.index.AtomicReaderContext;
 import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.FieldInvertState;
+import org.apache.lucene.index.Norm;
 import org.apache.lucene.search.CollectionStatistics;
 import org.apache.lucene.search.Explanation;
 import org.apache.lucene.search.IndexSearcher;
@@ -668,6 +670,23 @@
    */
   public abstract float idf(long docFreq, long numDocs);
 
+  /**
+   * Compute an index-time normalization value for this field instance.
+   * <p>
+   * This value will be stored in a single byte lossy representation by 
+   * {@link #encodeNormValue(float)}.
+   * 
+   * @param state statistics of the current field (such as length, boost, etc)
+   * @return an index-time normalization value
+   */
+  public abstract float lengthNorm(FieldInvertState state);
+  
+  @Override
+  public final void computeNorm(FieldInvertState state, Norm norm) {
+    float normValue = lengthNorm(state);
+    norm.setByte(encodeNormValue(normValue));
+  }
+  
   /** Cache of decoded bytes. */
   private static final float[] NORM_TABLE = new float[256];
 
Index: lucene/misc/src/java/org/apache/lucene/misc/SweetSpotSimilarity.java
===================================================================
--- lucene/misc/src/java/org/apache/lucene/misc/SweetSpotSimilarity.java	(revision 1406174)
+++ lucene/misc/src/java/org/apache/lucene/misc/SweetSpotSimilarity.java	(working copy)
@@ -108,7 +108,7 @@
    * discountOverlaps is true by default or true for this
    * specific field. */
   @Override
-  public void computeNorm(FieldInvertState state, Norm norm) {
+  public float lengthNorm(FieldInvertState state) {
     final int numTokens;
 
     if (discountOverlaps)
@@ -116,7 +116,7 @@
     else
       numTokens = state.getLength();
 
-    norm.setByte(encodeNormValue(state.getBoost() * computeLengthNorm(numTokens)));
+    return state.getBoost() * computeLengthNorm(numTokens);
   }
 
   /**
