private static Result dedupe(Query query, Execution execution, String dedupField) {
        Sorting sorting = query.getRanking().getSorting();
        if (sorting != null && sorting.fieldOrders().size() > 1) {
            query.trace("Can not use grouping for deduping with multi-level sorting.", 3);
            // To support this we'd have to generate a grouping expression with as many levels
            // as there are levels in the sort spec. This is probably too slow and costly that
            // we'd ever want to actually use it (and a bit harder to implement as well).
            return execution.search(query);
        }

        int hits = query.getHits();
        int offset = query.getOffset();
        int groupingHits = hits + offset;

        GroupingRequest groupingRequest = GroupingRequest.newInstance(query);
        groupingRequest.setRootOperation(
                buildGroupingExpression(
                        dedupField,
                        groupingHits,
                        query.getPresentation().getSummary(),
                        sorting));

        query.setHits(0);
        query.setOffset(0);
        Result result = execution.search(query);

        query = result.getQuery(); // query could have changed further down in the chain
        query.setHits(hits);
        query.setOffset(offset);

        Group root = groupingRequest.getResultGroup(result);
        if (null == root) {
            String msg = "Result group not found for deduping grouping request, returning empty result.";
            query.trace(msg, 3);
            log.log(Level.WARNING, msg);
            throw new IllegalStateException("Failed to produce deduped result set.");
        }
        result.hits().remove(root.getId().toString()); // hide our tracks

        GroupList resultGroups = root.getGroupList(dedupField);
        if (resultGroups == null) {
            query.trace("Deduping grouping request returned no hits, returning empty result.", 3);
            return result;
        }

        // Make sure that .addAll() doesn't re-order the hits we copy from the grouping
        // framework. The groups are already in the order they should be.
        result.hits().setOrderer(NOP_ORDERER);
        result.hits().addAll(getRequestedHits(resultGroups, offset, hits));

        Long countField = (Long) root.getField(LABEL_COUNT);
        long count = countField != null ? countField : 0;
        result.setTotalHitCount(count);

        return result;
    }
Until we can use the grouping pagination features in 5.1, we'll have to support offset
by simply requesting and discarding hit #0 up to hit #offset.
container-search/src/main/java/com/yahoo/search/grouping/UniqueGroupingSearcher.java