Index: contrib/queries/src/java/org/apache/lucene/search/trie/TrieUtils.java
===================================================================
--- contrib/queries/src/java/org/apache/lucene/search/trie/TrieUtils.java	(revision 765419)
+++ contrib/queries/src/java/org/apache/lucene/search/trie/TrieUtils.java	(working copy)
@@ -18,6 +18,8 @@
  */
 
 import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.ValueSource;
+import org.apache.lucene.search.CachingValueSource;
 import org.apache.lucene.search.FieldCache;
 import org.apache.lucene.search.ExtendedFieldCache;
 
@@ -64,57 +66,12 @@
 
   /** internal: maximum needed <code>char[]</code> buffer size for encoding */
   static final int INT_BUF_SIZE = 31/7 + 2;
-
-  /**
-   * A parser instance for filling a {@link ExtendedFieldCache}, that parses prefix encoded fields as longs.
-   */
-  public static final ExtendedFieldCache.LongParser FIELD_CACHE_LONG_PARSER=new ExtendedFieldCache.LongParser(){
-    public final long parseLong(final String val) {
-      final int shift = val.charAt(0)-SHIFT_START_LONG;
-      if (shift>0 && shift<=63)
-        throw new FieldCache.StopFillCacheException();
-      return prefixCodedToLong(val);
-    }
-  };
   
   /**
-   * A parser instance for filling a {@link FieldCache}, that parses prefix encoded fields as ints.
+   * A value source for the field cache, that parses prefix encoded fields.
    */
-  public static final FieldCache.IntParser FIELD_CACHE_INT_PARSER=new FieldCache.IntParser(){
-    public final int parseInt(final String val) {
-      final int shift = val.charAt(0)-SHIFT_START_INT;
-      if (shift>0 && shift<=31)
-        throw new FieldCache.StopFillCacheException();
-      return prefixCodedToInt(val);
-    }
-  };
+  public static final ValueSource TRIE_VALUE_SOURCE = new CachingValueSource(new TrieValueSource());
 
-  /**
-   * A parser instance for filling a {@link ExtendedFieldCache}, that parses prefix encoded fields as doubles.
-   * This uses {@link #sortableLongToDouble} to convert the encoded long to a double.
-   */
-  public static final ExtendedFieldCache.DoubleParser FIELD_CACHE_DOUBLE_PARSER=new ExtendedFieldCache.DoubleParser(){
-    public final double parseDouble(final String val) {
-      final int shift = val.charAt(0)-SHIFT_START_LONG;
-      if (shift>0 && shift<=63)
-        throw new FieldCache.StopFillCacheException();
-      return sortableLongToDouble(prefixCodedToLong(val));
-    }
-  };
-  
-  /**
-   * A parser instance for filling a {@link FieldCache}, that parses prefix encoded fields as floats.
-   * This uses {@link #sortableIntToFloat} to convert the encoded int to a float.
-   */
-  public static final FieldCache.FloatParser FIELD_CACHE_FLOAT_PARSER=new FieldCache.FloatParser(){
-    public final float parseFloat(final String val) {
-      final int shift = val.charAt(0)-SHIFT_START_INT;
-      if (shift>0 && shift<=31)
-        throw new FieldCache.StopFillCacheException();
-      return sortableIntToFloat(prefixCodedToInt(val));
-    }
-  };
-  
   /** internal */
   static int longToPrefixCoded(final long val, final int shift, final char[] buffer) {
     int nChars = (63-shift)/7 + 1, len = nChars+1;
@@ -291,12 +248,12 @@
 
   /** A factory method, that generates a {@link SortField} instance for sorting prefix encoded long values. */
   public static SortField getLongSortField(final String field, final boolean reverse) {
-    return new SortField(field, FIELD_CACHE_LONG_PARSER, reverse);
+    return new SortField(field, SortField.LONG, TRIE_VALUE_SOURCE, reverse);
   }
   
   /** A factory method, that generates a {@link SortField} instance for sorting prefix encoded int values. */
   public static SortField getIntSortField(final String field, final boolean reverse) {
-    return new SortField(field, FIELD_CACHE_INT_PARSER, reverse);
+    return new SortField(field, SortField.INT, TRIE_VALUE_SOURCE, reverse);
   }
 
   /**
Index: contrib/queries/src/java/org/apache/lucene/search/trie/TrieValueSource.java
===================================================================
--- contrib/queries/src/java/org/apache/lucene/search/trie/TrieValueSource.java	(revision 0)
+++ contrib/queries/src/java/org/apache/lucene/search/trie/TrieValueSource.java	(revision 0)
@@ -0,0 +1,115 @@
+package org.apache.lucene.search.trie;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.ValueSource;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.TermEnum;
+
+public class TrieValueSource extends ValueSource {
+
+  public double[] getDoubles(final IndexReader reader, String field) throws IOException {
+    final double[] retArray = new double[reader.maxDoc()];
+    new TrieUninverter() {
+      private double doubleVal;
+
+      protected void handleDoc(int index) {
+        retArray[index] = doubleVal;
+      }
+
+      protected boolean newTerm(String value) {
+        final int shift = value.charAt(0)-TrieUtils.SHIFT_START_LONG;
+        if (shift>0 && shift<=63) return true;
+        this.doubleVal = TrieUtils.sortableLongToDouble(TrieUtils.prefixCodedToLong(value));
+        return false;
+      }
+    }.go(reader, field);
+    return retArray;
+  }
+
+  public float[] getFloats(final IndexReader reader, String field) throws IOException {
+    final float[] retArray = new float[reader.maxDoc()];
+    new TrieUninverter() {
+      private float floatVal;
+
+      protected void handleDoc(int index) {
+        retArray[index] = floatVal;
+      }
+
+      protected boolean newTerm(String value) {
+        final int shift = value.charAt(0)-TrieUtils.SHIFT_START_INT;
+        if (shift>0 && shift<=63) return true;
+        this.floatVal = TrieUtils.sortableIntToFloat(TrieUtils.prefixCodedToInt(value));
+        return false;
+      }
+    }.go(reader, field);
+    return retArray;
+  }
+
+  public int[] getInts(final IndexReader reader, String field) throws IOException {
+    final int[] retArray = new int[reader.maxDoc()];
+    new TrieUninverter() {
+      private int intVal;
+
+      protected void handleDoc(int index) {
+        retArray[index] = intVal;
+      }
+
+      protected boolean newTerm(String value) {
+        final int shift = value.charAt(0)-TrieUtils.SHIFT_START_INT;
+        if (shift>0 && shift<=31) return true;
+        this.intVal = TrieUtils.prefixCodedToInt(value);
+        return false;
+      }
+    }.go(reader, field);
+    return retArray;
+  }
+
+  public long[] getLongs(final IndexReader reader, String field) throws IOException {
+    final long[] retArray = new long[reader.maxDoc()];
+    new TrieUninverter() {
+      private long longVal;
+
+      protected void handleDoc(int index) {
+        retArray[index] = longVal;
+      }
+
+      protected boolean newTerm(String value) {
+        final int shift = value.charAt(0)-TrieUtils.SHIFT_START_LONG;
+        if (shift>0 && shift<=63) return true;
+        this.longVal = TrieUtils.prefixCodedToLong(value);
+        return false;
+      }
+    }.go(reader, field);
+    return retArray;
+  }
+
+  protected static abstract class TrieUninverter {
+    public void go(IndexReader reader, String field) throws IOException {
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field)
+            break;
+          if (newTerm(term.text())) break;
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            handleDoc(termDocs.doc());
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+    }
+
+    protected abstract void handleDoc(int docID);
+
+    /** returns true, if parsing should be stopped */
+    protected abstract boolean newTerm(String text);
+  }
+}
Index: src/java/org/apache/lucene/index/DirectoryIndexReader.java
===================================================================
--- src/java/org/apache/lucene/index/DirectoryIndexReader.java	(revision 763931)
+++ src/java/org/apache/lucene/index/DirectoryIndexReader.java	(working copy)
@@ -26,6 +26,7 @@
 import java.util.Iterator;
 import java.util.Collections;
 
+import org.apache.lucene.search.ValueSource;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.Lock;
 import org.apache.lucene.store.LockObtainFailedException;
@@ -55,10 +56,16 @@
   IndexWriter writer;
 
   protected boolean readOnly;
-
   
+  ValueSource valueSource;
+
   void init(Directory directory, SegmentInfos segmentInfos, boolean closeDirectory, boolean readOnly)
     throws IOException {
+    init(directory, segmentInfos, closeDirectory, readOnly, null);
+  }
+  
+  void init(Directory directory, SegmentInfos segmentInfos, boolean closeDirectory, boolean readOnly, ValueSource valueSource)
+    throws IOException {
     this.directory = directory;
     this.segmentInfos = segmentInfos;
     this.closeDirectory = closeDirectory;
@@ -182,7 +189,8 @@
     DirectoryIndexReader newReader = doReopen(clonedInfos, true, openReadOnly);
     
     if (this != newReader) {
-      newReader.init(directory, clonedInfos, closeDirectory, openReadOnly);
+      //nocommit: I probably cant just share this - consider
+      newReader.init(directory, clonedInfos, closeDirectory, openReadOnly, valueSource);
       newReader.deletionPolicy = deletionPolicy;
     }
     newReader.writer = writer;
Index: src/java/org/apache/lucene/index/IndexReader.java
===================================================================
--- src/java/org/apache/lucene/index/IndexReader.java	(revision 763931)
+++ src/java/org/apache/lucene/index/IndexReader.java	(working copy)
@@ -19,7 +19,10 @@
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.search.CachingValueSource;
 import org.apache.lucene.search.Similarity;
+import org.apache.lucene.search.UninversionValueSource;
+import org.apache.lucene.search.ValueSource;
 import org.apache.lucene.store.*;
 
 import java.io.File;
@@ -1275,4 +1278,8 @@
   public long getUniqueTermCount() throws IOException {
     throw new UnsupportedOperationException("this reader does not implement getUniqueTermCount()");
   }
+  
+  public ValueSource getValueSource() {
+    throw new UnsupportedOperationException("You can only call this method on a SegmentReader. See #getSequentialSubReaders()");
+  }
 }
Index: src/java/org/apache/lucene/index/SegmentReader.java
===================================================================
--- src/java/org/apache/lucene/index/SegmentReader.java	(revision 763931)
+++ src/java/org/apache/lucene/index/SegmentReader.java	(working copy)
@@ -30,7 +30,10 @@
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.search.CachingValueSource;
 import org.apache.lucene.search.DefaultSimilarity;
+import org.apache.lucene.search.UninversionValueSource;
+import org.apache.lucene.search.ValueSource;
 import org.apache.lucene.store.BufferedIndexInput;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.IndexInput;
@@ -66,6 +69,7 @@
   private int rollbackPendingDeleteCount;
   IndexInput freqStream;
   IndexInput proxStream;
+  
 
   // optionally used for the .nrm file shared by multiple norms
   private IndexInput singleNormStream;
@@ -466,6 +470,7 @@
     }
     instance.init(dir, sis, closeDir, readOnly);
     instance.initialize(si, readBufferSize, doOpenStores);
+    instance.valueSource = new CachingValueSource(new UninversionValueSource());
     return instance;
   }
 
@@ -1273,4 +1278,8 @@
   public long getUniqueTermCount() {
     return tis.size();
   }
+  
+  public ValueSource getValueSource() {
+    return valueSource;
+  }
 }
Index: src/java/org/apache/lucene/search/CacheByReaderValueSource.java
===================================================================
--- src/java/org/apache/lucene/search/CacheByReaderValueSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/CacheByReaderValueSource.java	(revision 0)
@@ -0,0 +1,207 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.apache.lucene.index.IndexReader;
+
+/**
+ *
+ * 
+ */
+public class CacheByReaderValueSource extends ValueSource {
+  public Comparable[] getComparables(final IndexReader reader,
+      final String field, final SortComparator comparator) throws IOException {
+    return (Comparable[]) get(reader, SortField.CUSTOM, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getComparables(reader, field, comparator);
+      }
+    }, comparator);
+  }
+
+  public short[] getShorts(final IndexReader reader, final String field)
+      throws IOException {
+    return (short[]) get(reader, SortField.SHORT, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getShorts(reader, field);
+      }
+    },  null);
+  }
+
+  public StringIndex getStringIndex(final IndexReader reader, final String field)
+      throws IOException {
+    return (StringIndex) get(reader, SortField.STRING, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getStringIndex(reader, field);
+      }
+    }, null);
+  }
+
+  public String[] getStrings(final IndexReader reader, final String field)
+      throws IOException {
+    return (String[]) get(reader, SortField.STRING_VAL, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getStrings(reader, field);
+      }
+    }, null);
+  }
+
+  private Object get(IndexReader reader, int type, String field, HasData data, SortComparator comparator) throws IOException {
+    UninversionValueSource valueSource = new UninversionValueSource();
+    Object value;
+    Key key = new Key();
+    key.type = type;
+    key.field = field;
+    key.reader = reader;
+    key.comparator = comparator;
+    synchronized (cache) {
+      value = cache.get(key);
+      if (value == null) {
+        value = new CacheCreationPlaceholder();
+        cache.put(key, value);
+      }
+    }
+
+    if (value instanceof CacheCreationPlaceholder) {
+      synchronized (value) {
+        CacheCreationPlaceholder progress = (CacheCreationPlaceholder) value;
+        if (progress.value == null) {
+          progress.value = data.get(valueSource);
+          synchronized (cache) {
+            cache.put(key, progress.value);
+          }
+        }
+        return progress.value;
+      }
+    }
+    return value;
+  }
+
+  private static final class CacheCreationPlaceholder {
+    Object value;
+  }
+
+  private interface HasData {
+    Object get(UninversionValueSource valueSource) throws IOException;
+  }
+
+  private class Key {
+    SortComparator comparator;
+    int type;
+    String field;
+    IndexReader reader;
+    
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      Key other = (Key) obj;
+      if (!getOuterType().equals(other.getOuterType()))
+        return false;
+      if (comparator == null) {
+        if (other.comparator != null)
+          return false;
+      } else if (!comparator.equals(other.comparator))
+        return false;
+      if (field == null) {
+        if (other.field != null)
+          return false;
+      } else if (!field.equals(other.field))
+        return false;
+      if (reader == null) {
+        if (other.reader != null)
+          return false;
+      } else if (!reader.equals(other.reader))
+        return false;
+      if (type != other.type)
+        return false;
+      return true;
+    }
+
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + getOuterType().hashCode();
+      result = prime * result
+          + ((comparator == null) ? 0 : comparator.hashCode());
+      result = prime * result + ((field == null) ? 0 : field.hashCode());
+      result = prime * result + ((reader == null) ? 0 : reader.hashCode());
+      result = prime * result + type;
+      return result;
+    }
+
+    private CacheByReaderValueSource getOuterType() {
+      return CacheByReaderValueSource.this;
+    }
+
+  }
+
+  public final static CacheByReaderValueSource DEFAULT_CACHE_BY_READER_VALUE_SOURCE = new CacheByReaderValueSource();
+
+  private Map cache = new WeakHashMap();
+
+  public CacheByReaderValueSource() {
+
+  }
+
+  public byte[] getBytes(final IndexReader reader, final String field)
+      throws IOException {
+
+    return (byte[]) get(reader, SortField.BYTE, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getBytes(reader, field);
+      }
+    }, null);
+  }
+
+  public double[] getDoubles(final IndexReader reader, final String field)
+      throws IOException {
+    return (double[]) get(reader, SortField.DOUBLE, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getDoubles(reader, field);
+      }
+    }, null);
+  }
+
+  public float[] getFloats(final IndexReader reader, final String field)
+      throws IOException {
+    return (float[]) get(reader, SortField.FLOAT, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getFloats(reader, field);
+      }
+    }, null);
+  }
+
+
+  public int[] getInts(final IndexReader reader, final String field)
+      throws IOException {
+    return (int[]) get(reader, SortField.INT, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getInts(reader, field);
+      }
+    }, null);
+  }
+
+  public long[] getLongs(final IndexReader reader, final String field)
+      throws IOException {
+    return (long[]) get(reader, SortField.LONG, field, new HasData() {
+
+      public Object get(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getLongs(reader, field);
+      }
+    }, null);
+  }
+
+}
Index: src/java/org/apache/lucene/search/CachingByReaderUninverterValueSource.java
===================================================================
--- src/java/org/apache/lucene/search/CachingByReaderUninverterValueSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/CachingByReaderUninverterValueSource.java	(revision 0)
@@ -0,0 +1,271 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.UninversionValueSource.Uninverter;
+
+/**
+ *
+ * @deprecated
+ */
+public class CachingByReaderUninverterValueSource extends ValueSource {
+  public final static CachingByReaderUninverterValueSource DEFAULT_CACHE_BY_READER_VALUE_SOURCE = new CachingByReaderUninverterValueSource();
+
+  private Map cache = new WeakHashMap();
+
+  public CachingByReaderUninverterValueSource() {
+
+  }
+
+  public byte[] getBytes(final IndexReader reader, final String field)
+      throws IOException {
+
+    return (byte[]) get(reader, SortField.BYTE, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getBytes(reader, field);
+      }
+    }, null, null);
+  }
+
+  public byte[] getBytes(final IndexReader reader, final String field,
+      final Uninverter uninverter) throws IOException {
+    return (byte[]) get(reader, SortField.BYTE, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getBytes(reader, field, uninverter);
+      }
+    }, uninverter, null);
+  }
+
+  public double[] getDoubles(final IndexReader reader, final String field)
+      throws IOException {
+    return (double[]) get(reader, SortField.DOUBLE, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getDoubles(reader, field);
+      }
+    }, null, null);
+  }
+
+  public double[] getDoubles(final IndexReader reader, final String field,
+      final Uninverter uninverter) throws IOException {
+    return (double[]) get(reader, SortField.DOUBLE, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getDoubles(reader, field, uninverter);
+      }
+    }, uninverter, null);
+  }
+
+  public float[] getFloats(final IndexReader reader, final String field)
+      throws IOException {
+    return (float[]) get(reader, SortField.FLOAT, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getFloats(reader, field);
+      }
+    }, null, null);
+  }
+
+  public float[] getFloats(final IndexReader reader, final String field,
+      final Uninverter uninverter) throws IOException {
+    return (float[]) get(reader, SortField.FLOAT, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getFloats(reader, field, uninverter);
+      }
+    }, uninverter, null);
+  }
+
+  public int[] getInts(final IndexReader reader, final String field)
+      throws IOException {
+    return (int[]) get(reader, SortField.INT, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getInts(reader, field);
+      }
+    }, null, null);
+  }
+
+  public int[] getInts(final IndexReader reader, final String field,
+      final Uninverter uninverter) throws IOException {
+    return (int[]) get(reader, SortField.INT, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getInts(reader, field, uninverter);
+      }
+    }, uninverter, null);
+  }
+
+  public long[] getLongs(final IndexReader reader, final String field)
+      throws IOException {
+    return (long[]) get(reader, SortField.LONG, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getLongs(reader, field);
+      }
+    }, null, null);
+  }
+
+  public long[] getLongs(final IndexReader reader, final String field,
+      final Uninverter uninverter) throws IOException {
+    return (long[]) get(reader, SortField.LONG, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getLongs(reader, field, uninverter);
+      }
+    }, uninverter, null);
+  }
+
+  public short[] getShorts(final IndexReader reader, final String field)
+      throws IOException {
+    return (short[]) get(reader, SortField.SHORT, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getShorts(reader, field);
+      }
+    }, null, null);
+  }
+
+  public short[] getShorts(final IndexReader reader, final String field,
+      final Uninverter uninverter) throws IOException {
+    return (short[]) get(reader, SortField.SHORT, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getShorts(reader, field, uninverter);
+      }
+    }, uninverter, null);
+  }
+
+  public StringIndex getStringIndex(final IndexReader reader, final String field)
+      throws IOException {
+    return (StringIndex) get(reader, SortField.STRING, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getStringIndex(reader, field);
+      }
+    }, null, null);
+  }
+
+  public String[] getStrings(final IndexReader reader, final String field)
+      throws IOException {
+    return (String[]) get(reader, SortField.STRING_VAL, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getStrings(reader, field);
+      }
+    }, null, null);
+  }
+
+  public Comparable[] getComparables(final IndexReader reader,
+      final String field, final SortComparator comparator) throws IOException {
+    return (Comparable[]) get(reader, SortField.CUSTOM, field, new DataBuilder() {
+
+      public Object build(UninversionValueSource valueSource) throws IOException {
+        return valueSource.getComparables(reader, field, comparator);
+      }
+    }, null, comparator);
+  }
+
+  private Object get(IndexReader reader, int type, String field, DataBuilder data,
+      Uninverter uninverter, SortComparator comparator) throws IOException {
+    UninversionValueSource valueSource = new UninversionValueSource();
+    Object value;
+    Key key = new Key();
+    key.type = type;
+    key.field = field;
+    key.readerKey = reader.getFieldCacheKey();
+    key.uninverter = uninverter;
+    key.comparator = comparator;
+    synchronized (cache) {
+      value = cache.get(key);
+      if (value == null) {
+        value = new CacheCreationPlaceholder();
+        cache.put(key, value);
+      }
+    }
+
+    if (value instanceof CacheCreationPlaceholder) {
+      synchronized (value) {
+        CacheCreationPlaceholder progress = (CacheCreationPlaceholder) value;
+        if (progress.value == null) {
+          progress.value = data.build(valueSource);
+          synchronized (cache) {
+            cache.put(key, progress.value);
+          }
+        }
+        return progress.value;
+      }
+    }
+    return value;
+  }
+
+  private static final class CacheCreationPlaceholder {
+    Object value;
+  }
+
+  private static class Key {
+    Uninverter uninverter;
+    SortComparator comparator;
+    int type;
+    String field;
+    Object readerKey;
+
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result
+          + ((comparator == null) ? 0 : comparator.hashCode());
+      result = prime * result + ((field == null) ? 0 : field.hashCode());
+      result = prime * result
+          + ((readerKey == null) ? 0 : readerKey.hashCode());
+      result = prime * result + type;
+      result = prime * result
+          + ((uninverter == null) ? 0 : uninverter.hashCode());
+      return result;
+    }
+
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      Key other = (Key) obj;
+      if (comparator == null) {
+        if (other.comparator != null)
+          return false;
+      } else if (!comparator.equals(other.comparator))
+        return false;
+      if (field == null) {
+        if (other.field != null)
+          return false;
+      } else if (!field.equals(other.field))
+        return false;
+      if (readerKey == null) {
+        if (other.readerKey != null)
+          return false;
+      } else if (!readerKey.equals(other.readerKey))
+        return false;
+      if (type != other.type)
+        return false;
+      if (uninverter == null) {
+        if (other.uninverter != null)
+          return false;
+      } else if (!uninverter.equals(other.uninverter))
+        return false;
+      return true;
+    }
+
+  }
+
+  private interface DataBuilder {
+    Object build(UninversionValueSource valueSource) throws IOException;
+  }
+
+}
Index: src/java/org/apache/lucene/search/CachingValueSource.java
===================================================================
--- src/java/org/apache/lucene/search/CachingValueSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/CachingValueSource.java	(revision 0)
@@ -0,0 +1,190 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader;
+
+public class CachingValueSource extends ValueSource {
+
+  ValueSource valueSource;
+
+  private Map cache = new HashMap();
+
+  public CachingValueSource(ValueSource valueSource) {
+    this.valueSource = valueSource;
+  }
+
+  public byte[] getBytes(final IndexReader reader, final String field)
+      throws IOException {
+    return (byte[]) get(SortField.BYTE, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getBytes(reader, field);
+      }
+    }, null);
+  }
+
+  public double[] getDoubles(final IndexReader reader, final String field)
+      throws IOException {
+    return (double[]) get(SortField.DOUBLE, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getDoubles(reader, field);
+      }
+    }, null);
+  }
+
+  public float[] getFloats(final IndexReader reader, final String field)
+      throws IOException {
+    return (float[]) get(SortField.FLOAT, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getFloats(reader, field);
+      }
+    }, null);
+  }
+
+  public int[] getInts(final IndexReader reader, final String field)
+      throws IOException {
+    return (int[]) get(SortField.INT, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getInts(reader, field);
+      }
+    }, null);
+  }
+
+  public long[] getLongs(final IndexReader reader, final String field)
+      throws IOException {
+    return (long[]) get(SortField.LONG, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getLongs(reader, field);
+      }
+    }, null);
+  }
+
+  public short[] getShorts(final IndexReader reader, final String field)
+      throws IOException {
+    return (short[]) get(SortField.SHORT, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getShorts(reader, field);
+      }
+    }, null);
+  }
+
+  public StringIndex getStringIndex(final IndexReader reader, final String field)
+      throws IOException {
+    return (StringIndex) get(SortField.STRING, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getStringIndex(reader, field);
+      }
+    }, null);
+  }
+
+  public String[] getStrings(final IndexReader reader, final String field)
+      throws IOException {
+    return (String[]) get(SortField.STRING_VAL, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getStrings(reader, field);
+      }
+    }, null);
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.lucene.search.ValueSource#getComparables(org.apache.lucene.index.Indexjava.lang.String, org.apache.lucene.search.SortComparator)
+   */
+  public Comparable[] getComparables(final IndexReader reader, final String field, final SortComparator comparator)
+      throws IOException {
+    return (Comparable[]) get(SortField.CUSTOM, field, new HasData() {
+
+      public Object getData() throws IOException {
+        return valueSource.getComparables(reader, field, comparator);
+      }
+    }, comparator);
+  }
+
+  private Object get(int type, String field, HasData hasData, SortComparator comparator)
+      throws IOException {
+    Object value;
+    Key key = new Key();
+    key.type = type;
+    key.field = field;
+    key.comparator = comparator;
+    synchronized (cache) {
+      value = cache.get(key);
+      if (value == null) {
+        value = new CacheCreationPlaceholder();
+        cache.put(key, value);
+      }
+    }
+
+    if (value instanceof CacheCreationPlaceholder) {
+      synchronized (value) {
+        CacheCreationPlaceholder progress = (CacheCreationPlaceholder) value;
+        if (progress.value == null) {
+          progress.value = hasData.getData();
+          synchronized (cache) {
+            cache.put(key, progress.value);
+          }
+        }
+        return progress.value;
+      }
+    }
+    return value;
+  }
+
+  private static final class CacheCreationPlaceholder {
+    Object value;
+  }
+
+  private interface HasData {
+    Object getData() throws IOException;
+  }
+
+  private static class Key {
+    public SortComparator comparator;
+    int type;
+    String field;
+
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result
+          + ((comparator == null) ? 0 : comparator.hashCode());
+      result = prime * result + ((field == null) ? 0 : field.hashCode());
+      result = prime * result + type;
+      return result;
+    }
+
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      Key other = (Key) obj;
+      if (comparator == null) {
+        if (other.comparator != null)
+          return false;
+      } else if (!comparator.equals(other.comparator))
+        return false;
+      if (field == null) {
+        if (other.field != null)
+          return false;
+      } else if (!field.equals(other.field))
+        return false;
+      if (type != other.type)
+        return false;
+      return true;
+    }
+
+  }
+
+}
Index: src/java/org/apache/lucene/search/ExtendedFieldCache.java
===================================================================
--- src/java/org/apache/lucene/search/ExtendedFieldCache.java	(revision 765420)
+++ src/java/org/apache/lucene/search/ExtendedFieldCache.java	(working copy)
@@ -17,14 +17,13 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.index.IndexReader;
-
 import java.io.IOException;
 
+import org.apache.lucene.index.IndexReader;
 
 /**
  *
- *
+ * @deprecated //nocommit
  **/
 public interface ExtendedFieldCache extends FieldCache {
   public interface LongParser extends Parser {
@@ -53,6 +52,7 @@
    * @param field  Which field contains the longs.
    * @return The values in the given field for each document.
    * @throws java.io.IOException If any error occurs.
+   * @deprecated use IndexReader.getCachedData(reader, new LongArrayCacheKey(field))
    */
   public long[] getLongs(IndexReader reader, String field)
           throws IOException;
@@ -68,6 +68,7 @@
    * @param parser Computes integer for string values.
    * @return The values in the given field for each document.
    * @throws IOException If any error occurs.
+   * @deprecated use IndexReader.getCachedData(reader, new LongArrayCacheKey(field), parser)
    */
   public long[] getLongs(IndexReader reader, String field, LongParser parser)
           throws IOException;
@@ -83,6 +84,7 @@
    * @param field  Which field contains the doubles.
    * @return The values in the given field for each document.
    * @throws IOException If any error occurs.
+   * @deprecated use IndexReader.getCachedData(reader, new DoubleArrayCacheKey(field))
    */
   public double[] getDoubles(IndexReader reader, String field)
           throws IOException;
@@ -98,6 +100,7 @@
    * @param parser Computes integer for string values.
    * @return The values in the given field for each document.
    * @throws IOException If any error occurs.
+   * @deprecated use IndexReader.getCachedData(reader, new DoubleArrayCacheKey(field), parser)
    */
   public double[] getDoubles(IndexReader reader, String field, DoubleParser parser)
           throws IOException;
Index: src/java/org/apache/lucene/search/ExtendedFieldCacheImpl.java
===================================================================
--- src/java/org/apache/lucene/search/ExtendedFieldCacheImpl.java	(revision 765420)
+++ src/java/org/apache/lucene/search/ExtendedFieldCacheImpl.java	(working copy)
@@ -17,70 +17,67 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermDocs;
 import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.search.FieldCache.Parser;
+import org.apache.lucene.search.UninversionValueSource.Uninverter;
 
-import java.io.IOException;
-
 
 /**
- *
- *
+ * @deprecated use IndexReader.getCachedData
  **/
 class ExtendedFieldCacheImpl extends FieldCacheImpl implements ExtendedFieldCache {
-  private static final LongParser LONG_PARSER = new LongParser() {
-      public long parseLong(String value) {
-        return Long.parseLong(value);
-      }
+      
+  static final LongParser LONG_PARSER = new LongParser() {
+  public long parseLong(String value) {
+      return Long.parseLong(value);
+    }
   };
 
-  private static final DoubleParser DOUBLE_PARSER = new DoubleParser() {
-      public double parseDouble(String value) {
-        return Double.parseDouble(value);
-      }
+  static final DoubleParser DOUBLE_PARSER = new DoubleParser() {
+    public double parseDouble(String value) {
+      return Double.parseDouble(value);
+    }
   };
 
-
   public long[] getLongs(IndexReader reader, String field) throws IOException {
     return getLongs(reader, field, LONG_PARSER);
   }
 
   // inherit javadocs
-  public long[] getLongs(IndexReader reader, String field, LongParser parser)
+  public long[] getLongs(final IndexReader reader, String field, final LongParser parser)
       throws IOException {
-    return (long[]) longsCache.get(reader, new Entry(field, parser));
-  }
+    class LongUninverter extends Uninverter {
+      private long longVal;
+      private long[] retArray = new long[reader.maxDoc()];
+      private Parser lparser = parser;
 
-  Cache longsCache = new Cache() {
+      void handleDoc(int index) {
+        retArray[index] = longVal;
+      }
 
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      LongParser parser = (LongParser) entry.custom;
-      final long[] retArray = new long[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term(field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          long termval = parser.parseLong(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } catch (StopFillCacheException stop) {
-      } finally {
-        termDocs.close();
-        termEnum.close();
+      void newTerm(String value) {
+        this.longVal = parser.parseLong(value);
       }
-      return retArray;
-    }
-  };
+      
+      public int hashCode() {
+        return parser.hashCode();
+      }
+      
+      public boolean equals(Object object ) {
+        return lparser.equals(((LongUninverter)object).lparser);
+      }
+
+      Object getArray() {
+        return retArray;
+      }
+    };
+    Uninverter parserUninverter = new LongUninverter() ;
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getLongs(reader, field, parserUninverter);
+  }
 
   // inherit javadocs
   public double[] getDoubles(IndexReader reader, String field)
@@ -89,40 +86,37 @@
   }
 
   // inherit javadocs
-  public double[] getDoubles(IndexReader reader, String field, DoubleParser parser)
+  public double[] getDoubles(final IndexReader reader, String field, final DoubleParser parser)
       throws IOException {
-    return (double[]) doublesCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache doublesCache = new Cache() {
+    class DoubleUninverter extends Uninverter {
+      private double doubleVal;
+      private double[] retArray = new double[reader.maxDoc()];
+      private Parser dparser = parser;
+      
+      void handleDoc(int index) {
+        retArray[index] = doubleVal;
+      }
 
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      DoubleParser parser = (DoubleParser) entry.custom;
-      final double[] retArray = new double[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          double termval = parser.parseDouble(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } catch (StopFillCacheException stop) {
-      } finally {
-        termDocs.close();
-        termEnum.close();
+      void newTerm(String value) {
+        this.doubleVal = parser.parseDouble(value);
       }
-      return retArray;
-    }
-  };
 
+      public int hashCode() {
+        return parser.hashCode();
+      }
+      
+      public boolean equals(Object object ) {
+        return dparser.equals(((DoubleUninverter)object).dparser);
+      }
+      
+      
+      Object getArray() {
+        return retArray;
+      }
+    };
+    Uninverter parserUninverter = new DoubleUninverter() ;
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getDoubles(reader, field, parserUninverter);
+  }
 
   // inherit javadocs
   public Object getAuto(IndexReader reader, String field) throws IOException {
Index: src/java/org/apache/lucene/search/FieldCache.java
===================================================================
--- src/java/org/apache/lucene/search/FieldCache.java	(revision 765420)
+++ src/java/org/apache/lucene/search/FieldCache.java	(working copy)
@@ -17,9 +17,10 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.index.IndexReader;
 import java.io.IOException;
 
+import org.apache.lucene.index.IndexReader;
+
 /**
  * Expert: Maintains caches of term values.
  *
@@ -27,6 +28,7 @@
  *
  * @since   lucene 1.4
  * @version $Id$
+ * @deprecated see ValueSource
  */
 public interface FieldCache {
 
@@ -36,41 +38,15 @@
   public static final int STRING_INDEX = -1;
 
 
-  /** Expert: Stores term text values and document ordering data. */
-  public static class StringIndex {
-	  
-    public int binarySearchLookup(String key) {
-      // this special case is the reason that Arrays.binarySearch() isn't useful.
-      if (key == null)
-        return 0;
-	  
-      int low = 1;
-      int high = lookup.length-1;
-
-      while (low <= high) {
-        int mid = (low + high) >>> 1;
-        int cmp = lookup[mid].compareTo(key);
-
-        if (cmp < 0)
-          low = mid + 1;
-        else if (cmp > 0)
-          high = mid - 1;
-        else
-          return mid; // key found
-      }
-      return -(low + 1);  // key not found.
-    }
-	
-    /** All the term values, in natural order. */
-    public final String[] lookup;
-
-    /** For each document, an index into the lookup array. */
-    public final int[] order;
 
-    /** Creates one of these objects */
+  /**
+   * Expert: Stores term text values and document ordering data.
+   * 
+   * @deprecated use StringIndexCacheKey.StringIndex
+   */
+  public static class StringIndex extends org.apache.lucene.search.StringIndex { 
     public StringIndex (int[] values, String[] lookup) {
-      this.order = values;
-      this.lookup = lookup;
+      super(values,lookup);
     }
   }
 
@@ -96,6 +72,7 @@
 
   /** Interface to parse bytes from document fields.
    * @see FieldCache#getBytes(IndexReader, String, FieldCache.ByteParser)
+   * @deprecated see ValueSource
    */
   public interface ByteParser extends Parser {
     /** Return a single Byte representation of this field's value. */
@@ -104,20 +81,13 @@
 
   /** Interface to parse shorts from document fields.
    * @see FieldCache#getShorts(IndexReader, String, FieldCache.ShortParser)
+   * @deprecated see ValueSource
    */
-  public interface ShortParser extends Parser {
-    /** Return a short representation of this field's value. */
+  public interface ShortParser extends Parser { 
+    /** Return an float representation of this field's value. */
     public short parseShort(String string);
   }
-
   /** Interface to parse ints from document fields.
-   * @see FieldCache#getInts(IndexReader, String, FieldCache.IntParser)
-   */
-  public interface IntParser extends Parser {
-    /** Return an integer representation of this field's value. */
-    public int parseInt(String string);
-  }
-
   /** Interface to parse floats from document fields.
    * @see FieldCache#getFloats(IndexReader, String, FieldCache.FloatParser)
    */
@@ -126,6 +96,14 @@
     public float parseFloat(String string);
   }
 
+  /** Interface to parse ints from document fields.
+   * @see FieldCache#getInts(IndexReader, String, FieldCache.IntParser)
+   */
+  public interface IntParser extends Parser {
+    /** Return an integer representation of this field's value. */
+    public int parseInt(String string);
+  }
+
   /** Expert: The cache used internally by sorting and range query classes. */
   public static FieldCache DEFAULT = new FieldCacheImpl();
 
@@ -137,6 +115,7 @@
    * @param field   Which field contains the single byte values.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public byte[] getBytes (IndexReader reader, String field)
   throws IOException;
@@ -150,6 +129,7 @@
    * @param parser  Computes byte for string values.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public byte[] getBytes (IndexReader reader, String field, ByteParser parser)
   throws IOException;
@@ -162,6 +142,7 @@
    * @param field   Which field contains the shorts.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public short[] getShorts (IndexReader reader, String field)
   throws IOException;
@@ -175,6 +156,7 @@
    * @param parser  Computes short for string values.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public short[] getShorts (IndexReader reader, String field, ShortParser parser)
   throws IOException;
@@ -187,6 +169,7 @@
    * @param field   Which field contains the integers.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public int[] getInts (IndexReader reader, String field)
   throws IOException;
@@ -200,6 +183,7 @@
    * @param parser  Computes integer for string values.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public int[] getInts (IndexReader reader, String field, IntParser parser)
   throws IOException;
@@ -212,6 +196,7 @@
    * @param field   Which field contains the floats.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public float[] getFloats (IndexReader reader, String field)
   throws IOException;
@@ -225,6 +210,7 @@
    * @param parser  Computes float for string values.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public float[] getFloats (IndexReader reader, String field,
                             FloatParser parser) throws IOException;
@@ -237,6 +223,7 @@
    * @param field   Which field contains the strings.
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public String[] getStrings (IndexReader reader, String field)
   throws IOException;
@@ -249,6 +236,7 @@
    * @param field   Which field contains the strings.
    * @return Array of terms and index into the array for each document.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public StringIndex getStringIndex (IndexReader reader, String field)
   throws IOException;
@@ -263,6 +251,7 @@
    * @param field   Which field contains the values.
    * @return int[], float[] or StringIndex.
    * @throws IOException  If any error occurs.
+   * @deprecated see ValueSource
    */
   public Object getAuto (IndexReader reader, String field)
   throws IOException;
@@ -277,8 +266,7 @@
    * @param comparator Used to convert terms into something to sort by.
    * @return Array of sort objects, one for each document.
    * @throws IOException  If any error occurs.
-   * @deprecated Please implement {@link
-   * FieldComparatorSource} directly, instead.
+   * @deprecated see ValueSource
    */
   public Comparable[] getCustom (IndexReader reader, String field, SortComparator comparator)
   throws IOException;
Index: src/java/org/apache/lucene/search/FieldCacheImpl.java
===================================================================
--- src/java/org/apache/lucene/search/FieldCacheImpl.java	(revision 765420)
+++ src/java/org/apache/lucene/search/FieldCacheImpl.java	(working copy)
@@ -17,33 +17,34 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermDocs;
-import org.apache.lucene.index.TermEnum;
-
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.search.UninversionValueSource.Uninverter;
+
 /**
- * Expert: The default cache implementation, storing all values in memory.
- * A WeakHashMap is used for storage.
- *
- * <p>Created: May 19, 2004 4:40:36 PM
- *
- * @since   lucene 1.4
+ * Expert: The default cache implementation, storing all values in memory. A
+ * WeakHashMap is used for storage.
+ * 
+ * <p>
+ * Created: May 19, 2004 4:40:36 PM
+ * 
+ * @since lucene 1.4
  * @version $Id$
+ * @deprecated see ValueSource
  */
-class FieldCacheImpl
-implements FieldCache {
-	
+class FieldCacheImpl implements FieldCache {
+
   /** Expert: Internal cache. */
   abstract static class Cache {
     private final Map readerCache = new WeakHashMap();
-    
+
     protected abstract Object createValue(IndexReader reader, Object key)
         throws IOException;
 
@@ -82,11 +83,16 @@
     }
   }
 
+  /** @deprecated */
   static final class CreationPlaceholder {
     Object value;
   }
 
-  /** Expert: Every composite-key in the internal cache is of this type. */
+  /**
+   * Expert: Every composite-key in the internal cache is of this type.
+   * 
+   * @deprecated
+   */
   static class Entry {
     final String field;        // which Fieldable
     final int type;            // which SortField type
@@ -109,8 +115,11 @@
       this.locale = null;
     }
 
-    /** Creates one of these objects for a custom type with parser, needed by FieldSortedHitQueue. */
-    Entry (String field, int type, Parser parser) {
+    /**
+     * Creates one of these objects for a custom type with parser, needed by
+     * FieldSortedHitQueue.
+     */
+    Entry(String field, int type, Parser parser) {
       this.field = field.intern();
       this.type = type;
       this.custom = parser;
@@ -118,14 +127,15 @@
     }
 
     /** Two of these are equal iff they reference the same field and type. */
-    public boolean equals (Object o) {
+    public boolean equals(Object o) {
       if (o instanceof Entry) {
         Entry other = (Entry) o;
         if (other.field == field && other.type == type) {
           if (other.locale == null ? locale == null : other.locale.equals(locale)) {
             if (other.custom == null) {
-              if (custom == null) return true;
-            } else if (other.custom.equals (custom)) {
+              if (custom == null)
+                return true;
+            } else if (other.custom.equals(custom)) {
               return true;
             }
           }
@@ -136,33 +146,33 @@
 
     /** Composes a hashcode based on the field and type. */
     public int hashCode() {
-      return field.hashCode() ^ type ^ (custom==null ? 0 : custom.hashCode()) ^ (locale==null ? 0 : locale.hashCode());
+      return field.hashCode() ^ type ^ (custom == null ? 0 : custom.hashCode())
+          ^ (locale == null ? 0 : locale.hashCode());
     }
   }
 
-  private static final ByteParser BYTE_PARSER = new ByteParser() {
+  static final ByteParser BYTE_PARSER = new ByteParser() {
     public byte parseByte(String value) {
       return Byte.parseByte(value);
     }
   };
 
-  private static final ShortParser SHORT_PARSER = new ShortParser() {
+  static final ShortParser SHORT_PARSER = new ShortParser() {
     public short parseShort(String value) {
       return Short.parseShort(value);
     }
   };
 
-  private static final IntParser INT_PARSER = new IntParser() {
-      public int parseInt(String value) {
-        return Integer.parseInt(value);
-      }
+  static final IntParser INT_PARSER = new IntParser() {
+    public int parseInt(String value) {
+      return Integer.parseInt(value);
+    }
   };
 
-
-  private static final FloatParser FLOAT_PARSER = new FloatParser() {
-      public float parseFloat(String value) {
-        return Float.parseFloat(value);
-      }
+  static final FloatParser FLOAT_PARSER = new FloatParser() {
+    public float parseFloat(String value) {
+      return Float.parseFloat(value);
+    }
   };
 
   // inherit javadocs
@@ -171,120 +181,111 @@
   }
 
   // inherit javadocs
-  public byte[] getBytes(IndexReader reader, String field, ByteParser parser)
+  public byte[] getBytes(final IndexReader reader, String field, final ByteParser parser)
       throws IOException {
-    return (byte[]) bytesCache.get(reader, new Entry(field, parser));
-  }
+    class ByteUninverter extends Uninverter {
+      private byte byteVal;
+      private byte[] retArray = new byte[reader.maxDoc()];
+      private Parser bparser = parser;
+      
+      void handleDoc(int index) {
+        retArray[index] = byteVal;
+      }
 
-  Cache bytesCache = new Cache() {
+      void newTerm(String value) {
+        this.byteVal = parser.parseByte(value);
+      }
+      
+      public int hashCode() {
+        return bparser.hashCode();
+      }
+      
+      public boolean equals(Object object ) {
+        return bparser.equals(((ByteUninverter)object).bparser);
+      }
 
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      ByteParser parser = (ByteParser) entry.custom;
-      final byte[] retArray = new byte[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          byte termval = parser.parseByte(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } catch (StopFillCacheException stop) {
-      } finally {
-        termDocs.close();
-        termEnum.close();
+      Object getArray() {
+        return retArray;
       }
-      return retArray;
-    }
-  };
-  
+    };
+    Uninverter parserUninverter = new ByteUninverter();
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getBytes(reader, field, parserUninverter);
+  }
+
   // inherit javadocs
   public short[] getShorts (IndexReader reader, String field) throws IOException {
     return getShorts(reader, field, SHORT_PARSER);
   }
 
   // inherit javadocs
-  public short[] getShorts(IndexReader reader, String field, ShortParser parser)
+  public short[] getShorts(final IndexReader reader, String field, final ShortParser parser)
       throws IOException {
-    return (short[]) shortsCache.get(reader, new Entry(field, parser));
-  }
+    class ShortUninverter extends Uninverter {
+      private short shortVal;
+      private short[] retArray = new short[reader.maxDoc()];
+      private Parser sparser = parser;
 
-  Cache shortsCache = new Cache() {
+      void handleDoc(int index) {
+        retArray[index] = shortVal;
+      }
 
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      ShortParser parser = (ShortParser) entry.custom;
-      final short[] retArray = new short[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          short termval = parser.parseShort(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } catch (StopFillCacheException stop) {
-      } finally {
-        termDocs.close();
-        termEnum.close();
+      void newTerm(String value) {
+        this.shortVal = parser.parseShort(value);
       }
-      return retArray;
-    }
-  };
-  
+      
+      public int hashCode() {
+        return sparser.hashCode();
+      }
+      
+      public boolean equals(Object object ) {
+        return sparser.equals(((ShortUninverter)object).sparser);
+      }
+      
+      Object getArray() {
+        return retArray;
+      }
+    };
+    Uninverter parserUninverter = new ShortUninverter();
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getShorts(reader, field, parserUninverter);
+  }
+
   // inherit javadocs
   public int[] getInts (IndexReader reader, String field) throws IOException {
     return getInts(reader, field, INT_PARSER);
   }
 
   // inherit javadocs
-  public int[] getInts(IndexReader reader, String field, IntParser parser)
+  public int[] getInts(final IndexReader reader, String field, final IntParser parser)
       throws IOException {
-    return (int[]) intsCache.get(reader, new Entry(field, parser));
-  }
+    class IntUninverter  extends Uninverter {
+      private int intVal;
+      private int[] retArray = new int[reader.maxDoc()];
+      private Parser iparser = parser;
 
-  Cache intsCache = new Cache() {
+      void handleDoc(int index) {
+        retArray[index] = intVal;
+      }
 
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      IntParser parser = (IntParser) entry.custom;
-      final int[] retArray = new int[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          int termval = parser.parseInt(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } catch (StopFillCacheException stop) {
-      } finally {
-        termDocs.close();
-        termEnum.close();
+      void newTerm(String value) {
+        this.intVal = parser.parseInt(value);
       }
-      return retArray;
-    }
-  };
+      
+      public int hashCode() {
+        return parser.hashCode();
+      }
+      
+      public boolean equals(Object object ) {
+        return iparser.equals(((IntUninverter)object).iparser);
+      }
 
+      Object getArray() {
+        return retArray;
+      }
+    };
+    Uninverter parserUninverter = new IntUninverter();
+
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getInts(reader, field, parserUninverter);
+  }
 
   // inherit javadocs
   public float[] getFloats (IndexReader reader, String field)
@@ -293,136 +294,50 @@
   }
 
   // inherit javadocs
-  public float[] getFloats(IndexReader reader, String field, FloatParser parser)
+  public float[] getFloats(final IndexReader reader, String field, final FloatParser parser)
       throws IOException {
-    return (float[]) floatsCache.get(reader, new Entry(field, parser));
-  }
+    class FloatUninverter extends Uninverter {
+      private float floatVal;
+      private float[] retArray = new float[reader.maxDoc()];
+      private Parser fparser = parser;
+      
+      void handleDoc(int index) {
+        retArray[index] = floatVal;
+      }
 
-  Cache floatsCache = new Cache() {
+      void newTerm(String value) {
+        this.floatVal = parser.parseFloat(value);
+      }
 
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      FloatParser parser = (FloatParser) entry.custom;
-      final float[] retArray = new float[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          float termval = parser.parseFloat(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } catch (StopFillCacheException stop) {
-      } finally {
-        termDocs.close();
-        termEnum.close();
+      public int hashCode() {
+        return parser.hashCode();
       }
-      return retArray;
-    }
-  };
+      
+      public boolean equals(Object object ) {
+        return fparser.equals(((FloatUninverter)object).fparser);
+      }
+      
+      Object getArray() {
+        return retArray;
+      }
+    };
+    Uninverter parserUninverter = new FloatUninverter();
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getFloats(reader, field, parserUninverter);
+  }
 
   // inherit javadocs
   public String[] getStrings(IndexReader reader, String field)
       throws IOException {
-    return (String[]) stringsCache.get(reader, field);
+    return CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getStrings(reader, field);
   }
 
-  Cache stringsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object fieldKey)
-        throws IOException {
-      String field = ((String) fieldKey).intern();
-      final String[] retArray = new String[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          String termval = term.text();
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-
   // inherit javadocs
   public StringIndex getStringIndex(IndexReader reader, String field)
       throws IOException {
-    return (StringIndex) stringsIndexCache.get(reader, field);
+    org.apache.lucene.search.StringIndex stringIndex = CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getStringIndex(reader, field);
+    return new StringIndex(stringIndex.order, stringIndex.lookup);
   }
 
-  Cache stringsIndexCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object fieldKey)
-        throws IOException {
-      String field = ((String) fieldKey).intern();
-      final int[] retArray = new int[reader.maxDoc()];
-      String[] mterms = new String[reader.maxDoc()+1];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      int t = 0;  // current term number
-
-      // an entry for documents that have no terms in this field
-      // should a document with no terms be at top or bottom?
-      // this puts them at the top - if it is changed, FieldDocSortedHitQueue
-      // needs to change as well.
-      mterms[t++] = null;
-
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-
-          // store term text
-          // we expect that there is at most one term per document
-          if (t >= mterms.length) throw new RuntimeException ("there are more terms than " +
-                  "documents in field \"" + field + "\", but it's impossible to sort on " +
-                  "tokenized fields");
-          mterms[t] = term.text();
-
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = t;
-          }
-
-          t++;
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-
-      if (t == 0) {
-        // if there are no terms, make the term array
-        // have a single null entry
-        mterms = new String[1];
-      } else if (t < mterms.length) {
-        // if there are less terms than documents,
-        // trim off the dead array space
-        String[] terms = new String[t];
-        System.arraycopy (mterms, 0, terms, 0, t);
-        mterms = terms;
-      }
-
-      StringIndex value = new StringIndex (retArray, mterms);
-      return value;
-    }
-  };
-
   /** The pattern used to detect integer values in a field */
   /** removed for java 1.3 compatibility
    protected static final Pattern pIntegers = Pattern.compile ("[0-9\\-]+");
@@ -434,28 +349,21 @@
    * protected static final Object pFloats = Pattern.compile ("[0-9+\\-\\.eEfFdD]+");
    */
 
-	// inherit javadocs
+  // inherit javadocs
   public Object getAuto(IndexReader reader, String field) throws IOException {
-    return autoCache.get(reader, field);
-  }
-
-  Cache autoCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object fieldKey)
-        throws IOException {
-      String field = ((String)fieldKey).intern();
-      TermEnum enumerator = reader.terms (new Term (field));
-      try {
-        Term term = enumerator.term();
-        if (term == null) {
-          throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
-        }
-        Object ret = null;
-        if (term.field() == field) {
-          String termtext = term.text().trim();
+    field = ((String)field).intern();
+    TermEnum enumerator = reader.terms (new Term (field));
+    try {
+      Term term = enumerator.term();
+      if (term == null) {
+        throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
+      }
+      Object ret = null;
+      if (term.field() == field) {
+        String termtext = term.text().trim();
 
-          /**
-           * Java 1.4 level code:
+        /**
+         * Java 1.4 level code:
 
            if (pIntegers.matcher(termtext).matches())
            return IntegerSortedHitQueue.comparator (reader, enumerator, field);
@@ -483,42 +391,12 @@
       } finally {
         enumerator.close();
       }
-    }
-  };
+  }
 
   // inherit javadocs
   public Comparable[] getCustom(IndexReader reader, String field,
       SortComparator comparator) throws IOException {
-    return (Comparable[]) customCache.get(reader, new Entry(field, comparator));
+    return CacheByReaderValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getComparables(reader, field, comparator);
   }
 
-  Cache customCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      SortComparator comparator = (SortComparator) entry.custom;
-      final Comparable[] retArray = new Comparable[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          Comparable termval = comparator.getComparable (term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-  
 }
-
Index: src/java/org/apache/lucene/search/FieldComparator.java
===================================================================
--- src/java/org/apache/lucene/search/FieldComparator.java	(revision 765420)
+++ src/java/org/apache/lucene/search/FieldComparator.java	(working copy)
@@ -28,7 +28,7 @@
 import org.apache.lucene.search.FieldCache.FloatParser;
 import org.apache.lucene.search.FieldCache.IntParser;
 import org.apache.lucene.search.FieldCache.ShortParser;
-import org.apache.lucene.search.FieldCache.StringIndex;
+import org.apache.lucene.search.UninversionValueSource.Uninverter;
 
 /**
  * A FieldComparator compares hits across multiple IndexReaders.
@@ -46,18 +46,46 @@
   /** Parses field's values as byte (using {@link
    *  FieldCache#getBytes} and sorts by ascending value */
   public static final class ByteComparator extends FieldComparator {
+    private final static int TYPE = SortField.BYTE;
     private final byte[] values;
     private byte[] currentReaderValues;
     private final String field;
-    private ByteParser parser;
+    private ValueSource valueSource;
     private byte bottom;
+    private CachingByReaderUninverterValueSource uninversionValueSource;
+    private Uninverter parserUninverter;
 
-    ByteComparator(int numHits, String field, FieldCache.Parser parser) {
+    ByteComparator(int numHits, String field, ValueSource valueSource) {
       values = new byte[numHits];
       this.field = field;
-      this.parser = (ByteParser) parser;
+      this.valueSource = valueSource;
     }
 
+    /**
+     * @deprecated
+     */
+    ByteComparator(final int numHits, String field, CachingByReaderUninverterValueSource valueSource, final ByteParser byteParser) {
+      values = new byte[numHits];
+      this.field = field;
+
+      uninversionValueSource =  (CachingByReaderUninverterValueSource) valueSource;
+      this.parserUninverter = new Uninverter(){
+        private byte byteVal;
+        private byte[] retArray = new byte[numHits];
+
+        void handleDoc(int index) {
+          retArray[index] = byteVal;
+        }
+
+        void newTerm(String value) {
+          this.byteVal = byteParser.parseByte(value);
+        }
+
+        Object getArray() {
+          return retArray;
+        }};
+    }
+
     public int compare(int slot1, int slot2) {
       return values[slot1] - values[slot2];
     }
@@ -70,18 +98,25 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
-        .getBytes(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
-        .getBytes(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      
+      // nocommit: handle this better?
+      if(parserUninverter != null) {
+        currentReaderValues = uninversionValueSource.getBytes(reader, field, parserUninverter);
+      } else if(valueSource != null) {
+        currentReaderValues = valueSource.getBytes(reader, field);
+      } else {
+        currentReaderValues = reader.getValueSource().getBytes(reader, field);
+      }
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
 
     public int sortType() {
-      return SortField.BYTE;
+      return TYPE;
     }
 
     public Comparable value(int slot) {
@@ -136,16 +171,44 @@
   /** Parses field's values as double (using {@link
    *  ExtendedFieldCache#getDoubles} and sorts by ascending value */
   public static final class DoubleComparator extends FieldComparator {
+    private final static int TYPE = SortField.DOUBLE;
     private final double[] values;
     private double[] currentReaderValues;
     private final String field;
-    private DoubleParser parser;
+    private ValueSource valueSource;
     private double bottom;
+    private Uninverter parserUninverter;
+    private CachingByReaderUninverterValueSource uninversionValueSource;
+
+    DoubleComparator(int numHits, String field, ValueSource valueSource) {
+      values = new double[numHits];
+      this.field = field;
+      this.valueSource = valueSource;
+    }
 
-    DoubleComparator(int numHits, String field, FieldCache.Parser parser) {
+    /**
+     * @deprecated
+     */
+    DoubleComparator(final int numHits, String field, CachingByReaderUninverterValueSource valueSource, final DoubleParser doubleParser) {
       values = new double[numHits];
       this.field = field;
-      this.parser = (DoubleParser) parser;
+
+      uninversionValueSource =  (CachingByReaderUninverterValueSource) valueSource;
+      this.parserUninverter = new Uninverter(){
+        private double doubleVal;
+        private double[] retArray = new double[numHits];
+
+        void handleDoc(int index) {
+          retArray[index] = doubleVal;
+        }
+
+        void newTerm(String value) {
+          this.doubleVal = doubleParser.parseDouble(value);
+        }
+
+        Object getArray() {
+          return retArray;
+        }};
     }
 
     public int compare(int slot1, int slot2) {
@@ -175,38 +238,72 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
-      currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
-          .getDoubles(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
-          .getDoubles(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      // nocommit: handle this better?
+      if(parserUninverter != null) {
+        currentReaderValues = uninversionValueSource.getDoubles(reader, field, parserUninverter);
+      } else if(valueSource != null) {
+        currentReaderValues = valueSource.getDoubles(reader, field);
+      } else {
+        currentReaderValues = reader.getValueSource().getDoubles(reader, field);
+      }
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
 
     public int sortType() {
-      return SortField.DOUBLE;
+      return TYPE;
     }
 
     public Comparable value(int slot) {
       return new Double(values[slot]);
     }
-  }
+  };
 
   /** Parses field's values as float (using {@link
    *  FieldCache#getFloats} and sorts by ascending value */
   public static final class FloatComparator extends FieldComparator {
+    private final static int TYPE = SortField.FLOAT;
     private final float[] values;
     private float[] currentReaderValues;
     private final String field;
-    private FloatParser parser;
+    private ValueSource valueSource;
     private float bottom;
+    private CachingByReaderUninverterValueSource uninversionValueSource;
+    private Uninverter parserUninverter;
+
+    FloatComparator(int numHits, String field, ValueSource valueSource) {
+      values = new float[numHits];
+      this.field = field;
+      this.valueSource = valueSource;
+    }
 
-    FloatComparator(int numHits, String field, FieldCache.Parser parser) {
+    /**
+     * @deprecated
+     */
+    FloatComparator(final int numHits, String field, CachingByReaderUninverterValueSource valueSource, final FloatParser floatParser) {
       values = new float[numHits];
       this.field = field;
-      this.parser = (FloatParser) parser;
+
+      uninversionValueSource = (CachingByReaderUninverterValueSource) valueSource;
+      this.parserUninverter = new Uninverter(){
+        private float floatVal;
+        private float[] retArray = new float[numHits];
+
+        void handleDoc(int index) {
+          retArray[index] = floatVal;
+        }
+
+        void newTerm(String value) {
+          this.floatVal = floatParser.parseFloat(value);
+        }
+
+        Object getArray() {
+          return retArray;
+        }};
     }
 
     public int compare(int slot1, int slot2) {
@@ -240,37 +337,72 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      currentReaderValues = parser != null ? FieldCache.DEFAULT.getFloats(
-          reader, field, parser) : FieldCache.DEFAULT.getFloats(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      // nocommit: handle this better?
+      if(parserUninverter != null) {
+        currentReaderValues = uninversionValueSource.getFloats(reader, field, parserUninverter);
+      } else if(valueSource != null) {
+        currentReaderValues = valueSource.getFloats(reader, field);
+      } else {
+        currentReaderValues = reader.getValueSource().getFloats(reader, field);
+      }
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
 
     public int sortType() {
-      return SortField.FLOAT;
+      return TYPE;
     }
 
     public Comparable value(int slot) {
       return new Float(values[slot]);
     }
-  }
+  };
 
   /** Parses field's values as int (using {@link
    *  FieldCache#getInts} and sorts by ascending value */
   public static final class IntComparator extends FieldComparator {
+    private final static int TYPE = SortField.INT;
     private final int[] values;
     private int[] currentReaderValues;
     private final String field;
-    private IntParser parser;
-    private int bottom;                           // Value of bottom of queue
+    private int bottom; // Value of bottom of queue
+    private ValueSource valueSource;
+    private Uninverter parserUninverter;
+    private CachingByReaderUninverterValueSource uninversionValueSource;
+
+    IntComparator(int numHits, String field, ValueSource valueSource) {
+      values = new int[numHits];
+      this.field = field;
+      this.valueSource = valueSource;
+    }
 
-    IntComparator(int numHits, String field, FieldCache.Parser parser) {
+    /**
+     * @deprecated see IntComparator(int numHits, String field)
+     */
+    public IntComparator(final int numHits, String field, CachingByReaderUninverterValueSource valueSource, final IntParser parser) {
       values = new int[numHits];
       this.field = field;
-      this.parser = (IntParser) parser;
+
+      uninversionValueSource =  (CachingByReaderUninverterValueSource) valueSource;
+      this.parserUninverter = new Uninverter(){
+        private int intVal;
+        private int[] retArray = new int[numHits];
+
+        void handleDoc(int index) {
+          retArray[index] = intVal;
+        }
+
+        void newTerm(String value) {
+          this.intVal = parser.parseInt(value);
+        }
+
+        Object getArray() {
+          return retArray;
+        }};
     }
 
     public int compare(int slot1, int slot2) {
@@ -308,37 +440,73 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      currentReaderValues = parser != null ? FieldCache.DEFAULT.getInts(reader,
-          field, parser) : FieldCache.DEFAULT.getInts(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      // nocommit: handle this better?
+      if(parserUninverter != null) {
+        currentReaderValues = uninversionValueSource.getInts(reader, field, parserUninverter);
+      } else if(valueSource != null) {
+        currentReaderValues = valueSource.getInts(reader, field);
+      } else {
+        currentReaderValues = reader.getValueSource().getInts(reader, field);
+      }
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
 
     public int sortType() {
-      return SortField.INT;
+      return TYPE;
     }
 
     public Comparable value(int slot) {
       return new Integer(values[slot]);
     }
-  }
+  };
 
   /** Parses field's values as long (using {@link
    *  ExtendedFieldCache#getLongs} and sorts by ascending value */
   public static final class LongComparator extends FieldComparator {
+    private static final int TYPE = SortField.LONG;
     private final long[] values;
     private long[] currentReaderValues;
     private final String field;
-    private LongParser parser;
+    private ValueSource valueSource;
     private long bottom;
+    private Uninverter parserUninverter;
+    private CachingByReaderUninverterValueSource uninversionValueSource;
 
-    LongComparator(int numHits, String field, FieldCache.Parser parser) {
+    LongComparator(int numHits, String field, ValueSource valueSource) {
       values = new long[numHits];
       this.field = field;
-      this.parser = (LongParser) parser;
+      this.valueSource = valueSource;
+    }
+
+    /**
+     * @deprecated
+     */
+    LongComparator(final int numHits, String field, CachingByReaderUninverterValueSource valueSource, final LongParser longParser) {
+      values = new long[numHits];
+      this.field = field;
+
+      uninversionValueSource =  (CachingByReaderUninverterValueSource)  valueSource;
+      this.parserUninverter = new Uninverter() {
+        private long longVal;
+        private long[] retArray = new long[numHits];
+
+        void handleDoc(int index) {
+          retArray[index] = longVal;
+        }
+
+        void newTerm(String value) {
+          this.longVal = longParser.parseLong(value);
+        }
+
+        Object getArray() {
+          return retArray;
+        }
+      };
     }
 
     public int compare(int slot1, int slot2) {
@@ -372,18 +540,24 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
-          .getLongs(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
-          .getLongs(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      // nocommit: handle this better?
+      if(parserUninverter != null) {
+        currentReaderValues = uninversionValueSource.getLongs(reader, field, parserUninverter);
+      } else if(valueSource != null) {
+        currentReaderValues = valueSource.getLongs(reader, field);
+      } else {
+        currentReaderValues = reader.getValueSource().getLongs(reader, field);
+      }
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
 
     public int sortType() {
-      return SortField.LONG;
+      return TYPE;
     }
 
     public Comparable value(int slot) {
@@ -443,19 +617,50 @@
     }
   }
 
-  /** Parses field's values as short (using {@link
-   *  FieldCache#getShorts} and sorts by ascending value */
+  /**
+   * Parses field's values as short (using {@link FieldCache#getShorts} and
+   * sorts by ascending value
+   */
   public static final class ShortComparator extends FieldComparator {
+    private final static int TYPE = SortField.SHORT;
     private final short[] values;
     private short[] currentReaderValues;
     private final String field;
-    private ShortParser parser;
+    private ValueSource valueSource;
     private short bottom;
+    private CachingByReaderUninverterValueSource uninversionValueSource;
+    private Uninverter parserUninverter;
+
+    ShortComparator(int numHits, String field, ValueSource valueSource) {
+      values = new short[numHits];
+      this.field = field;
+      this.valueSource = valueSource;
+    }
 
-    ShortComparator(int numHits, String field, FieldCache.Parser parser) {
+    /**
+     * @deprecated
+     */
+    ShortComparator(final int numHits, String field, CachingByReaderUninverterValueSource valueSource, final ShortParser shortParser) {
       values = new short[numHits];
       this.field = field;
-      this.parser = (ShortParser) parser;
+
+      uninversionValueSource =  (CachingByReaderUninverterValueSource) valueSource;
+      this.parserUninverter = new Uninverter() {
+        private short shortVal;
+        private short[] retArray = new short[numHits];
+
+        void handleDoc(int index) {
+          retArray[index] = shortVal;
+        }
+
+        void newTerm(String value) {
+          this.shortVal = shortParser.parseShort(value);
+        }
+
+        Object getArray() {
+          return retArray;
+        }
+      };
     }
 
     public int compare(int slot1, int slot2) {
@@ -470,27 +675,34 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      currentReaderValues = parser != null ? ExtendedFieldCache.EXT_DEFAULT
-          .getShorts(reader, field, parser) : ExtendedFieldCache.EXT_DEFAULT
-          .getShorts(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      // nocommit: handle this better?
+      if(parserUninverter != null) {
+        currentReaderValues = uninversionValueSource.getShorts(reader, field, parserUninverter);
+      } else if(valueSource != null) {
+        currentReaderValues = valueSource.getShorts(reader, field);
+      } else {
+        currentReaderValues = reader.getValueSource().getShorts(reader, field);
+      }
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
 
     public int sortType() {
-      return SortField.BYTE;
+      return TYPE;
     }
 
     public Comparable value(int slot) {
       return new Short(values[slot]);
     }
-  }
+  };
 
-  /** Sorts by a field's value using the Collator for a
-   *  given Locale.*/
+  /**
+   * Sorts by a field's value using the Collator for a given Locale.
+   */
   public static final class StringComparatorLocale extends FieldComparator {
 
     private final String[] values;
@@ -498,6 +710,7 @@
     private final String field;
     final Collator collator;
     private String bottom;
+    private ValueSource valueSource;
 
     StringComparatorLocale(int numHits, String field, Locale locale) {
       values = new String[numHits];
@@ -536,9 +749,9 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      currentReaderValues = ExtendedFieldCache.EXT_DEFAULT.getStrings(reader,
-          field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      currentReaderValues =  reader.getValueSource().getStrings(reader, field);
     }
     
     public void setBottom(final int bottom) {
@@ -573,14 +786,17 @@
     private String bottomValue;
     private final boolean reversed;
     private final int sortPos;
+    private ValueSource valueSource;
 
-    public StringOrdValComparator(int numHits, String field, int sortPos, boolean reversed) {
+    public StringOrdValComparator(int numHits, String field, int sortPos,
+        boolean reversed) {
       ords = new int[numHits];
       values = new String[numHits];
       readerGen = new int[numHits];
       this.sortPos = sortPos;
       this.reversed = reversed;
       this.field = field;
+
     }
 
     public int compare(int slot1, int slot2) {
@@ -663,8 +879,10 @@
       readerGen[slot] = currentReaderGen;
     }
 
-    public void setNextReader(IndexReader reader, int docBase,  int numSlotsFull) throws IOException {
-      StringIndex currentReaderValues = ExtendedFieldCache.EXT_DEFAULT.getStringIndex(reader, field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      valueSource = reader.getValueSource();
+      StringIndex currentReaderValues = valueSource.getStringIndex(reader, field);
       currentReaderGen++;
       order = currentReaderValues.order;
       lookup = currentReaderValues.lookup;
@@ -705,7 +923,7 @@
     public String getField() {
       return field;
     }
-  }
+  };
 
   /** Sorts by field's natural String sort order.  All
    *  comparisons are done using String.compareTo, which is
@@ -755,11 +973,11 @@
       values[slot] = currentReaderValues[doc];
     }
 
-    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
-      currentReaderValues = ExtendedFieldCache.EXT_DEFAULT.getStrings(reader,
-          field);
+    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull)
+        throws IOException {
+      currentReaderValues =  reader.getValueSource().getStrings(reader, field);
     }
-    
+
     public void setBottom(final int bottom) {
       this.bottom = values[bottom];
     }
Index: src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java	(revision 765420)
+++ src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java	(working copy)
@@ -133,6 +133,7 @@
         case SortField.STRING:{
 					String s1 = (String) docA.fields[i];
 					String s2 = (String) docB.fields[i];
+					//TODO: update javadoc
 					// null values need to be sorted first, because of how FieldCache.getStringIndex()
 					// works - in that routine, any documents without a value in the given field are
 					// put first.  If both are null, the next SortField is used
@@ -188,6 +189,7 @@
 					throw new RuntimeException ("invalid SortField type: "+type);
         }
       }
+
 			if (fields[i].getReverse()) {
 				c = -c;
 			}
Index: src/java/org/apache/lucene/search/SortComparator.java
===================================================================
--- src/java/org/apache/lucene/search/SortComparator.java	(revision 765420)
+++ src/java/org/apache/lucene/search/SortComparator.java	(working copy)
@@ -17,10 +17,10 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.index.IndexReader;
-
 import java.io.IOException;
 
+import org.apache.lucene.index.IndexReader;
+
 /**
  * Abstract base class for sorting hits returned by a Query.
  *
@@ -43,11 +43,15 @@
 public abstract class SortComparator
 implements SortComparatorSource {
 
-  // inherit javadocs
+  
+  /* (non-Javadoc)
+   * @see org.apache.lucene.search.SortComparatorSource#newComparator(org.apache.lucene.index.IndexReader, java.lang.String)
+   */
   public ScoreDocComparator newComparator (final IndexReader reader, final String fieldname)
   throws IOException {
     final String field = fieldname.intern();
-    final Comparable[] cachedValues = FieldCache.DEFAULT.getCustom (reader, field, SortComparator.this);
+    // nocommit: check
+    final Comparable[] cachedValues = CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE.getComparables(reader, field, SortComparator.this);
     
     return new ScoreDocComparator() {
 
Index: src/java/org/apache/lucene/search/SortField.java
===================================================================
--- src/java/org/apache/lucene/search/SortField.java	(revision 765420)
+++ src/java/org/apache/lucene/search/SortField.java	(working copy)
@@ -21,6 +21,14 @@
 import java.io.Serializable;
 import java.util.Locale;
 
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.ExtendedFieldCache.DoubleParser;
+import org.apache.lucene.search.ExtendedFieldCache.LongParser;
+import org.apache.lucene.search.FieldCache.ByteParser;
+import org.apache.lucene.search.FieldCache.FloatParser;
+import org.apache.lucene.search.FieldCache.IntParser;
+import org.apache.lucene.search.FieldCache.ShortParser;
+
 /**
  * Stores information about how to sort documents by terms in an individual
  * field.  Fields must be indexed in order to sort by them.
@@ -108,6 +116,9 @@
 
   private boolean useLegacy = false; // remove in Lucene 3.0
 
+  ValueSource valueSource;
+  
+
   /** Creates a sort by terms in the given field where the type of term value
    * is determined dynamically ({@link #AUTO AUTO}).
    * @param field Name of field to sort by, cannot be <code>null</code>.
@@ -254,6 +265,21 @@
     this.comparatorSource = comparator;
   }
 
+  public SortField(String field, FieldComparatorSource comparator,
+      ValueSource valueSource, boolean reverse) {
+    initFieldType(field, CUSTOM);
+    this.reverse = reverse;
+    this.comparatorSource = comparator;
+    this.valueSource = valueSource;
+  }
+
+  public SortField(String field, int type, ValueSource valueSource,
+      boolean reverse) {
+    initFieldType(field, type);
+    this.reverse = reverse;
+    this.valueSource = valueSource;
+  }
+
   // Sets field & type, and ensures field is not NULL unless
   // type is SCORE or DOC
   private void initFieldType(String field, int type) {
@@ -431,7 +457,13 @@
   }
 
 
+//  protected FieldComparator getComparator(final IndexReader[] subReaders, final int numHits, final int sortPos, final boolean reversed) throws IOException {
+//    return getComparator(subReaders, numHits, sortPos, reversed);
+//  }
+  
   /** Returns the {@link FieldComparator} to use for sorting.
+   * @param subReaders array of {@link IndexReader} search
+   *   will step through
    * @param numHits number of top hits the queue will store
    * @param sortPos position of this SortField within {@link
    *   Sort}.  The comparator is primary if sortPos==0,
@@ -441,7 +473,7 @@
    * @return {@link FieldComparator} to use when sorting
    */
   protected FieldComparator getComparator(final int numHits, final int sortPos, final boolean reversed) throws IOException {
-
+    CachingByReaderUninverterValueSource cbrValueSource = CachingByReaderUninverterValueSource.DEFAULT_CACHE_BY_READER_VALUE_SOURCE;
     if (locale != null) {
       // TODO: it'd be nice to allow FieldCache.getStringIndex
       // to optionally accept a Locale so sorting could then use
@@ -457,22 +489,46 @@
       return new FieldComparator.DocComparator(numHits);
 
     case SortField.INT:
-      return new FieldComparator.IntComparator(numHits, field, parser);
+      if(parser == null) {
+        return new FieldComparator.IntComparator(numHits, field, valueSource);
+      } else {
+        return new FieldComparator.IntComparator(numHits, field, cbrValueSource, (IntParser) parser);
+      }
 
     case SortField.FLOAT:
-      return new FieldComparator.FloatComparator(numHits, field, parser);
+      if(parser == null) {
+        return new FieldComparator.FloatComparator(numHits, field, valueSource);
+      } else {
+        return new FieldComparator.FloatComparator(numHits, field, cbrValueSource, (FloatParser) parser);
+      }
 
     case SortField.LONG:
-      return new FieldComparator.LongComparator(numHits, field, parser);
+      if(parser == null) {
+        return new FieldComparator.LongComparator(numHits, field, valueSource);
+      } else {
+        return new FieldComparator.LongComparator(numHits, field, cbrValueSource, (LongParser) parser);
+      }
 
     case SortField.DOUBLE:
-      return new FieldComparator.DoubleComparator(numHits, field, parser);
+      if(parser == null) {
+        return new FieldComparator.DoubleComparator(numHits, field, valueSource);
+      } else {
+        return new FieldComparator.DoubleComparator(numHits, field, cbrValueSource, (DoubleParser) parser);
+      }
 
     case SortField.BYTE:
-      return new FieldComparator.ByteComparator(numHits, field, parser);
+      if(parser == null) {
+        return new FieldComparator.ByteComparator(numHits, field, valueSource);
+      } else {
+        return new FieldComparator.ByteComparator(numHits, field, cbrValueSource, (ByteParser) parser);
+      }
 
     case SortField.SHORT:
-      return new FieldComparator.ShortComparator(numHits, field, parser);
+      if(parser == null) {
+        return new FieldComparator.ShortComparator(numHits, field, valueSource);
+      } else {
+        return new FieldComparator.ShortComparator(numHits, field, cbrValueSource, (ShortParser) parser);
+      }
 
     case SortField.CUSTOM:
       assert factory == null && comparatorSource != null;
Index: src/java/org/apache/lucene/search/StringIndex.java
===================================================================
--- src/java/org/apache/lucene/search/StringIndex.java	(revision 0)
+++ src/java/org/apache/lucene/search/StringIndex.java	(revision 0)
@@ -0,0 +1,40 @@
+package org.apache.lucene.search;
+/**
+ * A String array and indexes into the array.
+ */
+public class StringIndex {
+
+  /** All the term values, in natural order. */
+  public final String[] lookup;
+
+  /** For each document, an index into the lookup array. */
+  public final int[] order;
+
+  /** Creates one of these objects */
+  public StringIndex(int[] values, String[] lookup) {
+    this.order = values;
+    this.lookup = lookup;
+  }
+  
+  public int binarySearchLookup(String key) {
+    // this special case is the reason that Arrays.binarySearch() isn't useful.
+    if (key == null)
+      return 0;
+  
+    int low = 1;
+    int high = lookup.length-1;
+
+    while (low <= high) {
+      int mid = (low + high) >>> 1;
+      int cmp = lookup[mid].compareTo(key);
+
+      if (cmp < 0)
+        low = mid + 1;
+      else if (cmp > 0)
+        high = mid - 1;
+      else
+        return mid; // key found
+    }
+    return -(low + 1);  // key not found.
+  }
+}
Index: src/java/org/apache/lucene/search/UninversionValueSource.java
===================================================================
--- src/java/org/apache/lucene/search/UninversionValueSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/UninversionValueSource.java	(revision 0)
@@ -0,0 +1,350 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.TermEnum;
+
+public class UninversionValueSource extends ValueSource {
+
+  public byte[] getBytes(IndexReader reader, String field)
+      throws IOException {
+
+    final byte[] retArray = new byte[reader.maxDoc()];
+
+    Uninverter byteUninverter = new AnonUninverter() {
+      private byte byteVal;
+
+      void handleDoc(int index) {
+        retArray[index] = byteVal;
+      }
+
+      void newTerm(String value) {
+        this.byteVal = Byte.parseByte(value);
+      }
+    };
+
+    byteUninverter.go(reader, field);
+    return retArray;
+  }
+
+  public byte[] getBytes(IndexReader reader, String field,
+      Uninverter uninverter) throws IOException {
+
+    uninverter.go(reader, field);
+    return (byte[]) uninverter.getArray();
+  }
+
+  public double[] getDoubles(IndexReader reader, String field)
+      throws IOException {
+    final double[] retArray = new double[reader.maxDoc()];
+    Uninverter doubleUniverter = new AnonUninverter() {
+      private double doubleVal;
+
+      void handleDoc(int index) {
+        retArray[index] = doubleVal;
+      }
+
+      void newTerm(String value) {
+        this.doubleVal = Double.parseDouble(value);
+      }
+      
+      public int hashCode() {
+        return 1;
+      }
+    };
+
+    doubleUniverter.go(reader, field);
+    return retArray;
+  }
+
+  // nocommit: these calls will skip caching
+  public double[] getDoubles(IndexReader reader, String field,
+      Uninverter uninverter) throws IOException {
+
+    uninverter.go(reader, field);
+    return (double[]) uninverter.getArray();
+  }
+
+  public float[] getFloats(IndexReader reader, String field)
+      throws IOException {
+    final float[] retArray = new float[reader.maxDoc()];
+
+    Uninverter floatUninverter = new AnonUninverter() {
+      private float floatVal;
+
+      void handleDoc(int index) {
+        retArray[index] = floatVal;
+      }
+
+      void newTerm(String value) {
+        this.floatVal = Float.parseFloat(value);
+      }
+    };
+    floatUninverter.go(reader, field);
+    return retArray;
+  }
+
+  // nocommit: these calls will skip caching
+  public float[] getFloats(IndexReader reader, String field,
+      Uninverter uninverter) throws IOException {
+
+    uninverter.go(reader, field);
+    return (float[]) uninverter.getArray();
+  }
+
+  public int[] getInts(IndexReader reader, String field)
+      throws IOException {
+
+    final int[] retArray = new int[reader.maxDoc()];
+
+    Uninverter intUninverter = new AnonUninverter() {
+      private int intVal;
+
+      void handleDoc(int index) {
+        retArray[index] = intVal;
+      }
+
+      void newTerm(String value) {
+        this.intVal = Integer.parseInt(value);
+      }
+      
+      public int hashCode() {
+        return 1;
+      }
+    };
+
+    intUninverter.go(reader, field);
+    return retArray;
+  }
+
+  // nocommit: these calls will skip caching
+  public int[] getInts(IndexReader reader, String field,
+      Uninverter uninverter) throws IOException {
+
+    uninverter.go(reader, field);
+    return (int[]) uninverter.getArray();
+  }
+
+  public long[] getLongs(IndexReader reader, String field)
+      throws IOException {
+    final long[] retArray = new long[reader.maxDoc()];
+    Uninverter longUninverter = new AnonUninverter() {
+      private long intVal;
+
+      void handleDoc(int index) {
+        retArray[index] = intVal;
+      }
+
+      void newTerm(String value) {
+        this.intVal = Long.parseLong(value);
+      }
+    };
+
+    longUninverter.go(reader, field);
+    return retArray;
+  }
+
+  // nocommit: these calls will skip caching
+  public long[] getLongs(IndexReader reader, String field,
+      Uninverter uninverter) throws IOException {
+
+    uninverter.go(reader, field);
+    return (long[]) uninverter.getArray();
+  }
+
+  public short[] getShorts(IndexReader reader, String field)
+      throws IOException {
+    final short[] retArray = new short[reader.maxDoc()];
+    Uninverter shortUninverter = new AnonUninverter() {
+      private short shortVal;
+
+      void handleDoc(int index) {
+        retArray[index] = shortVal;
+      }
+
+      void newTerm(String value) {
+        this.shortVal = Short.parseShort(value);
+      }
+    };
+    shortUninverter.go(reader, field);
+    return retArray;
+  }
+
+  // nocommit: these calls will skip caching
+  public short[] getShorts(IndexReader reader, String field,
+      Uninverter uninverter) throws IOException {
+
+    uninverter.go(reader, field);
+    return (short[]) uninverter.getArray();
+  }
+
+  /**
+   * @deprecated //nocommit
+   */
+  public Comparable[] getComparables(IndexReader reader, String field,
+      final SortComparator comparator) throws IOException {
+    final Comparable[] retArray = new Comparable[reader.maxDoc()];
+    Uninverter comparableUninverter = new AnonUninverter() {
+      private Comparable comparableVal;
+
+      void handleDoc(int index) {
+        retArray[index] = comparableVal;
+      }
+
+      void newTerm(String value) {
+        this.comparableVal = value;
+      }
+
+      void go(IndexReader reader, String field) throws IOException {
+        field = field.intern();
+        TermDocs termDocs = reader.termDocs();
+        TermEnum termEnum = reader.terms(new Term(field));
+        try {
+          do {
+            Term term = termEnum.term();
+            if (term == null || term.field() != field)
+              break;
+            Comparable termval = comparator.getComparable(term.text());
+            termDocs.seek(termEnum);
+            while (termDocs.next()) {
+              retArray[termDocs.doc()] = termval;
+            }
+          } while (termEnum.next());
+        } finally {
+          termDocs.close();
+          termEnum.close();
+        }
+      }
+
+    };
+    comparableUninverter.go(reader, field);
+    return retArray;
+  };
+
+  public StringIndex getStringIndex(final IndexReader reader, String field)
+      throws IOException {
+    final int[] retArray = new int[reader.maxDoc()];
+    class StringIndexUninverter extends AnonUninverter {
+
+      String[] mterms = new String[reader.maxDoc() + 1];
+
+      void go(IndexReader reader, String field) throws IOException {
+        TermDocs termDocs = reader.termDocs();
+        TermEnum termEnum = reader.terms(new Term(field, ""));
+        int t = 0; // current term number
+
+        // an entry for documents that have no terms in this field
+        // should a document with no terms be at top or bottom?
+        // this puts them at the top - if it is changed,
+        // FieldDocSortedHitQueue
+        // needs to change as well.
+        mterms[t++] = null;
+
+        try {
+          do {
+            Term term = termEnum.term();
+            if (term == null || term.field() != field)
+              break;
+
+            mterms[t] = term.text();
+
+            termDocs.seek(termEnum);
+            while (termDocs.next()) {
+              retArray[termDocs.doc()] = t;
+            }
+
+            t++;
+          } while (termEnum.next());
+        } finally {
+          termDocs.close();
+          termEnum.close();
+        }
+
+        if (t == 0) {
+          // if there are no terms, make the term array
+          // have a single null entry
+          mterms = new String[1];
+        } else if (t < mterms.length) {
+          // if there are less terms than documents,
+          // trim off the dead array space
+          String[] terms = new String[t];
+          System.arraycopy(mterms, 0, terms, 0, t);
+          mterms = terms;
+        }
+
+      }
+
+      void handleDoc(int docId) {
+      }
+
+      void newTerm(String text) {
+      }
+    }
+
+    StringIndexUninverter stringIndexUninverter = new StringIndexUninverter();
+
+    stringIndexUninverter.go(reader, field);
+    return new StringIndex(retArray, stringIndexUninverter.mterms);
+
+  }
+
+  public String[] getStrings(IndexReader reader, String field)
+      throws IOException {
+    final String[] retArray = new String[reader.maxDoc()];
+
+    Uninverter stringUninverter = new AnonUninverter() {
+      private String stringVal;
+
+      void handleDoc(int index) {
+        retArray[index] = stringVal;
+      }
+
+      void newTerm(String value) {
+        this.stringVal = value;
+      }
+
+    };
+
+    stringUninverter.go(reader, field);
+
+    return retArray;
+  }
+
+  abstract static class Uninverter {
+    void go(IndexReader reader, String field) throws IOException {
+      field = field.intern();
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field)
+            break;
+          newTerm(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            handleDoc(termDocs.doc());
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+    }
+
+    abstract void handleDoc(int docID);
+
+    abstract void newTerm(String text);
+
+    abstract Object getArray();
+  }
+
+  abstract class AnonUninverter extends Uninverter {
+    Object getArray() {
+      return null;
+    }
+  }
+}
Index: src/java/org/apache/lucene/search/ValueSource.java
===================================================================
--- src/java/org/apache/lucene/search/ValueSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/ValueSource.java	(revision 0)
@@ -0,0 +1,51 @@
+package org.apache.lucene.search;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+
+public abstract class ValueSource {
+
+  public byte[] getBytes(IndexReader reader, String field) throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public double[] getDoubles(IndexReader reader, String field)
+      throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public float[] getFloats(IndexReader reader, String field) throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public int[] getInts(IndexReader reader, String field) throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public long[] getLongs(IndexReader reader, String field) throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public short[] getShorts(IndexReader reader, String field) throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public StringIndex getStringIndex(IndexReader reader, String field)
+      throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  public String[] getStrings(IndexReader reader, String field)
+      throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+  /**
+   *   @Deprecated
+   */
+  public Comparable[] getComparables(IndexReader reader, String field, SortComparator comparator)  throws IOException {
+    throw new UnsupportedOperationException();
+  };
+
+}
Index: src/java/org/apache/lucene/search/ValueSourceFactory.java
===================================================================
--- src/java/org/apache/lucene/search/ValueSourceFactory.java	(revision 0)
+++ src/java/org/apache/lucene/search/ValueSourceFactory.java	(revision 0)
@@ -0,0 +1,7 @@
+package org.apache.lucene.search;
+
+import java.io.Serializable;
+
+public abstract  class ValueSourceFactory implements Serializable {
+  public abstract ValueSource getValueSource();
+}
Index: src/java/org/apache/lucene/search/function/ByteFieldSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/ByteFieldSource.java	(revision 765420)
+++ src/java/org/apache/lucene/search/function/ByteFieldSource.java	(working copy)
@@ -17,11 +17,13 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.function.DocValues;
-
-import java.io.IOException;
+import org.apache.lucene.search.UninversionValueSource;
+import org.apache.lucene.search.ValueSource;
+import org.apache.lucene.search.FieldCache.ByteParser;
 
 /**
  * Expert: obtains single byte field values from the 
@@ -38,7 +40,7 @@
  * on the field. 
  */
 public class ByteFieldSource extends FieldCacheSource {
-  private FieldCache.ByteParser parser;
+  private ByteParser parser;
 
   /**
    * Create a cached byte field source with default string-to-byte parser. 
@@ -48,7 +50,8 @@
   }
 
   /**
-   * Create a cached byte field source with a specific string-to-byte parser. 
+   * Create a cached byte field source with a specific string-to-byte parser.
+   * @deprecated
    */
   public ByteFieldSource(String field, FieldCache.ByteParser parser) {
     super(field);
@@ -64,7 +67,31 @@
   public DocValues getCachedFieldValues (FieldCache cache, String field, IndexReader reader) throws IOException {
     final byte[] arr = (parser==null) ?  
       cache.getBytes(reader, field) : 
-      cache.getBytes(reader, field, parser);
+      cache.getBytes(reader, field, (ByteParser) parser);
+    return new DocValues() {
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#floatVal(int) */
+      public float floatVal(int doc) { 
+        return (float) arr[doc]; 
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#intVal(int) */
+      public  int intVal(int doc) { 
+        return arr[doc]; 
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#toString(int) */
+      public String toString(int doc) { 
+        return  description() + '=' + intVal(doc);  
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#getInnerArray() */
+      Object getInnerArray() {
+        return arr;
+      }
+    };
+  }
+  
+  /*(non-Javadoc) @see org.apache.lucene.search.function.FieldCacheSource#getCachedValues(org.apache.lucene.search.FieldCache, java.lang.String, org.apache.lucene.index.IndexReader) */
+  public DocValues getCachedFieldValues (String field, IndexReader reader) throws IOException {
+    //nocommit: ignores parser
+    final byte[] arr = reader.getValueSource().getBytes(reader, field);
     return new DocValues() {
       /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#floatVal(int) */
       public float floatVal(int doc) { 
Index: src/java/org/apache/lucene/search/function/FieldCacheSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/FieldCacheSource.java	(revision 765420)
+++ src/java/org/apache/lucene/search/function/FieldCacheSource.java	(working copy)
@@ -39,6 +39,7 @@
  * The APIs introduced here might change in the future and will not be 
  * supported anymore in such a case.</font>
  *
+ * @deprecated see ValueSourceCacheSource
  */
 public abstract class FieldCacheSource extends ValueSource {
   private String field;
@@ -65,9 +66,21 @@
    * @param cache FieldCache so that values of a field are loaded once per reader (RAM allowing)
    * @param field Field for which values are required.
    * @see ValueSource
+   * @deprecated
    */
   public abstract DocValues getCachedFieldValues(FieldCache cache, String field, IndexReader reader) throws IOException;
 
+  /**
+   * Return cached DocValues for input field and reader.
+   * @param cache FieldCache so that values of a field are loaded once per reader (RAM allowing)
+   * @param field Field for which values are required.
+   * @see ValueSource
+   */
+  public DocValues getCachedFieldValues(String field, IndexReader reader) throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  
   /*(non-Javadoc) @see java.lang.Object#equals(java.lang.Object) */
   public final boolean equals(Object o) {
     if (!(o instanceof FieldCacheSource)) {
Index: src/java/org/apache/lucene/search/function/FloatFieldSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/FloatFieldSource.java	(revision 765420)
+++ src/java/org/apache/lucene/search/function/FloatFieldSource.java	(working copy)
@@ -17,11 +17,13 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.function.DocValues;
-
-import java.io.IOException;
+import org.apache.lucene.search.UninversionValueSource;
+import org.apache.lucene.search.ValueSource;
+import org.apache.lucene.search.FieldCache.FloatParser;
 
 /**
  * Expert: obtains float field values from the 
@@ -39,7 +41,7 @@
  *
  */
 public class FloatFieldSource extends FieldCacheSource {
-  private FieldCache.FloatParser parser;
+  private FloatParser parser;
 
   /**
    * Create a cached float field source with default string-to-float parser. 
@@ -50,6 +52,7 @@
 
   /**
    * Create a cached float field source with a specific string-to-float parser. 
+   * @deprecated
    */
   public FloatFieldSource(String field, FieldCache.FloatParser parser) {
     super(field);
@@ -65,7 +68,26 @@
   public DocValues getCachedFieldValues (FieldCache cache, String field, IndexReader reader) throws IOException {
     final float[] arr = (parser==null) ?
       cache.getFloats(reader, field) :
-      cache.getFloats(reader, field, parser);
+      cache.getFloats(reader, field, (FloatParser) parser);
+    return new DocValues() {
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#floatVal(int) */
+      public float floatVal(int doc) {
+        return arr[doc];      
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#toString(int) */
+      public String toString(int doc) { 
+        return  description() + '=' + arr[doc];  
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#getInnerArray() */
+      Object getInnerArray() {
+        return arr;
+      }
+    };
+  }
+  
+  /*(non-Javadoc) @see org.apache.lucene.search.function.FieldCacheSource#getCachedValues(org.apache.lucene.search.FieldCache, java.lang.String, org.apache.lucene.index.IndexReader) */
+  public DocValues getCachedFieldValues (String field, IndexReader reader) throws IOException {
+    final float[] arr = reader.getValueSource().getFloats(reader, field);
     return new DocValues() {
       /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#floatVal(int) */
       public float floatVal(int doc) {
Index: src/java/org/apache/lucene/search/function/IntFieldValueSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/IntFieldValueSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/function/IntFieldValueSource.java	(revision 0)
@@ -0,0 +1,5 @@
+package org.apache.lucene.search.function;
+
+public class IntFieldValueSource {
+
+}
Index: src/java/org/apache/lucene/search/function/OrdFieldSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/OrdFieldSource.java	(revision 765420)
+++ src/java/org/apache/lucene/search/function/OrdFieldSource.java	(working copy)
@@ -44,6 +44,8 @@
  * The APIs introduced here might change in the future and will not be 
  * supported anymore in such a case.</font>
  *
+ * 
+ * TODO: deprecated methods/classes used
  */
 
 public class OrdFieldSource extends ValueSource {
Index: src/java/org/apache/lucene/search/function/ReverseOrdFieldSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/ReverseOrdFieldSource.java	(revision 765420)
+++ src/java/org/apache/lucene/search/function/ReverseOrdFieldSource.java	(working copy)
@@ -45,6 +45,7 @@
  * The APIs introduced here might change in the future and will not be 
  * supported anymore in such a case.</font>
  *
+ * TODO: deprecated methods/classes used
  */
 
 public class ReverseOrdFieldSource extends ValueSource {
Index: src/java/org/apache/lucene/search/function/ShortFieldSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/ShortFieldSource.java	(revision 765420)
+++ src/java/org/apache/lucene/search/function/ShortFieldSource.java	(working copy)
@@ -17,11 +17,13 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.function.DocValues;
-
-import java.io.IOException;
+import org.apache.lucene.search.UninversionValueSource;
+import org.apache.lucene.search.ValueSource;
+import org.apache.lucene.search.FieldCache.ShortParser;
 
 /**
  * Expert: obtains short field values from the 
@@ -36,9 +38,10 @@
  * 
  * @see org.apache.lucene.search.function.FieldCacheSource for requirements 
  * on the field.
+ * TODO: deprecated methods/classes used
  */
 public class ShortFieldSource extends FieldCacheSource {
-  private FieldCache.ShortParser parser;
+  private ShortParser parser;
 
   /**
    * Create a cached short field source with default string-to-short parser. 
@@ -49,12 +52,13 @@
 
   /**
    * Create a cached short field source with a specific string-to-short parser. 
+   * @deprecated
    */
   public ShortFieldSource(String field, FieldCache.ShortParser parser) {
     super(field);
     this.parser = parser;
   }
-
+  
   /*(non-Javadoc) @see org.apache.lucene.search.function.ValueSource#description() */
   public String description() {
     return "short(" + super.description() + ')';
@@ -64,7 +68,32 @@
   public DocValues getCachedFieldValues (FieldCache cache, String field, IndexReader reader) throws IOException {
     final short[] arr = (parser==null) ?  
       cache.getShorts(reader, field) : 
-      cache.getShorts(reader, field, parser);
+      cache.getShorts(reader, field, (ShortParser) parser);
+    return new DocValues() {
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#floatVal(int) */
+      public float floatVal(int doc) { 
+        return (float) arr[doc];
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#intVal(int) */
+      public  int intVal(int doc) { 
+        return arr[doc]; 
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#toString(int) */
+      public String toString(int doc) { 
+        return  description() + '=' + intVal(doc);  
+      }
+      /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#getInnerArray() */
+      Object getInnerArray() {
+        return arr;
+      }
+    };
+  }
+  
+  /*(non-Javadoc) @see org.apache.lucene.search.function.FieldCacheSource#getCachedValues(org.apache.lucene.search.FieldCache, java.lang.String, org.apache.lucene.index.IndexReader) */
+  public DocValues getCachedFieldValues (String field, IndexReader reader) throws IOException {
+    // nocommit: parser support
+    final short[] arr = reader.getValueSource().getShorts(reader, field);
+    
     return new DocValues() {
       /*(non-Javadoc) @see org.apache.lucene.search.function.DocValues#floatVal(int) */
       public float floatVal(int doc) { 
Index: src/java/org/apache/lucene/search/function/ValueSourceCacheSource.java
===================================================================
--- src/java/org/apache/lucene/search/function/ValueSourceCacheSource.java	(revision 0)
+++ src/java/org/apache/lucene/search/function/ValueSourceCacheSource.java	(revision 0)
@@ -0,0 +1,31 @@
+package org.apache.lucene.search.function;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+
+public class ValueSourceCacheSource extends ValueSource {
+
+  public String description() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  
+  public boolean equals(Object o) {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+
+  public DocValues getValues(IndexReader reader) throws IOException {
+    return null;
+  }
+
+
+  public int hashCode() {
+    // TODO Auto-generated method stub
+    return 0;
+  }
+
+}

