diff options
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java index bf0abb1132f..5b2521f324d 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java @@ -6,13 +6,17 @@ import com.yahoo.search.Result; import com.yahoo.search.dispatch.searchcluster.SearchCluster; import com.yahoo.search.result.Coverage; import com.yahoo.search.result.ErrorMessage; +import com.yahoo.search.result.Hit; +import com.yahoo.search.result.HitGroup; import com.yahoo.search.searchchain.Execution; import com.yahoo.vespa.config.search.DispatchConfig; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; @@ -56,8 +60,6 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM private boolean timedOut = false; private boolean degradedByMatchPhase = false; - private boolean trimResult = false; - public InterleavedSearchInvoker(Collection<SearchInvoker> invokers, SearchCluster searchCluster, Set<Integer> alreadyFailedNodes) { super(Optional.empty()); this.invokers = Collections.newSetFromMap(new IdentityHashMap<>()); @@ -82,7 +84,6 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM int originalOffset = query.getOffset(); query.setHits(query.getHits() + query.getOffset()); query.setOffset(0); - trimResult = originalHits != query.getHits() || originalOffset != query.getOffset(); for (SearchInvoker invoker : invokers) { invoker.sendSearchRequest(query); @@ -95,6 +96,8 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM @Override protected Result getSearchResult(Execution execution) throws IOException { + + List<Hit> merged = Collections.emptyList(); long nextTimeout = query.getTimeLeft(); try { while (!invokers.isEmpty() && nextTimeout >= 0) { @@ -103,7 +106,7 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM log.fine(() -> "Search timed out with " + askedNodes + " requests made, " + answeredNodes + " responses received"); break; } else { - mergeResult(invoker.getSearchResult(execution)); + merged = mergeResult(invoker.getSearchResult(execution), merged); ejectInvoker(invoker); } nextTimeout = nextTimeout(); @@ -117,18 +120,15 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM } insertNetworkErrors(); result.setCoverage(createCoverage()); - trimResult(execution); + int needed = query.getOffset() + query.getHits(); + for (int index = query.getOffset(); (index < merged.size()) && (index < needed); index++) { + result.hits().add(merged.get(index)); + } Result ret = result; result = null; return ret; } - private void trimResult(Execution execution) { - if (trimResult || result.hits().size() > query.getHits()) { - result.hits().trim(query.getOffset(), query.getHits()); - } - } - private void insertNetworkErrors() { // Network errors will be reported as errors only when all nodes fail, otherwise they are just traced boolean asErrors = answeredNodes == 0; @@ -195,15 +195,34 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM return nextAdaptive; } - private void mergeResult(Result partialResult) { + private List<Hit> mergeResult(Result partialResult, List<Hit> current) { collectCoverage(partialResult.getCoverage(true)); if (result == null) { result = partialResult; - return; + return result.hits().asUnorderedHits(); } result.mergeWith(partialResult); - result.hits().addAll(partialResult.hits().asUnorderedHits()); + int needed = query.getOffset() + query.getHits(); + List<Hit> partial = partialResult.hits().asUnorderedHits(); + List<Hit> merged = new ArrayList<>(needed); + int indexCurrent = 0; + int indexPartial = 0; + while (indexCurrent < current.size() && indexPartial < partial.size() && merged.size() < needed) { + int cmpRes = current.get(indexCurrent).compareTo(partial.get(indexPartial)); + if (cmpRes <= 0) { + merged.add(current.get(indexCurrent++)); + } else { + merged.add(partial.get(indexPartial++)); + } + } + while ((indexCurrent < current.size()) && (merged.size() < needed)) { + merged.add(current.get(indexCurrent++)); + } + while ((indexPartial < partial.size()) && (merged.size() < needed)) { + merged.add(partial.get(indexPartial++)); + } + return merged; } private void collectCoverage(Coverage source) { |