Index: src/test/org/apache/lucene/search/TestFieldCache.java
===================================================================
--- src/test/org/apache/lucene/search/TestFieldCache.java	(revision 954645)
+++ 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 954645)
+++ 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 954645)
+++ 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,105 @@
     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;
+      int currentArrayNumber;
+      byte[][] blocks;
+      int[] blockEnds;
+      int end;
+      
+      final BytesRef term = new BytesRef();
+
+      public DocTermsIndexEnum() {
+        currentOrd = 0;
+        currentArrayNumber = 0;
+        blocks = bytes.getBlocks();
+        blockEnds = bytes.getBlockEnds();
+        currentArrayNumber = bytes.fillUsingLengthPrefix2(term, termOrdToBytesOffset.get(0));
+        end = blockEnds[currentArrayNumber];
+      }
+
+      @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?
+        currentArrayNumber = bytes.fillUsingLengthPrefix2(term, termOrdToBytesOffset.get((int)ord));
+        end = blockEnds[currentArrayNumber];
+        currentOrd = (int)ord;
+        return SeekStatus.FOUND;
+      }
+
+      @Override
+      public BytesRef next() throws IOException {
+        int start = term.offset + term.length;
+        if (start >= end) {
+          // switch byte blocks
+          if (currentArrayNumber+1 >= blocks.length) {
+            return null;
+          }
+          currentArrayNumber++;
+          term.bytes = blocks[currentArrayNumber];
+          end = blockEnds[currentArrayNumber];
+          start = 0;
+          if (end<=0) return null;  // special case of empty last array
+        }
+
+        currentOrd++;
+
+        byte[] block = term.bytes;
+        if ((block[start] & 128) == 0) {
+          term.length = block[start];
+          term.offset = start+1;
+        } else {
+          term.length = (((int) (block[start] & 0x7f)) << 8) | (block[1+start] & 0xff);
+          term.offset = start+2;
+        }
+
+        return 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 954645)
+++ src/java/org/apache/lucene/util/PagedBytes.java	(working copy)
@@ -32,6 +32,7 @@
  * <p>@lucene.internal</p>*/
 public final class PagedBytes {
   private final List<byte[]> blocks = new ArrayList<byte[]>();
+  private final List<Integer> blockEnd = new ArrayList<Integer>();
   private final int blockSize;
   private final int blockBits;
   private final int blockMask;
@@ -42,6 +43,7 @@
 
   public final static class Reader implements Closeable {
     private final byte[][] blocks;
+    private final int[] blockEnds;
     private final int blockBits;
     private final int blockMask;
     private final int blockSize;
@@ -52,6 +54,10 @@
       for(int i=0;i<blocks.length;i++) {
         blocks[i] = pagedBytes.blocks.get(i);
       }
+      blockEnds = new int[blocks.length];
+      for(int i=0;i< blockEnds.length;i++) {
+        blockEnds[i] = pagedBytes.blockEnd.get(i);
+      }
       blockBits = pagedBytes.blockBits;
       blockMask = pagedBytes.blockMask;
       blockSize = pagedBytes.blockSize;
@@ -102,6 +108,34 @@
       return b;
     }
 
+    /** @lucene.internal  Reads length as 1 or 2 byte vInt prefix, starting @ start.  Returns the block number of the term. */
+    public int fillUsingLengthPrefix2(BytesRef b, long start) {
+      final int index = (int) (start >> blockBits);
+      final int offset = (int) (start & blockMask);
+      final byte[] block = b.bytes = blocks[index];
+
+      if ((block[offset] & 128) == 0) {
+        b.length = block[offset];
+        b.offset = offset+1;
+      } else {
+        b.length = (((int) (block[offset] & 0x7f)) << 8) | (block[1+offset] & 0xff);
+        b.offset = offset+2;
+        assert b.length > 0;
+      }
+      return index;
+    }
+
+
+    /** @lucene.internal */
+    public byte[][] getBlocks() {
+      return blocks;
+    }
+
+    /** @lucene.internal */
+    public int[] getBlockEnds() {
+      return blockEnds;
+    }
+
     public void close() {
       threadBuffers.close();
     }
@@ -123,6 +157,7 @@
       if (left == 0) {
         if (currentBlock != null) {
           blocks.add(currentBlock);
+          blockEnd.add(upto);
         }
         currentBlock = new byte[blockSize];
         upto = 0;
@@ -149,6 +184,7 @@
       if (left == 0) {
         if (currentBlock != null) {
           blocks.add(currentBlock);
+          blockEnd.add(upto);          
         }
         currentBlock = new byte[blockSize];
         upto = 0;
@@ -178,6 +214,7 @@
       currentBlock = EMPTY_BYTES;
     }
     blocks.add(currentBlock);
+    blockEnd.add(upto); 
     currentBlock = null;
     return new Reader(this);
   }
@@ -200,6 +237,7 @@
       }
       if (currentBlock != null) {
         blocks.add(currentBlock);
+        blockEnd.add(upto);        
       }
       currentBlock = new byte[blockSize];
       upto = 0;
