You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2015/07/30 19:19:43 UTC

[05/25] incubator-usergrid git commit: Comparators partially implemented.

Comparators partially implemented.

Merges iterators.  Paging still incomplete.

Merges iterators.  Paging still incomplete.

WIP overwrite

WIP overwrite


Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/68c7eae1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/68c7eae1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/68c7eae1

Branch: refs/heads/master
Commit: 68c7eae1eb4409b067c8f3c3e4923b6b5e5a8e86
Parents: bb2837c
Author: Todd Nine <tn...@apigee.com>
Authored: Thu Jun 18 11:06:17 2015 -0600
Committer: Todd Nine <tn...@apigee.com>
Committed: Thu Jun 25 11:14:49 2015 -0600

----------------------------------------------------------------------
 .../persistence/cassandra/CassandraService.java |  42 ++--
 .../persistence/cassandra/QueryProcessor.java   |  15 +-
 .../cassandra/index/ConnectedIndexScanner.java  |   4 +-
 .../index/DynamicCompositeStartToBytes.java     |  48 ++++
 .../cassandra/index/IndexBucketScanner.java     |  81 +++++--
 .../cassandra/index/StartToBytes.java           |  34 +++
 .../cassandra/index/UUIDStartToBytes.java       |  41 ++++
 .../persistence/query/ir/SearchVisitor.java     |  10 +-
 .../query/ir/result/AbstractScanColumn.java     |  32 +--
 .../query/ir/result/GatherIterator.java         | 111 +++++++---
 .../ir/result/SearchCollectionVisitor.java      |  14 +-
 .../ir/result/SearchConnectionVisitor.java      |   3 +-
 .../ir/result/SecondaryIndexSliceParser.java    | 220 ++++++++++++++++++-
 .../query/ir/result/SliceIterator.java          |  17 +-
 .../persistence/query/ir/result/UUIDColumn.java |  36 +--
 .../query/ir/result/UUIDIndexSliceParser.java   |   2 +-
 .../query/ir/result/UnionIterator.java          |  18 +-
 .../usergrid/persistence/CollectionIT.java      |   2 +-
 18 files changed, 552 insertions(+), 178 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
index 58d5d0f..12ea338 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/CassandraService.java
@@ -39,6 +39,7 @@ import org.apache.usergrid.persistence.IndexBucketLocator;
 import org.apache.usergrid.persistence.IndexBucketLocator.IndexType;
 import org.apache.usergrid.persistence.cassandra.index.IndexBucketScanner;
 import org.apache.usergrid.persistence.cassandra.index.IndexScanner;
+import org.apache.usergrid.persistence.cassandra.index.UUIDStartToBytes;
 import org.apache.usergrid.persistence.hector.CountingMutator;
 
 import me.prettyprint.cassandra.connection.HConnectionManager;
@@ -1027,29 +1028,27 @@ public class CassandraService {
      *
      * @throws Exception the exception
      */
-       public IndexScanner getIdList( Keyspace ko, Object key, UUID start, UUID finish, int count, boolean reversed,
-                                      IndexBucketLocator locator, UUID applicationId, String collectionName, boolean keepFirst )
+       public IndexScanner getIdList( Object key, UUID start, UUID finish, int count, boolean reversed,
+                                      final String bucket, UUID applicationId, boolean keepFirst )
                throws Exception {
 
-           //TODO, refactor this
-           throw new UnsupportedOperationException( "Implement me" );
-
-   //        if ( count <= 0 ) {
-   //            count = DEFAULT_COUNT;
-   //        }
-   //
-   //        if ( NULL_ID.equals( start ) ) {
-   //            start = null;
-   //        }
-   //
-   //
-   //        final boolean skipFirst = start != null && !keepFirst;
-   //
-   //        IndexScanner scanner =
-   //                new IndexBucketScanner( this, locator, ENTITY_ID_SETS, applicationId, IndexType.COLLECTION, key, start,
-   //                        finish, reversed, count, skipFirst, collectionName );
-   //
-   //        return scanner;
+           if ( count <= 0 ) {
+               count = DEFAULT_COUNT;
+           }
+
+           if ( NULL_ID.equals( start ) ) {
+               start = null;
+           }
+
+
+           final boolean skipFirst = start != null && !keepFirst;
+
+
+           IndexScanner scanner =
+                   new IndexBucketScanner<UUID>( this, ENTITY_ID_SETS, UUIDStartToBytes.INSTANCE, applicationId, key, bucket, start,
+                           finish, reversed, count, skipFirst );
+
+           return scanner;
        }
 
 
@@ -1064,4 +1063,5 @@ public class CassandraService {
     	}
     	cluster = null;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/QueryProcessor.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/QueryProcessor.java
index f55aa67..ebaacf4 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/QueryProcessor.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/QueryProcessor.java
@@ -448,7 +448,7 @@ public class QueryProcessor {
                 node = newSliceNode();
             }
             else {
-                node = getUnionNode( op );
+                node = getUnionNode( );
             }
 
             String fieldName = op.getProperty().getIndexedValue();
@@ -485,7 +485,7 @@ public class QueryProcessor {
 
             checkIndexed( propertyName );
 
-            getUnionNode( op ).setFinish( propertyName, op.getLiteral().getValue(), false );
+            getUnionNode( ).setFinish( propertyName, op.getLiteral().getValue(), false );
         }
 
 
@@ -502,7 +502,7 @@ public class QueryProcessor {
 
             checkIndexed( propertyName );
 
-            getUnionNode( op ).setFinish( propertyName, op.getLiteral().getValue(), true );
+            getUnionNode( ).setFinish( propertyName, op.getLiteral().getValue(), true );
         }
 
 
@@ -519,7 +519,7 @@ public class QueryProcessor {
             //checkIndexed( fieldName );
 
             Literal<?> literal = op.getLiteral();
-            SliceNode node = getUnionNode( op );
+            SliceNode node = getUnionNode( );
 
             // this is an edge case. If we get more edge cases, we need to push
             // this down into the literals and let the objects
@@ -554,7 +554,7 @@ public class QueryProcessor {
 
             checkIndexed( propertyName );
 
-            getUnionNode( op ).setStart( propertyName, op.getLiteral().getValue(), false );
+            getUnionNode( ).setStart( propertyName, op.getLiteral().getValue(), false );
         }
 
 
@@ -570,7 +570,7 @@ public class QueryProcessor {
 
             checkIndexed( propertyName );
 
-            getUnionNode( op ).setStart( propertyName, op.getLiteral().getValue(), true );
+            getUnionNode( ).setStart( propertyName, op.getLiteral().getValue(), true );
         }
 
 
@@ -578,9 +578,8 @@ public class QueryProcessor {
          * Return the current leaf node to add to if it exists. This means that we can compress multiple 'AND'
          * operations and ranges into a single node. Otherwise a new node is created and pushed to the stack
          *
-         * @param current The current operand node
          */
-        private SliceNode getUnionNode( EqualityOperand current ) {
+        private SliceNode getUnionNode( ) {
 
             /**
              * we only create a new slice node in 3 situations 1. No nodes exist 2.

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/ConnectedIndexScanner.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/ConnectedIndexScanner.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/ConnectedIndexScanner.java
index 87726cb..6c6152a 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/ConnectedIndexScanner.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/ConnectedIndexScanner.java
@@ -174,11 +174,11 @@ public class ConnectedIndexScanner implements IndexScanner {
         }
 
         //remove the first element, we need to skip it
-        if ( skipFirst && lastResults.size() > 0) {
+        if ( skipFirst && lastResults != null && lastResults.size() > 0) {
             lastResults.remove( 0  );
         }
 
-        if ( hasMore && lastResults.size() > 0 ) {
+        if ( hasMore && lastResults !=null && lastResults.size() > 0 ) {
             // set the bytebuffer for the next pass
             lastResults.remove( lastResults.size() - 1 );
         }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/DynamicCompositeStartToBytes.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/DynamicCompositeStartToBytes.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/DynamicCompositeStartToBytes.java
new file mode 100644
index 0000000..072e8ca
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/DynamicCompositeStartToBytes.java
@@ -0,0 +1,48 @@
+/*
+ *
+ *  * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  * contributor license agreements.  See the NOTICE file distributed with
+ *  * this work for additional information regarding copyright ownership.
+ *  * The ASF licenses this file to You under the Apache License, Version 2.0
+ *  * (the "License"); you may not use this file except in compliance with
+ *  * the License.  You may obtain a copy of the License at
+ *  *
+ *  *      http://www.apache.org/licenses/LICENSE-2.0
+ *  *
+ *  * Unless required by applicable law or agreed to in writing, software
+ *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  * See the License for the specific language governing permissions and
+ *  * limitations under the License.
+ *
+ */
+package org.apache.usergrid.persistence.cassandra.index;
+
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import me.prettyprint.cassandra.serializers.UUIDSerializer;
+import me.prettyprint.hector.api.beans.DynamicComposite;
+
+
+/**
+ * Converts a DynamicComposite to bytes
+ */
+public class DynamicCompositeStartToBytes implements StartToBytes<DynamicComposite> {
+
+    public static final DynamicCompositeStartToBytes INSTANCE = new DynamicCompositeStartToBytes();
+
+    private DynamicCompositeStartToBytes(){}
+
+
+    @Override
+    public ByteBuffer toBytes( final DynamicComposite toBytes ) {
+
+        if(toBytes == null){
+            return null;
+        }
+
+        return toBytes.serialize();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/IndexBucketScanner.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/IndexBucketScanner.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/IndexBucketScanner.java
index e568575..bf61846 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/IndexBucketScanner.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/IndexBucketScanner.java
@@ -18,19 +18,16 @@ package org.apache.usergrid.persistence.cassandra.index;
 
 
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
-import java.util.NavigableSet;
-import java.util.Set;
-import java.util.TreeSet;
 import java.util.UUID;
 
-import org.apache.usergrid.persistence.IndexBucketLocator;
-import org.apache.usergrid.persistence.IndexBucketLocator.IndexType;
+import org.apache.cassandra.utils.FBUtilities;
+
 import org.apache.usergrid.persistence.cassandra.ApplicationCF;
 import org.apache.usergrid.persistence.cassandra.CassandraService;
 
+import com.google.common.primitives.UnsignedBytes;
 import com.yammer.metrics.annotation.Metered;
 
 import me.prettyprint.hector.api.beans.HColumn;
@@ -44,7 +41,7 @@ import static org.apache.usergrid.persistence.cassandra.CassandraPersistenceUtil
  *
  * @author tnine
  */
-public class IndexBucketScanner implements IndexScanner {
+public class IndexBucketScanner<T> implements IndexScanner {
 
     private final CassandraService cass;
     private final UUID applicationId;
@@ -55,12 +52,13 @@ public class IndexBucketScanner implements IndexScanner {
     private final int pageSize;
     private final boolean skipFirst;
     private final String bucket;
+    private final StartToBytes<T> scanStartSerializer;
 
     /** Pointer to our next start read */
-    private Object start;
+    private ByteBuffer start;
 
     /** Set to the original value to start scanning from */
-    private Object scanStart;
+    private T initialStartValue;
 
     /** Iterator for our results from the last page load */
     private List<HColumn<ByteBuffer, ByteBuffer>> lastResults;
@@ -70,14 +68,14 @@ public class IndexBucketScanner implements IndexScanner {
 
 
 
-    public IndexBucketScanner( CassandraService cass, ApplicationCF columnFamily,
-                               UUID applicationId, Object keyPrefix, String bucket,  Object start, Object finish,
+    public IndexBucketScanner( CassandraService cass, ApplicationCF columnFamily, StartToBytes<T> scanStartSerializer,
+                               UUID applicationId, Object keyPrefix, String bucket,  T start, T finish,
                                boolean reversed, int pageSize, boolean skipFirst) {
         this.cass = cass;
+        this.scanStartSerializer = scanStartSerializer;
         this.applicationId = applicationId;
         this.keyPrefix = keyPrefix;
         this.columnFamily = columnFamily;
-        this.start = start;
         this.finish = finish;
         this.reversed = reversed;
         this.skipFirst = skipFirst;
@@ -85,7 +83,10 @@ public class IndexBucketScanner implements IndexScanner {
 
         //we always add 1 to the page size.  This is because we pop the last column for the next page of results
         this.pageSize = pageSize+1;
-        this.scanStart = start;
+
+        //the initial value set when we started scanning
+        this.initialStartValue = start;
+        this.start = scanStartSerializer.toBytes( initialStartValue );
     }
 
 
@@ -95,7 +96,7 @@ public class IndexBucketScanner implements IndexScanner {
     @Override
     public void reset() {
         hasMore = true;
-        start = scanStart;
+        start = scanStartSerializer.toBytes( initialStartValue );
     }
 
 
@@ -122,12 +123,10 @@ public class IndexBucketScanner implements IndexScanner {
         //we purposefully use instance equality.  If it's a pointer to the same value, we need to increase by 1
         //since we'll be skipping the first value
 
-        final boolean firstPageSkipFirst = this.skipFirst &&  start == scanStart;
-
-        if(firstPageSkipFirst){
-            selectSize++;
-        }
 
+        final boolean shouldCheckFirst =
+                //we should skip the value it's a cursor resume OR it's a previous page from a stateful iterator
+                (this.skipFirst &&  initialStartValue != null) || start != null;
 
         final List<HColumn<ByteBuffer, ByteBuffer>>
                 resultsTree = cass.getColumns( cass.getApplicationKeyspace( applicationId ), columnFamily, rowKey,
@@ -140,7 +139,6 @@ public class IndexBucketScanner implements IndexScanner {
         if ( resultsTree.size() == selectSize ) {
             hasMore = true;
 
-
             // set the bytebuffer for the next pass
             start = resultsTree.get( resultsTree.size() - 1 ).getName();
         }
@@ -149,8 +147,25 @@ public class IndexBucketScanner implements IndexScanner {
         }
 
         //remove the first element since it needs to be skipped AFTER the size check. Otherwise it will fail
-        if ( firstPageSkipFirst ) {
-            resultsTree.remove( 0 );
+        //we only want to skip if our byte value are the same as our expected start.  Since we aren't stateful you can't
+        //be sure your start even comes back, and you don't want to erroneously remove columns
+        if ( shouldCheckFirst && resultsTree.size() > 0  && start != null) {
+            final int startIndex = start.position();
+            final int startLength = start.remaining();
+
+
+
+            final ByteBuffer returnedBuffer = resultsTree.get( 0 ).getName();
+            final int returnedIndex = returnedBuffer.position();
+            final int returnedLength = returnedBuffer.remaining();
+
+
+            final int compare = FBUtilities.compareUnsigned( start.array(), returnedBuffer.array(),  startIndex, returnedIndex, startLength, returnedLength ) ;
+
+            //the byte buffers are the same as our seek (which may or may not be the case in the first seek)
+            if(compare == 0){
+                resultsTree.remove( 0 );
+            }
         }
 
         lastResults = resultsTree;
@@ -159,6 +174,27 @@ public class IndexBucketScanner implements IndexScanner {
     }
 
 
+    /**
+     * Returns true if the 2 byte buffers contain the same bytes, false otherwise
+     * @param first
+     * @param second
+     * @return
+     */
+    private boolean compareBuffer(final ByteBuffer first, final ByteBuffer second){
+        int firstLength = first.remaining();
+        int firstPosition = first.position();
+
+        int secondLength = second.remaining();
+        int secondPosition = second.position();
+
+        final int compare = FBUtilities.compareUnsigned( first.array(), second.array(),  firstPosition, secondPosition, firstLength, secondLength);
+
+        return compare == 0;
+
+
+    }
+
+
     /*
      * (non-Javadoc)
      *
@@ -235,4 +271,5 @@ public class IndexBucketScanner implements IndexScanner {
     public boolean isReversed() {
         return this.reversed;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/StartToBytes.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/StartToBytes.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/StartToBytes.java
new file mode 100644
index 0000000..c6516b8
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/StartToBytes.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.persistence.cassandra.index;
+
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * Parse our index values into byte buffer
+ */
+public interface StartToBytes<T> {
+
+    /**
+     * Convert the start scanning type to bytes
+     * @param toBytes
+     * @return
+     */
+    ByteBuffer toBytes(final T toBytes);
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/UUIDStartToBytes.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/UUIDStartToBytes.java b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/UUIDStartToBytes.java
new file mode 100644
index 0000000..2cdf9fd
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/cassandra/index/UUIDStartToBytes.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.persistence.cassandra.index;
+
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import me.prettyprint.cassandra.serializers.UUIDSerializer;
+
+
+/**
+ * Converts a UUID to bytes
+ */
+public class UUIDStartToBytes implements StartToBytes<UUID> {
+
+    public static final UUIDStartToBytes INSTANCE = new UUIDStartToBytes();
+
+    private UUIDStartToBytes(){}
+
+    private static final UUIDSerializer UUID_SERIALIZER = UUIDSerializer.get();
+
+    @Override
+    public ByteBuffer toBytes( final UUID toBytes ) {
+        return UUID_SERIALIZER.toByteBuffer( toBytes );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/SearchVisitor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/SearchVisitor.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/SearchVisitor.java
index 410b99f..fc2df4d 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/SearchVisitor.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/SearchVisitor.java
@@ -49,8 +49,6 @@ import org.apache.usergrid.persistence.query.ir.result.UnionIterator;
  */
 public abstract class SearchVisitor implements NodeVisitor {
 
-    private static final SecondaryIndexSliceParser COLLECTION_PARSER = new SecondaryIndexSliceParser();
-
     protected final Query query;
 
     protected final QueryProcessor queryProcessor;
@@ -162,7 +160,7 @@ public abstract class SearchVisitor implements NodeVisitor {
 
         final int nodeId = node.getId();
 
-        UnionIterator union = new UnionIterator( queryProcessor.getPageSizeHint( node ), nodeId, queryProcessor.getCursorCache( nodeId ) );
+        UnionIterator union = new UnionIterator( queryProcessor.getPageSizeHint( node ), nodeId );
 
         if ( left != null ) {
             union.addIterator( left );
@@ -211,7 +209,7 @@ public abstract class SearchVisitor implements NodeVisitor {
             if ( subResults == null ) {
                 QuerySlice firstFieldSlice = new QuerySlice( slice.getPropertyName(), -1 );
                 subResults =
-                        new SliceIterator( slice, secondaryIndexScan( orderByNode, firstFieldSlice ), COLLECTION_PARSER );
+                        new SliceIterator( slice, secondaryIndexScan( orderByNode, firstFieldSlice ), new SecondaryIndexSliceParser() );
             }
 
             orderIterator = new OrderByIterator( slice, orderByNode.getSecondarySorts(), subResults, em,
@@ -230,7 +228,7 @@ public abstract class SearchVisitor implements NodeVisitor {
                 scanner = secondaryIndexScan( orderByNode, slice );
             }
 
-            SliceIterator joinSlice = new SliceIterator( slice, scanner, COLLECTION_PARSER);
+            SliceIterator joinSlice = new SliceIterator( slice, scanner, new SecondaryIndexSliceParser());
 
             IntersectionIterator union = new IntersectionIterator( queryProcessor.getPageSizeHint( orderByNode ) );
             union.addIterator( joinSlice );
@@ -261,7 +259,7 @@ public abstract class SearchVisitor implements NodeVisitor {
         for ( QuerySlice slice : node.getAllSlices() ) {
             IndexScanner scanner = secondaryIndexScan( node, slice );
 
-            intersections.addIterator( new SliceIterator( slice, scanner, COLLECTION_PARSER) );
+            intersections.addIterator( new SliceIterator( slice, scanner, new SecondaryIndexSliceParser()) );
         }
 
         results.push( intersections );

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/AbstractScanColumn.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/AbstractScanColumn.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/AbstractScanColumn.java
index 383ead7..2a359be 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/AbstractScanColumn.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/AbstractScanColumn.java
@@ -30,9 +30,9 @@ import org.apache.cassandra.utils.ByteBufferUtil;
  */
 public abstract class AbstractScanColumn implements ScanColumn {
 
-    private final UUID uuid;
-    private final ByteBuffer buffer;
-    private ScanColumn child;
+    protected final UUID uuid;
+    protected final ByteBuffer buffer;
+    protected ScanColumn child;
 
 
     protected AbstractScanColumn( final UUID uuid, final ByteBuffer columnNameBuffer ) {
@@ -58,13 +58,13 @@ public abstract class AbstractScanColumn implements ScanColumn {
         if ( this == o ) {
             return true;
         }
-        if ( !( o instanceof AbstractScanColumn ) ) {
+        if ( !( o instanceof ScanColumn ) ) {
             return false;
         }
 
-        AbstractScanColumn that = ( AbstractScanColumn ) o;
+        ScanColumn that = ( ScanColumn ) o;
 
-        return uuid.equals( that.uuid );
+        return uuid.equals( that.getUUID() );
     }
 
 
@@ -94,24 +94,4 @@ public abstract class AbstractScanColumn implements ScanColumn {
         return child;
     }
 
-
-    /**
-     * Comparator for comparing children.  A null safe call
-     * @param otherScanColumn
-     * @return
-     */
-    protected int compareChildren( final ScanColumn otherScanColumn ) {
-
-        if ( otherScanColumn == null ) {
-            return 1;
-        }
-
-        final ScanColumn otherChild = otherScanColumn.getChild();
-
-        if ( child != null && otherChild != null ) {
-            return child.compareTo( otherChild );
-        }
-
-        return 0;
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/GatherIterator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/GatherIterator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/GatherIterator.java
index 29912cc..5bc91e0 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/GatherIterator.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/GatherIterator.java
@@ -1,11 +1,16 @@
 package org.apache.usergrid.persistence.query.ir.result;
 
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.UUID;
 
@@ -21,18 +26,20 @@ import org.apache.usergrid.persistence.query.ir.SearchVisitor;
 public class GatherIterator implements ResultIterator {
 
 
-    private final Collection<SearchVisitor> searchVisitors;
     private final QueryNode rootNode;
     private final int pageSize;
 
 
-    private Set<ScanColumn> next;
+    private Iterator<ScanColumn> mergedIterators;
+    private Map<UUID, ResultIterator> cursorMap;
+    private List<ResultIterator> iterators;
 
 
     public GatherIterator(final int pageSize, final QueryNode rootNode, final Collection<SearchVisitor> searchVisitors) {
         this.pageSize = pageSize;
         this.rootNode = rootNode;
-        this.searchVisitors = searchVisitors;
+        this.cursorMap = new HashMap<UUID, ResultIterator>( pageSize );
+        createIterators( searchVisitors );
     }
 
 
@@ -45,6 +52,14 @@ public class GatherIterator implements ResultIterator {
     @Override
     public void finalizeCursor( final CursorCache cache, final UUID lastValue ) {
         //find the last value in the tree, and return it's cursor
+        final ResultIterator sourceIterator = cursorMap.get( lastValue );
+
+        if(sourceIterator == null){
+            throw new IllegalArgumentException( "Could not find the iterator that provided the candidate with uuid " + lastValue );
+        }
+
+        //delegate to the source iterator
+        sourceIterator.finalizeCursor( cache, lastValue );
     }
 
 
@@ -56,12 +71,11 @@ public class GatherIterator implements ResultIterator {
 
     @Override
     public boolean hasNext() {
-
-        if(next() == null){
-            advance();
+        if(mergedIterators == null || !mergedIterators.hasNext()){
+            mergeIterators();
         }
 
-        return next != null;
+        return mergedIterators.hasNext();
     }
 
 
@@ -71,38 +85,76 @@ public class GatherIterator implements ResultIterator {
             throw new NoSuchElementException( "No more elements" );
         }
 
-        final Set<ScanColumn> results = next;
-        next = null;
-        return results;
+        return getNextPage();
+    }
+
+    private void createIterators(final Collection<SearchVisitor> searchVisitors ){
+
+        this.iterators = new ArrayList<ResultIterator>( searchVisitors.size() );
+
+        for(SearchVisitor visitor: searchVisitors){
+
+            try {
+                rootNode.visit( visitor );
+            }
+            catch ( Exception e ) {
+                throw new RuntimeException( "Unable to process query", e );
+            }
+
+            final ResultIterator iterator = visitor.getResults();
+
+            iterators.add( iterator );
+
+        }
+
     }
 
 
     /**
+     * Get the next page of results
+     * @return
+     */
+    private Set<ScanColumn> getNextPage(){
+
+        //try to take from our PageSize
+        LinkedHashSet<ScanColumn> resultSet = new LinkedHashSet<ScanColumn>( pageSize );
+
+        for(int i = 0; i < pageSize && mergedIterators.hasNext(); i ++){
+            resultSet.add( mergedIterators.next() );
+        }
+
+
+        return resultSet;
+    }
+
+    /**
      * Advance the iterator
      */
-    private void advance(){
+    private void mergeIterators(){
         //TODO make this concurrent
 
+        //clear the cursor map
+        cursorMap.clear();
 
-        final TreeSet<ScanColumn> results = new TreeSet<ScanColumn>(  );
-
+        TreeSet<ScanColumn> merged = new TreeSet<ScanColumn>(  );
 
-        for(SearchVisitor visitor: searchVisitors){
-              merge(results, visitor);
+        for(ResultIterator iterator: this.iterators){
+              merge(merged, iterator);
         }
 
-        this.next = results;
+        mergedIterators = merged.iterator();
+
     }
 
 
+
+
     /**
      * Merge this interator into our final column results
      * @param results
-     * @param visitor
+     * @param iterator
      */
-    private void merge(final TreeSet<ScanColumn> results, final SearchVisitor visitor){
-
-        final ResultIterator iterator = visitor.getResults();
+    private void merge(final TreeSet<ScanColumn> results, final ResultIterator iterator){
 
 
         //nothing to do, return
@@ -110,19 +162,24 @@ public class GatherIterator implements ResultIterator {
             return;
         }
 
-
         final Iterator<ScanColumn> nextPage = iterator.next().iterator();
 
-
         //only take from the iterator what we need to create a full page.
         for(int i = 0 ; i < pageSize && nextPage.hasNext(); i ++){
-            results.add( nextPage.next() );
+            final ScanColumn next = nextPage.next();
+
+            results.add(next);
+            cursorMap.put( next.getUUID(), iterator );
+
+//            //results are too large, trim them
+//            if(results.size() > pageSize){
+//               final ScanColumn toRemove =  results.pollLast();
+//                cursorMap.remove( toRemove.getUUID() );
+//            }
 
-            //results are too large, trim them
-            if(results.size() > pageSize){
-                results.pollLast();
-            }
         }
 
     }
+
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchCollectionVisitor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchCollectionVisitor.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchCollectionVisitor.java
index 78abbca..c20baf4 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchCollectionVisitor.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchCollectionVisitor.java
@@ -7,6 +7,7 @@ import org.apache.usergrid.persistence.EntityRef;
 import org.apache.usergrid.persistence.IndexBucketLocator;
 import org.apache.usergrid.persistence.cassandra.CassandraService;
 import org.apache.usergrid.persistence.cassandra.QueryProcessor;
+import org.apache.usergrid.persistence.cassandra.index.DynamicCompositeStartToBytes;
 import org.apache.usergrid.persistence.cassandra.index.IndexBucketScanner;
 import org.apache.usergrid.persistence.cassandra.index.IndexScanner;
 import org.apache.usergrid.persistence.cassandra.index.NoOpIndexScanner;
@@ -77,7 +78,7 @@ public class SearchCollectionVisitor extends SearchVisitor {
         // perform the search
         else {
             columns =
-                    searchIndexBuckets( indexKey, slice, collection.getName(), queryProcessor.getPageSizeHint( node ) );
+                    searchIndexBuckets( indexKey, slice, queryProcessor.getPageSizeHint( node ) );
         }
 
         return columns;
@@ -100,10 +101,10 @@ public class SearchCollectionVisitor extends SearchVisitor {
 
 
         IndexScanner indexScanner = cassandraService
-                .getIdList( cassandraService.getApplicationKeyspace( applicationId ),
+                .getIdList(
                         key( headEntity.getUuid(), DICTIONARY_COLLECTIONS, collectionName ), startId, null,
-                        queryProcessor.getPageSizeHint( node ), query.isReversed(), indexBucketLocator, applicationId,
-                        collectionName, node.isForceKeepFirst() );
+                        queryProcessor.getPageSizeHint( node ), query.isReversed(), bucket,  applicationId,
+                        node.isForceKeepFirst() );
 
         this.results.push( new SliceIterator( slice, indexScanner, UUID_PARSER ) );
     }
@@ -149,10 +150,9 @@ public class SearchCollectionVisitor extends SearchVisitor {
      *
      * @param indexKey The index key to read
      * @param slice Slice set in the query
-     * @param collectionName The name of the collection to search
      * @param pageSize The page size to load when iterating
      */
-    private IndexScanner searchIndexBuckets( Object indexKey, QuerySlice slice, String collectionName, int pageSize )
+    private IndexScanner searchIndexBuckets( Object indexKey, QuerySlice slice, int pageSize )
             throws Exception {
 
         DynamicComposite[] range = slice.getRange();
@@ -160,7 +160,7 @@ public class SearchCollectionVisitor extends SearchVisitor {
         Object keyPrefix = key( indexKey, slice.getPropertyName() );
 
         IndexScanner scanner =
-                new IndexBucketScanner( cassandraService, ENTITY_INDEX, applicationId, keyPrefix, bucket, range[0],
+                new IndexBucketScanner( cassandraService, ENTITY_INDEX, DynamicCompositeStartToBytes.INSTANCE, applicationId, keyPrefix, bucket, range[0],
                         range[1], slice.isReversed(), pageSize, slice.hasCursor() );
 
         return scanner;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchConnectionVisitor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchConnectionVisitor.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchConnectionVisitor.java
index 74ff19f..6f833db 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchConnectionVisitor.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SearchConnectionVisitor.java
@@ -13,6 +13,7 @@ import org.apache.usergrid.persistence.cassandra.CassandraService;
 import org.apache.usergrid.persistence.cassandra.ConnectionRefImpl;
 import org.apache.usergrid.persistence.cassandra.QueryProcessor;
 import org.apache.usergrid.persistence.cassandra.index.ConnectedIndexScanner;
+import org.apache.usergrid.persistence.cassandra.index.DynamicCompositeStartToBytes;
 import org.apache.usergrid.persistence.cassandra.index.IndexBucketScanner;
 import org.apache.usergrid.persistence.cassandra.index.IndexScanner;
 import org.apache.usergrid.persistence.cassandra.index.NoOpIndexScanner;
@@ -205,7 +206,7 @@ public class SearchConnectionVisitor extends SearchVisitor {
 
 
           IndexScanner scanner =
-                  new IndexBucketScanner( cassandraService, ENTITY_INDEX, applicationId,
+                  new IndexBucketScanner( cassandraService, ENTITY_INDEX,  DynamicCompositeStartToBytes.INSTANCE, applicationId,
                           keyPrefix, shardBucket, range[0], range[1], slice.isReversed(), pageSize, slice.hasCursor());
 
           return scanner;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SecondaryIndexSliceParser.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SecondaryIndexSliceParser.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SecondaryIndexSliceParser.java
index e27d99c..b26f684 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SecondaryIndexSliceParser.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SecondaryIndexSliceParser.java
@@ -17,50 +17,85 @@
 package org.apache.usergrid.persistence.query.ir.result;
 
 
+import java.math.BigInteger;
 import java.nio.ByteBuffer;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.UUID;
 
+import org.apache.usergrid.utils.UUIDUtils;
+
 import me.prettyprint.hector.api.beans.DynamicComposite;
 
 
 /**
- * Parser for reading and writing secondary index composites
+ * Parser for reading and writing secondary index composites.  Instances of this class should not be shared among
+ * iterators.
+ *
+ * It it designed with the following assumptions in mind.
+ *
+ * 1) The slice contains the same data type for every element 2) Evaluating the first parse call for a comparator is
+ * sufficient for subsequent use
  *
  * @author tnine
  */
 public class SecondaryIndexSliceParser implements SliceParser {
 
+    //the type comparator
+    private Comparator<SecondaryIndexColumn> typeComparator;
+
+
+    public SecondaryIndexSliceParser() {}
+
 
     /* (non-Javadoc)
      * @see org.apache.usergrid.persistence.query.ir.result.SliceParser#parse(java.nio.ByteBuffer)
      */
     @Override
-    public ScanColumn parse( ByteBuffer buff, final boolean isReversed) {
-        DynamicComposite composite = DynamicComposite.fromByteBuffer( buff.duplicate() );
+    public ScanColumn parse( ByteBuffer buff, final boolean isReversed ) {
+        final DynamicComposite composite = DynamicComposite.fromByteBuffer( buff.duplicate() );
 
-        throw new UnsupportedOperationException( "Implement me with static comparators" );
+        final UUID uuid = ( UUID ) composite.get( 2 );
+        final Object value = composite.get( 1 );
 
-//        return new SecondaryIndexColumn( ( UUID ) composite.get( 2 ), composite.get( 1 ), buff, null );
+        if ( typeComparator == null ) {
+            typeComparator = getTypeComparator( value, isReversed );
+        }
+
+        return new SecondaryIndexColumn( uuid, value, buff, typeComparator );
     }
 
 
+    private Comparator<SecondaryIndexColumn> getTypeComparator( final Object value, final boolean isReversed ) {
+
+        final Class clazz = value.getClass();
+        final Comparator<SecondaryIndexColumn> comparator = COMPARATOR_MAP.get( new MapKey( clazz, isReversed ) );
+
+        if ( comparator == null ) {
+            throw new NullPointerException( "comparator was not found for runtime type '" + clazz + "'" );
+        }
+
+        return comparator;
+    }
+
 
+    /**
+     * Column for our secondary index type
+     */
     public static class SecondaryIndexColumn extends AbstractScanColumn {
 
         private final Object value;
-        private final Comparator<Object> valueComparator;
+        private final Comparator<SecondaryIndexColumn> valueComparator;
 
 
         /**
          * Create the secondary index column
-         * @param uuid
-         * @param value
-         * @param columnNameBuffer
+         *
          * @param valueComparator The comparator for the values
          */
         public SecondaryIndexColumn( final UUID uuid, final Object value, final ByteBuffer columnNameBuffer,
-                                  final Comparator<Object> valueComparator ) {
+                                     final Comparator<SecondaryIndexColumn> valueComparator ) {
             super( uuid, columnNameBuffer );
             this.value = value;
             this.valueComparator = valueComparator;
@@ -74,8 +109,169 @@ public class SecondaryIndexSliceParser implements SliceParser {
 
 
         @Override
-        public int compareTo( final ScanColumn o ) {
-            throw new UnsupportedOperationException( "Impelment me" );
+        public int compareTo( final ScanColumn other ) {
+            if ( other == null ) {
+                return 1;
+            }
+
+            return valueComparator.compare( this, ( SecondaryIndexColumn ) other );
+        }
+    }
+
+
+    private static final Map<MapKey, Comparator<SecondaryIndexColumn>> COMPARATOR_MAP =
+            new HashMap<MapKey, Comparator<SecondaryIndexColumn>>();
+
+    static {
+
+        final LongComparator longComparator = new LongComparator();
+        COMPARATOR_MAP.put( new MapKey( Long.class, false ), longComparator );
+        COMPARATOR_MAP.put( new MapKey( Long.class, true ), new ReverseComparator( longComparator ) );
+
+        final StringComparator stringComparator = new StringComparator();
+
+        COMPARATOR_MAP.put( new MapKey( String.class, false ), stringComparator );
+        COMPARATOR_MAP.put( new MapKey( String.class, true ), new ReverseComparator( stringComparator ) );
+
+
+        final UUIDComparator uuidComparator = new UUIDComparator();
+
+        COMPARATOR_MAP.put( new MapKey( UUID.class, false ), uuidComparator );
+        COMPARATOR_MAP.put( new MapKey( UUID.class, true ), new ReverseComparator( uuidComparator ) );
+
+        final BigIntegerComparator bigIntegerComparator = new BigIntegerComparator();
+
+        COMPARATOR_MAP.put( new MapKey( BigInteger.class, false ), bigIntegerComparator );
+        COMPARATOR_MAP.put( new MapKey( BigInteger.class, true ), new ReverseComparator( bigIntegerComparator ) );
+    }
+
+
+    /**
+     * The key for the map
+     */
+    private static final class MapKey {
+        public final Class<?> clazz;
+        public final boolean reversed;
+
+
+        private MapKey( final Class<?> clazz, final boolean reversed ) {
+            this.clazz = clazz;
+            this.reversed = reversed;
+        }
+
+
+        @Override
+        public boolean equals( final Object o ) {
+            if ( this == o ) {
+                return true;
+            }
+            if ( !( o instanceof MapKey ) ) {
+                return false;
+            }
+
+            final MapKey mapKey = ( MapKey ) o;
+
+            if ( reversed != mapKey.reversed ) {
+                return false;
+            }
+            return clazz.equals( mapKey.clazz );
+        }
+
+
+        @Override
+        public int hashCode() {
+            int result = clazz.hashCode();
+            result = 31 * result + ( reversed ? 1 : 0 );
+            return result;
+        }
+    }
+
+
+    private static abstract class SecondaryIndexColumnComparator implements Comparator<SecondaryIndexColumn> {
+
+        /**
+         * If the result of compare is != 0 it is returned, otherwise the uuids are compared
+         */
+        protected int compareValues( final int compare, final SecondaryIndexColumn first,
+                                     SecondaryIndexColumn second ) {
+            if ( compare != 0 ) {
+                return compare;
+            }
+
+            return com.fasterxml.uuid.UUIDComparator.staticCompare( first.uuid, second.uuid );
+        }
+    }
+
+
+    private static final class LongComparator extends SecondaryIndexColumnComparator {
+
+        @Override
+        public int compare( final SecondaryIndexColumn first, final SecondaryIndexColumn second ) {
+
+            final Long firstLong = ( Long ) first.value;
+            final Long secondLong = ( Long ) second.value;
+
+
+            return compareValues( Long.compare( firstLong, secondLong ), first, second );
+        }
+    }
+
+
+    private static final class StringComparator extends SecondaryIndexColumnComparator {
+        @Override
+        public int compare( final SecondaryIndexColumn first, final SecondaryIndexColumn second ) {
+
+            if ( first == null && second != null ) {
+                return -1;
+            }
+
+            final String firstString = ( String ) first.value;
+            final String secondString = ( String ) second.value;
+
+
+            return compareValues( firstString.compareTo( secondString ), first, second );
+        }
+    }
+
+
+    private static final class UUIDComparator extends SecondaryIndexColumnComparator {
+        @Override
+        public int compare( final SecondaryIndexColumn first, final SecondaryIndexColumn second ) {
+            final UUID firstUUID = ( UUID ) first.value;
+            final UUID secondUUID = ( UUID ) second.value;
+
+
+            return compareValues( UUIDUtils.compare( firstUUID, secondUUID ), first, second );
+        }
+    }
+
+
+    private static final class BigIntegerComparator extends SecondaryIndexColumnComparator {
+        @Override
+        public int compare( final SecondaryIndexColumn first, final SecondaryIndexColumn second ) {
+            final BigInteger firstInt = ( BigInteger ) first.value;
+            final BigInteger secondInt = ( BigInteger ) second.value;
+
+
+            return compareValues( firstInt.compareTo( secondInt ), first, second );
+        }
+    }
+
+
+    /**
+     * Reversed our comparator
+     */
+    private static final class ReverseComparator implements Comparator<SecondaryIndexColumn> {
+
+        private final Comparator<SecondaryIndexColumn> comparator;
+
+
+        private ReverseComparator( final Comparator<SecondaryIndexColumn> comparator ) {this.comparator = comparator;}
+
+
+        @Override
+        public int compare( final SecondaryIndexColumn first, final SecondaryIndexColumn second ) {
+            return comparator.compare( first, second ) * -1;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SliceIterator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SliceIterator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SliceIterator.java
index 3f052da..a386159 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SliceIterator.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/SliceIterator.java
@@ -26,6 +26,7 @@ import java.util.UUID;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
 import org.apache.usergrid.persistence.cassandra.CursorCache;
 import org.apache.usergrid.persistence.cassandra.index.IndexScanner;
 import org.apache.usergrid.persistence.exceptions.QueryIterationException;
@@ -127,9 +128,9 @@ public class SliceIterator implements ResultIterator {
 
         while ( results.hasNext() ) {
 
-            ByteBuffer colName = results.next().getName().duplicate();
+            final ByteBuffer colName = results.next().getName().duplicate();
 
-            ScanColumn parsed = parser.parse( colName, isReversed );
+            final ScanColumn parsed = parser.parse( colName, isReversed );
 
             //skip this value, the parser has discarded it
             if ( parsed == null ) {
@@ -215,22 +216,22 @@ public class SliceIterator implements ResultIterator {
             //this is a bug
             if ( scanner.hasNext() ) {
                 logger.error(
-                        "An iterator attempted to access a slice that was not iterated over.  This will result in the" +
-                                " cursor construction failing" );
+                        "An iterator attempted to access a slice that was not iterated over.  This will result in the"
+                                + " cursor construction failing" );
                 throw new QueryIterationException(
-                        "An iterator attempted to access a slice that was not iterated over.  This will result in the" +
-                                " cursor construction failing" );
+                        "An iterator attempted to access a slice that was not iterated over.  This will result in the"
+                                + " cursor construction failing" );
             }
 
             final ByteBuffer sliceCursor = slice.getCursor();
 
             //we've never loaded anything, just re-use the existing slice
-            if (last == null && sliceCursor != null ) {
+            if ( last == null && sliceCursor != null ) {
                 bytes = sliceCursor;
             }
 
             //use the last column we loaded.  This way our scan returns nothing next time since start == finish
-            else if(last != null) {
+            else if ( last != null ) {
                 bytes = last.getCursorValue();
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDColumn.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDColumn.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDColumn.java
index a5e09c1..640b391 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDColumn.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDColumn.java
@@ -4,53 +4,35 @@ package org.apache.usergrid.persistence.query.ir.result;
 import java.nio.ByteBuffer;
 import java.util.UUID;
 
+import org.apache.usergrid.persistence.cassandra.Serializers;
 import org.apache.usergrid.utils.UUIDUtils;
 
 
 /**
  * Used as a comparator for columns
  */
-class UUIDColumn implements  ScanColumn{
+class UUIDColumn extends AbstractScanColumn{
 
-    private final UUID uuid;
     private final int compareReversed;
-    private ScanColumn child;
 
-
-    UUIDColumn( final UUID uuid, final int compareReversed ) {
-        this.uuid = uuid;
+    protected UUIDColumn( final UUID uuid, final ByteBuffer columnNameBuffer, final int compareReversed  ) {
+        super( uuid, columnNameBuffer );
         this.compareReversed = compareReversed;
     }
 
 
-    @Override
-    public UUID getUUID() {
-        return uuid;
-    }
-
-
-    @Override
-    public ByteBuffer getCursorValue() {
-        return null;
-    }
-
-
-    @Override
-    public void setChild( final ScanColumn childColumn ) {
-        this.child = childColumn;
+    public UUIDColumn( final UUID uuid, final int compareReversed ) {
+        super(uuid, Serializers.ue.toByteBuffer( uuid ));
+        this.compareReversed = compareReversed;
     }
 
 
-    @Override
-    public ScanColumn getChild() {
-        return child;
-    }
 
 
     @Override
     public int compareTo( final ScanColumn other ) {
-
         return  UUIDUtils.compare( uuid, other.getUUID() ) * compareReversed;
-
     }
+
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDIndexSliceParser.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDIndexSliceParser.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDIndexSliceParser.java
index 91644ce..2c5b1ba 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDIndexSliceParser.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UUIDIndexSliceParser.java
@@ -33,6 +33,6 @@ public class UUIDIndexSliceParser implements SliceParser {
     @Override
     public ScanColumn parse( final ByteBuffer columnNameBytes, final boolean isReversed ) {
         final int compare = isReversed? -1: 1;
-        return new UUIDColumn( ue.fromByteBuffer( columnNameBytes.duplicate() ), compare );
+        return new UUIDColumn( ue.fromByteBuffer( columnNameBytes.duplicate() ), columnNameBytes,  compare );
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UnionIterator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UnionIterator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UnionIterator.java
index 635ca97..aca9852 100644
--- a/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UnionIterator.java
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/query/ir/result/UnionIterator.java
@@ -133,7 +133,7 @@ public class UnionIterator extends MultiIterator {
 
         private final List<ScanColumn> list;
 
-        private UUIDColumn min;
+//        private UUIDColumn min;
 
 
         public SortedColumnList( final int maxSize, final UUID minUuid ) {
@@ -141,9 +141,9 @@ public class UnionIterator extends MultiIterator {
             this.list = new ArrayList<ScanColumn>( maxSize );
             this.maxSize = maxSize;
 
-            if ( minUuid != null ) {
-                min = new UUIDColumn( minUuid, 1 ) ;
-            }
+//            if ( minUuid != null ) {
+//                min = new UUIDColumn( minUuid, 1 ) ;
+//            }
         }
 
 
@@ -152,9 +152,9 @@ public class UnionIterator extends MultiIterator {
          */
         public void add( ScanColumn col ) {
             //less than our min, don't add
-            if ( min != null && min.compareTo( col ) >= 0 ) {
-                return;
-            }
+//            if ( min != null && min.compareTo( col ) >= 0 ) {
+//                return;
+//            }
 
             int index = Collections.binarySearch( this.list, col );
 
@@ -215,7 +215,7 @@ public class UnionIterator extends MultiIterator {
             }
 
             final UUID oldMin = this.list.get( size - 1 ).getUUID();
-            min = new UUIDColumn( oldMin, 1 );
+//            min = new UUIDColumn( oldMin, 1 );
         }
 
 
@@ -228,7 +228,7 @@ public class UnionIterator extends MultiIterator {
 
         public void reset(){
             clear();
-            this.min = null;
+//            this.min = null;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/68c7eae1/stack/core/src/test/java/org/apache/usergrid/persistence/CollectionIT.java
----------------------------------------------------------------------
diff --git a/stack/core/src/test/java/org/apache/usergrid/persistence/CollectionIT.java b/stack/core/src/test/java/org/apache/usergrid/persistence/CollectionIT.java
index ac58bd7..99fed21 100644
--- a/stack/core/src/test/java/org/apache/usergrid/persistence/CollectionIT.java
+++ b/stack/core/src/test/java/org/apache/usergrid/persistence/CollectionIT.java
@@ -1444,7 +1444,7 @@ public class CollectionIT extends AbstractCoreIT {
         Query query = Query.fromQL( s );
 
         Results r = em.searchCollection( em.getApplicationRef(), "loveobjects", query );
-        assertTrue( r.size() == 1 );
+        assertEquals(1,  r.size() );
 
         String username = ( String ) ( ( Map ) r.getEntities().get( 0 ).getProperty( "Recipient" ) ).get( "Username" );
         // selection results should be a list of lists