Optional<SearchInvoker> createSearchInvoker(VespaBackend searcher,
                                                Query query,
                                                List<Node> nodes,
                                                boolean acceptIncompleteCoverage,
                                                int maxHits) {
        Group group = cluster.get(nodes.get(0).group()); // Nodes must be of the same group
        List<SearchInvoker> invokers = new ArrayList<>(nodes.size());
        Set<Integer> failed = null;
        for (Node node : nodes) {
            if (   node.isWorking() == Boolean.FALSE
                || createNodeSearchInvoker(searcher, query, maxHits, node)
                        .map(invoker -> { invokers.add(invoker); return invoker; })
                        .isEmpty()) {
                if (failed == null) {
                    failed = new HashSet<>();
                }
                failed.add(node.key());
            }
        }

        if (failed != null) {
            List<Node> success = new ArrayList<>(nodes.size() - failed.size());
            for (Node node : nodes) {
                if ( ! failed.contains(node.key())) {
                    success.add(node);
                }
            }
            if ( ! cluster.isPartialGroupCoverageSufficient(group.hasSufficientCoverage(), success) && !acceptIncompleteCoverage) {
                return Optional.empty();
            }
            if (invokers.isEmpty()) {
                return Optional.of(createCoverageErrorInvoker(nodes, failed));
            }
        }

        if (invokers.size() == 1 && failed == null) {
            return Optional.of(invokers.get(0));
        } else {
            return Optional.of(new InterleavedSearchInvoker(Timer.monotonic, invokers, hitEstimator, dispatchConfig, group, failed));
        }
    }
Creates a {@link SearchInvoker} for a list of content nodes.

@param searcher the searcher processing the query
@param query the search query being processed
@param nodes pre-selected list of content nodes, all in a group or a subset of a group
@param acceptIncompleteCoverage if some of the nodes are unavailable and this parameter is
                                false, verify that the remaining set of nodes has sufficient coverage
@return the invoker or empty if some node in the
        list is invalid and the remaining coverage is not sufficient
container-search/src/main/java/com/yahoo/search/dispatch/InvokerFactory.java