Index: src/test/org/apache/lucene/search/TestFieldCache.java
===================================================================
--- src/test/org/apache/lucene/search/TestFieldCache.java	(revision 951737)
+++ src/test/org/apache/lucene/search/TestFieldCache.java	(working copy)
@@ -22,6 +22,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.store.RAMDirectory;
 import org.apache.lucene.store.MockRAMDirectory;
 import org.apache.lucene.store.Directory;
@@ -167,6 +168,20 @@
       final String s = term == null ? null : term.utf8ToString();
       assertTrue("for doc " + i + ": " + s + " does not equal: " + unicodeStrings[i], unicodeStrings[i] == null || unicodeStrings[i].equals(s));
     }
+
+    int nTerms = termsIndex.numOrd();
+    System.out.println("nTerms="+nTerms);
+
+    TermsEnum tenum = termsIndex.getTermsEnum();
+    BytesRef val = new BytesRef();
+    for (int i=1; i<nTerms; i++) {
+      BytesRef val1 = tenum.next();
+      BytesRef val2 = termsIndex.lookup(i,val);
+      System.out.println("i="+i);
+      assertEquals(val2, val1);
+    }
+
+
     // test bad field
     termsIndex = cache.getTermsIndex(reader, "bogusfield");
 
Index: src/java/org/apache/lucene/search/FieldCache.java
===================================================================
--- src/java/org/apache/lucene/search/FieldCache.java	(revision 951737)
+++ src/java/org/apache/lucene/search/FieldCache.java	(working copy)
@@ -18,6 +18,7 @@
  */
 
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.util.NumericUtils;
 import org.apache.lucene.util.RamUsageEstimator;
 import org.apache.lucene.util.BytesRef;
@@ -530,6 +531,9 @@
 
     /** Number of documents */
     public abstract int size();
+
+    /** Returns a TermsEnum that can iterate over the values in this index entry */
+    public abstract TermsEnum getTermsEnum();
   }
 
   /** Checks the internal cache for an appropriate entry, and if none
Index: src/java/org/apache/lucene/search/FieldCacheImpl.java
===================================================================
--- src/java/org/apache/lucene/search/FieldCacheImpl.java	(revision 951737)
+++ src/java/org/apache/lucene/search/FieldCacheImpl.java	(working copy)
@@ -19,17 +19,9 @@
 
 import java.io.IOException;
 import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
+import java.util.*;
 
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.TermsEnum;
+import org.apache.lucene.index.*;
 import org.apache.lucene.util.PagedBytes;
 import org.apache.lucene.util.packed.PackedInts;
 import org.apache.lucene.util.packed.GrowableWriter;
@@ -674,6 +666,72 @@
     public BytesRef lookup(int ord, BytesRef ret) {
       return bytes.fillUsingLengthPrefix(ret, termOrdToBytesOffset.get(ord));
     }
+
+    @Override
+    public TermsEnum getTermsEnum() {
+      return this.new DocTermsIndexEnum();
+    }
+
+    class DocTermsIndexEnum extends TermsEnum {
+      int currentOrd;
+      final BytesRef term = new BytesRef();
+
+      public DocTermsIndexEnum() {
+        currentOrd = 0;
+        bytes.fillUsingLengthPrefix(term, termOrdToBytesOffset.get(0));
+      }
+
+      @Override
+      public SeekStatus seek(BytesRef text, boolean useCache) throws IOException {
+        // TODO
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public SeekStatus seek(long ord) throws IOException {
+        assert(ord >= 0 && ord <= numOrd);
+        // TODO: if gap is small, could iterate from current position?  Or let user decide that?
+        bytes.fillUsingLengthPrefix(term, termOrdToBytesOffset.get((int)ord));
+        currentOrd = (int)ord;
+        return SeekStatus.FOUND;
+      }
+
+      @Override
+      public BytesRef next() throws IOException {
+        currentOrd++;
+        return bytes.next(term);
+      }
+
+      @Override
+      public BytesRef term() throws IOException {
+        return term;
+      }
+
+      @Override
+      public long ord() throws IOException {
+        return currentOrd;
+      }
+
+      @Override
+      public int docFreq() {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public DocsEnum docs(Bits skipDocs, DocsEnum reuse) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public DocsAndPositionsEnum docsAndPositions(Bits skipDocs, DocsAndPositionsEnum reuse) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public Comparator<BytesRef> getComparator() throws IOException {
+        throw new UnsupportedOperationException();
+      }
+    }
   }
 
   private static boolean DEFAULT_FASTER_BUT_MORE_RAM = true;
Index: src/java/org/apache/lucene/util/PagedBytes.java
===================================================================
--- src/java/org/apache/lucene/util/PagedBytes.java	(revision 951737)
+++ src/java/org/apache/lucene/util/PagedBytes.java	(working copy)
@@ -17,8 +17,12 @@
  * limitations under the License.
  */
 
+import org.apache.lucene.index.DocsAndPositionsEnum;
+import org.apache.lucene.index.DocsEnum;
+import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.store.IndexInput;
 
+import java.util.Comparator;
 import java.util.List;
 import java.util.ArrayList;
 import java.io.Closeable;
@@ -102,6 +106,35 @@
       return b;
     }
 
+    /** Go to the next value when length is encoded as a 1 or 2 byte vInt prefix.
+     * Returns null if no more values. */
+    public BytesRef next(BytesRef current) {
+      int start = current.offset + current.length;
+      if (start >= current.bytes.length) {
+        // switch byte blocks
+        current.bytes = null;
+        for (int i=0; i<blocks.length-1; i++) {
+          if (current.bytes == blocks[i]) {
+            current.bytes = blocks[i+1];
+          }
+        }
+        if (current.bytes == null || current.bytes.length == 0)
+          return null;
+        start = 0;
+      }
+
+      byte[] block = current.bytes;
+      if ((block[start] & 128) == 0) {
+        current.length = block[start];
+        current.offset = start+1;
+      } else {
+        current.length = (((int) (block[start] & 0x7f)) << 8) | (block[1+start] & 0xff);
+        current.offset = start+2;
+      }
+
+      return current;
+    }
+
     public void close() {
       threadBuffers.close();
     }
