Index: src/java/org/apache/lucene/search/DefaultSimilarity.java
===================================================================
--- src/java/org/apache/lucene/search/DefaultSimilarity.java	(revision 813416)
+++ src/java/org/apache/lucene/search/DefaultSimilarity.java	(working copy)
@@ -44,11 +44,6 @@
   public float lengthNorm(String fieldName, int numTerms) {
     return (float)(1.0 / Math.sqrt(numTerms));
   }
-  
-  /** Implemented as <code>1/sqrt(sumOfSquaredWeights)</code>. */
-  public float queryNorm(float sumOfSquaredWeights) {
-    return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
-  }
 
   /** Implemented as <code>sqrt(freq)</code>. */
   public float tf(float freq) {
Index: src/java/org/apache/lucene/search/Query.java
===================================================================
--- src/java/org/apache/lucene/search/Query.java	(revision 813416)
+++ src/java/org/apache/lucene/search/Query.java	(working copy)
@@ -97,8 +97,7 @@
   public Weight weight(Searcher searcher) throws IOException {
     Query query = searcher.rewrite(this);
     Weight weight = query.createWeight(searcher);
-    float sum = weight.sumOfSquaredWeights();
-    float norm = getSimilarity(searcher).queryNorm(sum);
+    float norm = getSimilarity(searcher).queryNorm(weight);
     weight.normalize(norm);
     return weight;
   }
Index: src/java/org/apache/lucene/search/Similarity.java
===================================================================
--- src/java/org/apache/lucene/search/Similarity.java	(revision 813416)
+++ src/java/org/apache/lucene/search/Similarity.java	(working copy)
@@ -397,8 +397,48 @@
    *
    * @param sumOfSquaredWeights the sum of the squares of query term weights
    * @return a normalization factor for query weights
+   * @deprecated use {@link #queryNorm(Weight)}
+   */
+  public float queryNorm(float sumOfSquaredWeights) {
+    return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
+  }
+  
+
+  /** Computes the normalization value for a query given the Weight.  This 
+   * value is multiplied into the weight of each query term. While the classic 
+   * query normalization factor is computed as 1/sqrt(sumOfSquaredWeights), 
+   * other implementations might completely ignore sumOfSquaredWeights (ie return 1).
+   *
+   * <p>This does not affect ranking, but the default implementation does make scores
+   * from different queries more comparable than they would be by eliminating the
+   * magnitude of the Query vector as a factor in the score.
+   *
+   * @param weight the Query Weight
+   * @return a normalization factor for query weights
+   * @throws IOException 
+   * @throws IOException 
    */
-  public abstract float queryNorm(float sumOfSquaredWeights);
+  public float queryNorm(Weight weight) throws IOException {
+    if (supportedMethods.overridesQueryNorm) {
+      float sum;
+
+      sum = weight.sumOfSquaredWeights();
+
+      return queryNorm(sum);
+    } else {
+      // Implemented as <code>1/sqrt(sumOfSquaredWeights)</code>.
+      float sum;
+      try {
+        sum = weight.sumOfSquaredWeights();
+      } catch (IOException e) {
+        // this should not need to throw an IOException,
+        // but if it does, we will convert to runtime
+        throw new RuntimeException();
+      }
+      return (float) (1.0 / Math.sqrt(sum));
+    }
+  }
+  
 
   /** Encodes a normalization factor for storage in an index.
    *
@@ -694,11 +734,12 @@
   
     /** @deprecated Remove this when old API is removed! */
   private static final class MethodSupport implements Serializable {
-    final boolean overridesCollectionIDF, overridesTermIDF;
+    final boolean overridesCollectionIDF, overridesTermIDF, overridesQueryNorm;
 
     MethodSupport(Class clazz) {
       overridesCollectionIDF = isMethodOverridden(clazz, "idf", C_IDF_METHOD_PARAMS);
       overridesTermIDF = isMethodOverridden(clazz, "idf", T_IDF_METHOD_PARAMS);
+      overridesQueryNorm = isMethodOverridden(clazz, "queryNorm", QN_METHOD_PARAMS);
     }
     
     private static boolean isMethodOverridden(Class clazz, String name, Class[] params) {
@@ -714,6 +755,10 @@
     
     /** @deprecated Remove this when old API is removed! */
     private static final Class[] C_IDF_METHOD_PARAMS = new Class[]{Collection.class, Searcher.class};
+    
+    /** @deprecated Remove this when old API is removed! */
+    private static final Class[] QN_METHOD_PARAMS = new Class[]{float.class};
+    
   }
   
   /** @deprecated Remove this when old API is removed! */
Index: src/java/org/apache/lucene/search/SimilarityDelegator.java
===================================================================
--- src/java/org/apache/lucene/search/SimilarityDelegator.java	(revision 813416)
+++ src/java/org/apache/lucene/search/SimilarityDelegator.java	(working copy)
@@ -1,5 +1,7 @@
 package org.apache.lucene.search;
 
+import java.io.IOException;
+
 import org.apache.lucene.index.FieldInvertState;
 
 /**
@@ -45,6 +47,10 @@
   public float queryNorm(float sumOfSquaredWeights) {
     return delegee.queryNorm(sumOfSquaredWeights);
   }
+  
+  public float queryNorm(Weight weight) throws IOException {
+    return delegee.queryNorm(weight);
+  }
 
   public float tf(float freq) {
     return delegee.tf(freq);
Index: src/test/org/apache/lucene/search/JustCompileSearch.java
===================================================================
--- src/test/org/apache/lucene/search/JustCompileSearch.java	(revision 813416)
+++ src/test/org/apache/lucene/search/JustCompileSearch.java	(working copy)
@@ -375,8 +375,8 @@
     public float lengthNorm(String fieldName, int numTokens) {
       throw new UnsupportedOperationException(UNSUPPORTED_MSG);
     }
-
-    public float queryNorm(float sumOfSquaredWeights) {
+    
+    public float queryNorm(Weight weight) {
       throw new UnsupportedOperationException(UNSUPPORTED_MSG);
     }
 
@@ -446,7 +446,7 @@
       throw new UnsupportedOperationException(UNSUPPORTED_MSG);
     }
 
-    public float sumOfSquaredWeights() throws IOException {
+    public float sumOfSquaredWeights() {
       throw new UnsupportedOperationException(UNSUPPORTED_MSG);
     }
 
Index: src/test/org/apache/lucene/search/TestSimilarity.java
===================================================================
--- src/test/org/apache/lucene/search/TestSimilarity.java	(revision 813416)
+++ src/test/org/apache/lucene/search/TestSimilarity.java	(working copy)
@@ -48,6 +48,7 @@
     public float idf(Collection terms, Searcher searcher) { return 1.0f; }
     public float idf(int docFreq, int numDocs) { return 1.0f; }
     public float coord(int overlap, int maxOverlap) { return 1.0f; }
+    public float queryNorm(Weight weight) { return 1.0f; }
   }
 
   public void testSimilarity() throws Exception {

