Index: src/test/org/apache/lucene/index/TestIndexReader.java
===================================================================
--- src/test/org/apache/lucene/index/TestIndexReader.java	(revision 768376)
+++ src/test/org/apache/lucene/index/TestIndexReader.java	(working copy)
@@ -1377,10 +1377,17 @@
         String curField = (String) it1.next();
         byte[] norms1 = index1.norms(curField);
         byte[] norms2 = index2.norms(curField);
-        assertEquals(norms1.length, norms2.length);
-        for (int i = 0; i < norms1.length; i++) {
-          assertEquals("Norm different for doc " + i + " and field '" + curField + "'.", norms1[i], norms2[i]);
-        }      
+        if (norms1 != null && norms2 != null)
+        {
+          assertEquals(norms1.length, norms2.length);
+	        for (int i = 0; i < norms1.length; i++) {
+	          assertEquals("Norm different for doc " + i + " and field '" + curField + "'.", norms1[i], norms2[i]);
+	        }
+        }
+        else
+        {
+          assertSame(norms1, norms2);
+        }
       }
       
       // check deletions
Index: src/test/org/apache/lucene/index/TestSegmentReader.java
===================================================================
--- src/test/org/apache/lucene/index/TestSegmentReader.java	(revision 768376)
+++ src/test/org/apache/lucene/index/TestSegmentReader.java	(working copy)
@@ -173,16 +173,21 @@
         assertEquals(reader.hasNorms(f.name()), !f.getOmitNorms());
         assertEquals(reader.hasNorms(f.name()), !DocHelper.noNorms.containsKey(f.name()));
         if (!reader.hasNorms(f.name())) {
-          // test for fake norms of 1.0
+          // test for fake norms of 1.0 or null depending on the flag
           byte [] norms = reader.norms(f.name());
-          assertEquals(norms.length,reader.maxDoc());
-          for (int j=0; j<reader.maxDoc(); j++) {
-            assertEquals(norms[j], DefaultSimilarity.encodeNorm(1.0f));
+          byte norm1 = DefaultSimilarity.encodeNorm(1.0f);
+          if (reader.getDisableFakeNorms())
+            assertNull(norms);
+          else {
+            assertEquals(norms.length,reader.maxDoc());
+            for (int j=0; j<reader.maxDoc(); j++) {
+              assertEquals(norms[j], norm1);
+            }
           }
           norms = new byte[reader.maxDoc()];
           reader.norms(f.name(),norms, 0);
           for (int j=0; j<reader.maxDoc(); j++) {
-            assertEquals(norms[j], DefaultSimilarity.encodeNorm(1.0f));
+            assertEquals(norms[j], norm1);
           }
         }
       }
Index: src/java/org/apache/lucene/search/spans/SpanScorer.java
===================================================================
--- src/java/org/apache/lucene/search/spans/SpanScorer.java	(revision 768376)
+++ src/java/org/apache/lucene/search/spans/SpanScorer.java	(working copy)
@@ -89,7 +89,7 @@
 
   public float score() throws IOException {
     float raw = getSimilarity().tf(freq) * value; // raw score
-    return raw * Similarity.decodeNorm(norms[doc]); // normalize
+    return norms == null? raw : raw * Similarity.decodeNorm(norms[doc]); // normalize
   }
 
   public Explanation explain(final int doc) throws IOException {
Index: src/java/org/apache/lucene/search/spans/SpanWeight.java
===================================================================
--- src/java/org/apache/lucene/search/spans/SpanWeight.java	(revision 768376)
+++ src/java/org/apache/lucene/search/spans/SpanWeight.java	(working copy)
@@ -122,7 +122,7 @@
     Explanation fieldNormExpl = new Explanation();
     byte[] fieldNorms = reader.norms(field);
     float fieldNorm =
-      fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 0.0f;
+      fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 1.0f;
     fieldNormExpl.setValue(fieldNorm);
     fieldNormExpl.setDescription("fieldNorm(field="+field+", doc="+doc+")");
     fieldExpl.addDetail(fieldNormExpl);
Index: src/java/org/apache/lucene/search/MultiPhraseQuery.java
===================================================================
--- src/java/org/apache/lucene/search/MultiPhraseQuery.java	(revision 768376)
+++ src/java/org/apache/lucene/search/MultiPhraseQuery.java	(working copy)
@@ -225,7 +225,7 @@
       Explanation fieldNormExpl = new Explanation();
       byte[] fieldNorms = reader.norms(field);
       float fieldNorm =
-        fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 0.0f;
+        fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 1.0f;
       fieldNormExpl.setValue(fieldNorm);
       fieldNormExpl.setDescription("fieldNorm(field="+field+", doc="+doc+")");
       fieldExpl.addDetail(fieldNormExpl);
Index: src/java/org/apache/lucene/search/PhraseScorer.java
===================================================================
--- src/java/org/apache/lucene/search/PhraseScorer.java	(revision 768376)
+++ src/java/org/apache/lucene/search/PhraseScorer.java	(working copy)
@@ -104,7 +104,7 @@
   public float score() throws IOException {
     //System.out.println("scoring " + first.doc);
     float raw = getSimilarity().tf(freq) * value; // raw score
-    return raw * Similarity.decodeNorm(norms[first.doc]); // normalize
+    return norms == null ? raw : raw * Similarity.decodeNorm(norms[first.doc]); // normalize
   }
 
   public boolean skipTo(int target) throws IOException {
Index: src/java/org/apache/lucene/search/PhraseQuery.java
===================================================================
--- src/java/org/apache/lucene/search/PhraseQuery.java	(revision 768376)
+++ src/java/org/apache/lucene/search/PhraseQuery.java	(working copy)
@@ -216,7 +216,7 @@
       Explanation fieldNormExpl = new Explanation();
       byte[] fieldNorms = reader.norms(field);
       float fieldNorm =
-        fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 0.0f;
+        fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 1.0f;
       fieldNormExpl.setValue(fieldNorm);
       fieldNormExpl.setDescription("fieldNorm(field="+field+", doc="+doc+")");
       fieldExpl.addDetail(fieldNormExpl);
Index: src/java/org/apache/lucene/search/TermQuery.java
===================================================================
--- src/java/org/apache/lucene/search/TermQuery.java	(revision 768376)
+++ src/java/org/apache/lucene/search/TermQuery.java	(working copy)
@@ -111,7 +111,7 @@
       Explanation fieldNormExpl = new Explanation();
       byte[] fieldNorms = reader.norms(field);
       float fieldNorm =
-        fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 0.0f;
+        fieldNorms!=null ? Similarity.decodeNorm(fieldNorms[doc]) : 1.0f;
       fieldNormExpl.setValue(fieldNorm);
       fieldNormExpl.setDescription("fieldNorm(field="+field+", doc="+doc+")");
       fieldExpl.addDetail(fieldNormExpl);
Index: src/java/org/apache/lucene/search/TermScorer.java
===================================================================
--- src/java/org/apache/lucene/search/TermScorer.java	(revision 768376)
+++ src/java/org/apache/lucene/search/TermScorer.java	(working copy)
@@ -127,7 +127,7 @@
       ? scoreCache[f]                             // cache hit
       : getSimilarity().tf(f)*weightValue;        // cache miss
 
-    return raw * SIM_NORM_DECODER[norms[doc] & 0xFF]; // normalize for field
+    return norms == null ? raw : raw * SIM_NORM_DECODER[norms[doc] & 0xFF]; // normalize for field
   }
 
   /** Skips to the first match beyond the current whose document number is
Index: src/java/org/apache/lucene/index/DirectoryIndexReader.java
===================================================================
--- src/java/org/apache/lucene/index/DirectoryIndexReader.java	(revision 768376)
+++ src/java/org/apache/lucene/index/DirectoryIndexReader.java	(working copy)
@@ -227,7 +227,9 @@
       // TODO: right now we *always* make a new reader; in
       // the future we could have write make some effort to
       // detect that no changes have occurred
-      return writer.getReader();
+      IndexReader reader = writer.getReader();
+      reader.setDisableFakeNorms(getDisableFakeNorms());
+      return reader;
     }
 
     if (commit == null) {
@@ -298,6 +300,7 @@
       } else {
         reader = (DirectoryIndexReader) finder.doBody(commit.getSegmentsFileName());
       }
+      reader.setDisableFakeNorms(getDisableFakeNorms());
     } finally {
       if (myCloseDirectory) {
         assert directory instanceof FSDirectory;
Index: src/java/org/apache/lucene/index/SegmentReader.java
===================================================================
--- src/java/org/apache/lucene/index/SegmentReader.java	(revision 768376)
+++ src/java/org/apache/lucene/index/SegmentReader.java	(working copy)
@@ -629,11 +629,11 @@
       }
     } else {
       if (openReadOnly)
-        return new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null, doClone);
+        newReader = new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null, doClone);
       else
-        return new MultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null, false, doClone);
+        newReader = new MultiSegmentReader(directory, infos, closeDirectory, new SegmentReader[] {this}, null, null, false, doClone);
     }
-    
+    newReader.setDisableFakeNorms(getDisableFakeNorms());
     return newReader;
   }
   
@@ -708,6 +708,7 @@
         }
       }
 
+      clone.setDisableFakeNorms(getDisableFakeNorms());
       clone.norms = new HashMap();
 
       // Clone norms
@@ -1032,7 +1033,7 @@
   public synchronized byte[] norms(String field) throws IOException {
     ensureOpen();
     byte[] bytes = getNorms(field);
-    if (bytes==null) bytes=fakeNorms();
+    if (bytes==null && !getDisableFakeNorms()) bytes=fakeNorms();
     return bytes;
   }
 
@@ -1053,7 +1054,7 @@
     ensureOpen();
     Norm norm = (Norm) norms.get(field);
     if (norm == null) {
-      System.arraycopy(fakeNorms(), 0, bytes, offset, maxDoc());
+      Arrays.fill(bytes, offset, bytes.length, DefaultSimilarity.encodeNorm(1.0f));
       return;
     }
   
Index: src/java/org/apache/lucene/index/MultiReader.java
===================================================================
--- src/java/org/apache/lucene/index/MultiReader.java	(revision 768376)
+++ src/java/org/apache/lucene/index/MultiReader.java	(working copy)
@@ -18,6 +18,7 @@
  */
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -27,6 +28,7 @@
 import org.apache.lucene.index.MultiSegmentReader.MultiTermDocs;
 import org.apache.lucene.index.MultiSegmentReader.MultiTermEnum;
 import org.apache.lucene.index.MultiSegmentReader.MultiTermPositions;
+import org.apache.lucene.search.DefaultSimilarity;
 
 /** An IndexReader which reads multiple indexes, appending their content.
  *
@@ -179,6 +181,7 @@
       }
       MultiReader mr = new MultiReader(newSubReaders);
       mr.decrefOnClose = newDecrefOnClose;
+      mr.setDisableFakeNorms(getDisableFakeNorms());
       return mr;
     } else {
       return this;
@@ -288,7 +291,7 @@
     if (bytes != null)
       return bytes;          // cache hit
     if (!hasNorms(field))
-      return fakeNorms();
+      return getDisableFakeNorms() ? null : fakeNorms();
 
     bytes = new byte[maxDoc()];
     for (int i = 0; i < subReaders.length; i++)
@@ -301,14 +304,18 @@
     throws IOException {
     ensureOpen();
     byte[] bytes = (byte[])normsCache.get(field);
-    if (bytes==null && !hasNorms(field)) bytes=fakeNorms();
-    if (bytes != null)                            // cache hit
-      System.arraycopy(bytes, 0, result, offset, maxDoc());
-
     for (int i = 0; i < subReaders.length; i++)      // read from segments
       subReaders[i].norms(field, result, offset + starts[i]);
-  }
 
+    if (bytes==null && !hasNorms(field))
+        Arrays.fill(result, offset, result.length, DefaultSimilarity.encodeNorm(1.0f));
+    else if (bytes != null)                            // cache hit
+      System.arraycopy(bytes, 0, result, offset, maxDoc());
+    else
+      for (int i = 0; i < subReaders.length; i++)      // read from segments
+        subReaders[i].norms(field, result, offset + starts[i]);
+}
+
   protected void doSetNorm(int n, String field, byte value)
     throws CorruptIndexException, IOException {
     synchronized (normsCache) {
Index: src/java/org/apache/lucene/index/IndexReader.java
===================================================================
--- src/java/org/apache/lucene/index/IndexReader.java	(revision 768376)
+++ src/java/org/apache/lucene/index/IndexReader.java	(working copy)
@@ -116,6 +116,8 @@
   
   private volatile int refCount;
 
+  private boolean disableFakeNorms = false;
+
   /** Expert: returns the current refCount for this reader */
   public synchronized int getRefCount() {
     return refCount;
@@ -1275,4 +1277,21 @@
   public long getUniqueTermCount() throws IOException {
     throw new UnsupportedOperationException("this reader does not implement getUniqueTermCount()");
   }
+
+  /** Expert: Return the state of the flag that disables fakes norms in favor of representing the absence of field norms with null.
+   * @return true if fake norms are disabled
+   * @deprecated
+   */
+  public boolean getDisableFakeNorms() {
+    return disableFakeNorms;
+  }
+
+  /** Expert: Set the state of the flag that disables fakes norms in favor of representing the absence of field norms with null.
+   * @param disableFakeNorms true to disable fake norms, false to preserve the legacy behavior
+   * @deprecated
+   */
+  public void setDisableFakeNorms(boolean disableFakeNorms) {
+    this.disableFakeNorms = disableFakeNorms;
+ }
+
 }
Index: src/java/org/apache/lucene/index/MultiSegmentReader.java
===================================================================
--- src/java/org/apache/lucene/index/MultiSegmentReader.java	(revision 768376)
+++ src/java/org/apache/lucene/index/MultiSegmentReader.java	(working copy)
@@ -18,6 +18,7 @@
  */
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -27,6 +28,7 @@
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.search.DefaultSimilarity;
 import org.apache.lucene.store.Directory;
 
 /** 
@@ -262,15 +264,18 @@
   }
 
   protected synchronized DirectoryIndexReader doReopen(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException {
-    if (infos.size() == 1) {
+    DirectoryIndexReader reader;
+	if (infos.size() == 1) {
       // The index has only one segment now, so we can't refresh the MultiSegmentReader.
       // Return a new [ReadOnly]SegmentReader instead
-      return SegmentReader.get(openReadOnly, infos, infos.info(0), false);
+      reader = SegmentReader.get(openReadOnly, infos, infos.info(0), false);
     } else if (openReadOnly) {
-      return new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache, doClone);
+      reader = new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache, doClone);
     } else {
-      return new MultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache, false, doClone);
-    }            
+      reader = new MultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache, false, doClone);
+    }
+    reader.setDisableFakeNorms(getDisableFakeNorms());
+    return reader;
   }
 
   public TermFreqVector[] getTermFreqVectors(int n) throws IOException {
@@ -397,7 +402,7 @@
     if (bytes != null)
       return bytes;          // cache hit
     if (!hasNorms(field))
-      return fakeNorms();
+      return getDisableFakeNorms() ? null : fakeNorms();
 
     bytes = new byte[maxDoc()];
     for (int i = 0; i < subReaders.length; i++)
@@ -410,12 +415,13 @@
     throws IOException {
     ensureOpen();
     byte[] bytes = (byte[])normsCache.get(field);
-    if (bytes==null && !hasNorms(field)) bytes=fakeNorms();
-    if (bytes != null)                            // cache hit
+    if (bytes==null && !hasNorms(field))
+      Arrays.fill(result, offset, result.length, DefaultSimilarity.encodeNorm(1.0f));
+    else if (bytes != null)                            // cache hit
       System.arraycopy(bytes, 0, result, offset, maxDoc());
-
-    for (int i = 0; i < subReaders.length; i++)      // read from segments
-      subReaders[i].norms(field, result, offset + starts[i]);
+    else
+      for (int i = 0; i < subReaders.length; i++)      // read from segments
+        subReaders[i].norms(field, result, offset + starts[i]);
   }
 
   protected void doSetNorm(int n, String field, byte value)
@@ -514,6 +520,12 @@
       throw new IllegalStateException("no readers");
   }
 
+  public void setDisableFakeNorms(boolean disableFakeNorms) {
+    super.setDisableFakeNorms(disableFakeNorms);
+    for (int i = 0; i < subReaders.length; i++)
+        subReaders[i].setDisableFakeNorms(disableFakeNorms);
+  }
+
   static class MultiTermEnum extends TermEnum {
     private SegmentMergeQueue queue;
   
