summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java47
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) {