Index: modules/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java
===================================================================
--- modules/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java	(revision 1237329)
+++ modules/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java	(working copy)
@@ -61,7 +61,8 @@
     ordSet.clear();
     for (SearchGroupDocs<BytesRef> group : groupMap.values()) {
 //      System.out.println("  group=" + (group.groupValue == null ? "null" : group.groupValue.utf8ToString()));
-      int ord = group.groupValue == null ? 0 : index.binarySearchLookup(group.groupValue, spareBytesRef);
+      //int ord = group.groupValue == null ? 0 : index.binarySearchLookup(group.groupValue, spareBytesRef);
+      int ord = group.groupValue == null ? 0 : index.getExact(group.groupValue);
       if (ord >= 0) {
         groupDocs[ordSet.put(ord)] = group;
       }
Index: lucene/src/java/org/apache/lucene/search/FieldCache.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/FieldCache.java	(revision 1237329)
+++ lucene/src/java/org/apache/lucene/search/FieldCache.java	(working copy)
@@ -549,6 +549,8 @@
       return -(low + 1);  // key not found.
     }
 
+    public abstract int getExact(BytesRef key);
+
     /** The BytesRef argument must not be null; the method
      *  returns the same BytesRef, or an empty (length=0)
      *  BytesRef if this ord is the null ord (0). */
Index: lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java	(revision 1237329)
+++ lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java	(working copy)
@@ -40,7 +40,12 @@
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.FieldCacheSanityChecker;
 import org.apache.lucene.util.FixedBitSet;
+import org.apache.lucene.util.IntsRef;
 import org.apache.lucene.util.PagedBytes;
+import org.apache.lucene.util.fst.Builder;
+import org.apache.lucene.util.fst.FST;
+import org.apache.lucene.util.fst.PositiveIntOutputs;
+import org.apache.lucene.util.fst.Util;
 import org.apache.lucene.util.packed.GrowableWriter;
 import org.apache.lucene.util.packed.PackedInts;
 
@@ -903,13 +908,15 @@
     private final PagedBytes.Reader bytes;
     private final PackedInts.Reader termOrdToBytesOffset;
     private final PackedInts.Reader docToTermOrd;
+    private final FST<Long> termsFST;
     private final int numOrd;
 
-    public DocTermsIndexImpl(PagedBytes.Reader bytes, PackedInts.Reader termOrdToBytesOffset, PackedInts.Reader docToTermOrd, int numOrd) {
+    public DocTermsIndexImpl(PagedBytes.Reader bytes, PackedInts.Reader termOrdToBytesOffset, PackedInts.Reader docToTermOrd, int numOrd, FST<Long> fst) {
       this.bytes = bytes;
       this.docToTermOrd = docToTermOrd;
       this.termOrdToBytesOffset = termOrdToBytesOffset;
       this.numOrd = numOrd;
+      this.termsFST = fst;
     }
 
     @Override
@@ -934,11 +941,42 @@
 
     @Override
     public BytesRef lookup(int ord, BytesRef ret) {
-      return bytes.fill(ret, termOrdToBytesOffset.get(ord));
+      //return bytes.fill(ret, termOrdToBytesOffset.get(ord));
+      if (ord == 0) {
+        ret.length = 0;
+        return ret;
+        // nocommit why does TestGrouping get angry if we
+        //return null here....?
+        //return null;
+      }
+      try {
+        final IntsRef ic = Util.getByOutput(termsFST, ord);
+        assert ic != null: "ord=" + ord;
+        return Util.toBytesRef(ic, ret);
+      } catch (IOException ioe) {
+        // Pffft!
+        throw new RuntimeException(ioe);
+      }
     }
 
     @Override
+    public int getExact(BytesRef key) {
+      try {
+        Long value = Util.get(termsFST, Util.toIntsRef(key, new IntsRef()));
+        if (value == null) {
+          return -1;
+        } else {
+          return value.intValue();
+        }
+      } catch (IOException ioe) {
+        // Pfffft!
+        throw new RuntimeException(ioe);
+      }
+    }
+
+    @Override
     public TermsEnum getTermsEnum() {
+      // nocommit: FSTEnum
       return this.new DocTermsIndexEnum();
     }
 
@@ -1151,6 +1189,13 @@
       bytes.copyUsingLengthPrefix(new BytesRef());
       int termOrd = 1;
 
+      // nocommit
+      final PositiveIntOutputs fstOutputs = PositiveIntOutputs.getSingleton(true);
+      
+      // nocommit try packing too
+      final Builder<Long> builder = new Builder<Long>(FST.INPUT_TYPE.BYTE1, fstOutputs);
+      final IntsRef scratchIntsRef = new IntsRef();
+
       if (terms != null) {
         final TermsEnum termsEnum = terms.iterator(null);
         DocsEnum docs = null;
@@ -1179,6 +1224,7 @@
             }
             docToTermOrd.set(docID, termOrd);
           }
+          builder.add(Util.toIntsRef(term, scratchIntsRef), fstOutputs.get(termOrd));
           termOrd++;
         }
 
@@ -1188,7 +1234,11 @@
       }
 
       // maybe an int-only impl?
-      return new DocTermsIndexImpl(bytes.freeze(true), termOrdToBytesOffset.getMutable(), docToTermOrd.getMutable(), termOrd);
+      final FST<Long> termsFST = builder.finish();
+      if (termsFST != null) {
+        System.out.println("FST: " + termsFST.sizeInBytes() + " numTerms=" + termOrd + " field=" + entryKey.field + " vs PagedBytes=" + (bytes.getPointer() + (termOrdToBytesOffset.getBitsPerValue()*termOrd)/8));
+      }
+      return new DocTermsIndexImpl(bytes.freeze(true), termOrdToBytesOffset.getMutable(), docToTermOrd.getMutable(), termOrd, termsFST);
     }
   }
 
