private Result buildResultFromCompletedVisitor(Query query, Visitor visitor, Visitor.Context context) {
        lazyTrace(query, 8, "offset=", query.getOffset(), ", hits=", query.getHits());

        String summaryClass = query.getPresentation().getSummary();
        var partialSummaryHandler = context.partialSummaryHandler();
        if (partialSummaryHandler != null) {
            summaryClass = partialSummaryHandler.askForSummary();
        }
        Result result = new Result(query);
        List<SearchResult.Hit> hits = visitor.getHits(); // Sorted on rank
        Map<String, DocumentSummary.Summary> summaryMap = visitor.getSummaryMap();

        lazyTrace(query, 7, "total hit count = ", visitor.getTotalHitCount(),
                  ", returned hit count = ", hits.size(), ", summary count = ",
                  summaryMap.size());

        VisitorStatistics stats = visitor.getStatistics();
        result.setTotalHitCount(visitor.getTotalHitCount());
        result.setCoverage(new Coverage(stats.getDocumentsVisited(), stats.getDocumentsVisited(), 1, 1));
        query.trace(visitor.getStatistics().toString(), false, 2);
        query.getContext(true).setProperty(STREAMING_STATISTICS, stats);

        DocsumPacket[] summaryPackets = new DocsumPacket [hits.size()];

        int index = 0;
        boolean skippedEarlierResult = false;
        for (SearchResult.Hit hit : hits) {
            if (!verifyDocId(hit.getDocId(), query, skippedEarlierResult)) {
                skippedEarlierResult = true;
                continue;
            }
            FastHit fastHit = buildSummaryHit(query, hit);
            result.hits().add(fastHit);

            DocumentSummary.Summary summary = summaryMap.get(hit.getDocId());
            if (summary != null) {
                DocsumPacket dp = new DocsumPacket(summary.getSummary());
                summaryPackets[index] = dp;
            } else {
                return new Result(query, ErrorMessage.createBackendCommunicationError("Did not find summary for hit with document id " +
                                                                                      hit.getDocId()));
            }
            index++;
        }
        if (result.isFilled(summaryClass)) {
            lazyTrace(query, 8, "Result is filled for summary class ", summaryClass);
        } else {
            lazyTrace(query, 8, "Result is not filled for summary class ", summaryClass);
        }

        List<Grouping> groupingList = visitor.getGroupings();
        lazyTrace(query, 8, "Grouping list=", groupingList);
        if ( ! groupingList.isEmpty() ) {
            GroupingListHit groupHit = new GroupingListHit(groupingList, getDocumentDatabase(query), query);
            result.hits().add(groupHit);
        }

        FillHitsResult fillHitsResult = fillHits(result, summaryPackets, summaryClass);
        int skippedHits = fillHitsResult.skippedHits;
        if (fillHitsResult.error != null) {
            result.hits().addError(ErrorMessage.createTimeout(fillHitsResult.error));
            return result;
        }

        if (skippedHits == 0) {
            query.trace("All hits have been filled",4); // TODO: cache results or result.analyzeHits(); ?
        } else {
            lazyTrace(query, 8, "Skipping some hits for query: ", result.getQuery());
        }

        lazyTrace(query, 8, "Returning result ", result);

        if (skippedHits > 0) {
            log.info("skipping " + skippedHits + " hits for query: " + result.getQuery());
            result.hits().addError(ErrorMessage.createTimeout("Missing hit summary data for " + skippedHits + " hits"));
        }

        var errors = visitor.getErrors();
        for (var error : errors) {
            result.hits().addError(ErrorMessage.createSearchReplyError(error));
        }

        return result;
    }
The route to the storage cluster.
container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingBackend.java