summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/dispatch
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2019-09-16 22:57:02 +0200
committerGitHub <noreply@github.com>2019-09-16 22:57:02 +0200
commit049d1eb173f90f002e9f7251476fa0c8a71e6f7e (patch)
tree432ee8550037db4765d5fe8bad542b7038643fe3 /container-search/src/main/java/com/yahoo/search/dispatch
parent74a39bfa696568cf2d94b9c3a773f4fc0c2d0d54 (diff)
Revert "Revert "Revert "Revert "Use a LeanHit until merging is done." MERGEOK"""
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/dispatch')
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java74
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/InvokerResult.java52
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/LeanHit.java63
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java13
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java50
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java3
7 files changed, 167 insertions, 92 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 388a31d1482..84e5e7d747f 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
@@ -93,10 +93,9 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM
}
@Override
- protected Result getSearchResult(Execution execution) throws IOException {
- Result result = new Result(query);
- List<Hit> merged = Collections.emptyList();
- List<Hit> auxiliary = new ArrayList<>();
+ protected InvokerResult getSearchResult(Execution execution) throws IOException {
+ InvokerResult result = new InvokerResult(query, query.getHits());
+ List<LeanHit> merged = Collections.emptyList();
long nextTimeout = query.getTimeLeft();
try {
while (!invokers.isEmpty() && nextTimeout >= 0) {
@@ -105,7 +104,7 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM
log.fine(() -> "Search timed out with " + askedNodes + " requests made, " + answeredNodes + " responses received");
break;
} else {
- merged = mergeResult(result, invoker.getSearchResult(execution), merged, auxiliary);
+ merged = mergeResult(result.getResult(), invoker.getSearchResult(execution), merged);
ejectInvoker(invoker);
}
nextTimeout = nextTimeout();
@@ -114,12 +113,11 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM
throw new RuntimeException("Interrupted while waiting for search results", e);
}
- insertNetworkErrors(result);
- result.setCoverage(createCoverage());
+ insertNetworkErrors(result.getResult());
+ result.getResult().setCoverage(createCoverage());
int needed = query.getOffset() + query.getHits();
- result.hits().addAll(auxiliary);
for (int index = query.getOffset(); (index < merged.size()) && (index < needed); index++) {
- result.hits().add(merged.get(index));
+ result.getLeanHits().add(merged.get(index));
}
query.setOffset(0); // Now we are all trimmed down
return result;
@@ -191,43 +189,31 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM
return nextAdaptive;
}
- private List<Hit> mergeResult(Result result, Result partialResult, List<Hit> current, List<Hit> auxiliaryHits) {
- collectCoverage(partialResult.getCoverage(true));
+ private List<LeanHit> mergeResult(Result result, InvokerResult partialResult, List<LeanHit> current) {
+ collectCoverage(partialResult.getResult().getCoverage(true));
- result.mergeWith(partialResult);
- List<Hit> partial = partialResult.hits().asUnorderedHits();
- if (current.isEmpty() ) {
- boolean hasAuxillary = false;
- for(Hit hit : partial) {
- if (hit.isAuxiliary()) {
- hasAuxillary = true;
- break;
- }
+ result.mergeWith(partialResult.getResult());
+ List<Hit> partialNonLean = partialResult.getResult().hits().asUnorderedHits();
+ for(Hit hit : partialNonLean) {
+ if (hit.isAuxiliary()) {
+ result.hits().add(hit);
}
- if ( ! hasAuxillary)
- return partial;
}
+ if (current.isEmpty() ) {
+ return partialResult.getLeanHits();
+ }
+ List<LeanHit> partial = partialResult.getLeanHits();
if (partial.isEmpty()) {
return current;
}
int needed = query.getOffset() + query.getHits();
- List<Hit> merged = new ArrayList<>(needed);
+ List<LeanHit> merged = new ArrayList<>(needed);
int indexCurrent = 0;
int indexPartial = 0;
while (indexCurrent < current.size() && indexPartial < partial.size() && merged.size() < needed) {
- Hit incommingHit = partial.get(indexPartial);
- if (incommingHit.isAuxiliary()) {
- auxiliaryHits.add(incommingHit);
- indexPartial++;
- continue;
- }
- Hit currentHit = current.get(indexCurrent);
- if (currentHit.isAuxiliary()) {
- auxiliaryHits.add(currentHit);
- indexCurrent++;
- continue;
- }
+ LeanHit incommingHit = partial.get(indexPartial);
+ LeanHit currentHit = current.get(indexCurrent);
int cmpRes = currentHit.compareTo(incommingHit);
if (cmpRes < 0) {
@@ -242,21 +228,11 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM
indexPartial++;
}
}
- while (indexCurrent < current.size()) {
- Hit h = current.get(indexCurrent++);
- if (h.isAuxiliary()) {
- auxiliaryHits.add(h);
- } else if (merged.size() < needed) {
- merged.add(h);
- }
+ while ((indexCurrent < current.size()) && (merged.size() < needed)) {
+ merged.add(current.get(indexCurrent++));
}
- while (indexPartial < partial.size()) {
- Hit h = partial.get(indexPartial++);
- if (h.isAuxiliary()) {
- auxiliaryHits.add(h);
- } else if (merged.size() < needed) {
- merged.add(h);
- }
+ while ((indexPartial < partial.size()) && (merged.size() < needed)) {
+ merged.add(partial.get(indexPartial++));
}
return merged;
}
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/InvokerResult.java b/container-search/src/main/java/com/yahoo/search/dispatch/InvokerResult.java
new file mode 100644
index 00000000000..cd8228624c5
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/InvokerResult.java
@@ -0,0 +1,52 @@
+package com.yahoo.search.dispatch;
+
+import com.yahoo.prelude.fastsearch.FastHit;
+import com.yahoo.search.Query;
+import com.yahoo.search.Result;
+import com.yahoo.search.query.Sorting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Wraps a Result and a flat, skinny hit list
+ */
+public class InvokerResult {
+ private final Result result;
+ private final List<LeanHit> leanHits;
+ public InvokerResult(Result result) {
+ this.result = result;
+ this.leanHits = Collections.emptyList();
+ }
+ public InvokerResult(Query query, int expectedHits) {
+ result = new Result(query);
+ leanHits = new ArrayList<>(expectedHits);
+ }
+
+ public Result getResult() {
+ return result;
+ }
+
+ public List<LeanHit> getLeanHits() {
+ return leanHits;
+ }
+ void complete() {
+ Query query = result.getQuery();
+ Sorting sorting = query.getRanking().getSorting();
+ for (LeanHit hit : leanHits) {
+ FastHit fh = new FastHit(hit.getGid(), hit.getRelevance(), hit.getPartId(), hit.getDistributionKey());
+ if (hit.hasSortData()) {
+ fh.setSortData(hit.getSortData(), sorting);
+ }
+ if (hit.getQueryPacketData() != null) {
+ fh.setQueryPacketData(hit.getQueryPacketData());
+ }
+ fh.setQuery(query);
+ fh.setFillable();
+ fh.setCached(false);
+ result.hits().add(fh);
+ }
+ leanHits.clear();
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/LeanHit.java b/container-search/src/main/java/com/yahoo/search/dispatch/LeanHit.java
new file mode 100644
index 00000000000..6ec0e3f27d1
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/LeanHit.java
@@ -0,0 +1,63 @@
+package com.yahoo.search.dispatch;
+
+import com.yahoo.fs4.QueryPacketData;
+
+import java.util.Arrays;
+
+public class LeanHit implements Comparable<LeanHit> {
+ private final byte [] gid;
+ private final double relevance;
+ private final byte [] sortData;
+ private final int partId;
+ private final int distributionKey;
+ //TODO Remove when FS4 is gone
+ private QueryPacketData queryPacketData;
+ public LeanHit(byte [] gid, int partId, int distributionKey, double relevance) {
+ this.gid = gid;
+ this.relevance = relevance;
+ this.sortData = null;
+ this.partId = partId;
+ this.distributionKey = distributionKey;
+ }
+ public LeanHit(byte [] gid, int partId, int distributionKey, byte [] sortData) {
+ this.gid = gid;
+ this.relevance = Double.NEGATIVE_INFINITY;
+ this.sortData = sortData;
+ this.partId = partId;
+ this.distributionKey = distributionKey;
+ }
+ public double getRelevance() { return relevance; }
+ public byte [] getGid() { return gid; }
+ public byte [] getSortData() { return sortData; }
+ public boolean hasSortData() { return sortData != null; }
+ public int getPartId() { return partId; }
+ public int getDistributionKey() { return distributionKey; }
+
+ QueryPacketData getQueryPacketData() { return queryPacketData; }
+
+ public void setQueryPacketData(QueryPacketData queryPacketData) {
+ this.queryPacketData = queryPacketData;
+ }
+
+ @Override
+ public int compareTo(LeanHit o) {
+ int res = (sortData != null)
+ ? compareData(sortData, o.sortData)
+ : Double.compare(o.relevance, relevance);
+ return (res != 0) ? res : compareData(gid, o.gid);
+ }
+
+ private static int compareData(byte [] left, byte [] right) {
+ int i = Arrays.mismatch(left, right);
+ if (i < 0) {
+ return 0;
+ }
+ int max = Integer.min(left.length, right.length);
+ if (i >= max) {
+ return left.length - right.length;
+ }
+ int vl = (int) left[i] & 0xFF;
+ int vr = (int) right[i] & 0xFF;
+ return vl - vr;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java
index b1d25dddbb8..52a45dc421c 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java
@@ -42,12 +42,12 @@ public class SearchErrorInvoker extends SearchInvoker {
}
@Override
- protected Result getSearchResult(Execution execution) throws IOException {
+ protected InvokerResult getSearchResult(Execution execution) throws IOException {
Result res = new Result(query, message);
if (coverage != null) {
res.setCoverage(coverage);
}
- return res;
+ return new InvokerResult(res);
}
@Override
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java
index 3bfb9089457..77b3df7c83a 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java
@@ -32,14 +32,15 @@ public abstract class SearchInvoker extends CloseableInvoker {
*/
public Result search(Query query, Execution execution) throws IOException {
sendSearchRequest(query);
- Result result = getSearchResult(execution);
- setFinalStatus(result.hits().getError() == null);
- return result;
+ InvokerResult result = getSearchResult(execution);
+ setFinalStatus(result.getResult().hits().getError() == null);
+ result.complete();
+ return result.getResult();
}
protected abstract void sendSearchRequest(Query query) throws IOException;
- protected abstract Result getSearchResult(Execution execution) throws IOException;
+ protected abstract InvokerResult getSearchResult(Execution execution) throws IOException;
protected void setMonitor(ResponseMonitor<SearchInvoker> monitor) {
this.monitor = monitor;
@@ -55,12 +56,12 @@ public abstract class SearchInvoker extends CloseableInvoker {
return node.map(Node::key);
}
- protected Result errorResult(Query query, ErrorMessage errorMessage) {
+ protected InvokerResult errorResult(Query query, ErrorMessage errorMessage) {
Result error = new Result(query, errorMessage);
Coverage errorCoverage = new Coverage(0, 0, 0);
errorCoverage.setNodesTried(1);
error.setCoverage(errorCoverage);
- return error;
+ return new InvokerResult(error);
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java
index 6039e09bbe1..7fd41862212 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java
@@ -15,6 +15,8 @@ import com.yahoo.prelude.fastsearch.GroupingListHit;
import com.yahoo.prelude.fastsearch.VespaBackEndSearcher;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
+import com.yahoo.search.dispatch.InvokerResult;
+import com.yahoo.search.dispatch.LeanHit;
import com.yahoo.search.grouping.vespa.GroupingExecutor;
import com.yahoo.search.query.Model;
import com.yahoo.search.query.QueryTree;
@@ -22,7 +24,6 @@ import com.yahoo.search.query.Ranking;
import com.yahoo.search.query.Sorting;
import com.yahoo.search.query.Sorting.Order;
import com.yahoo.search.result.Coverage;
-import com.yahoo.search.result.Relevance;
import com.yahoo.searchlib.aggregation.Grouping;
import com.yahoo.slime.BinaryFormat;
import com.yahoo.vespa.objects.BufferSerializer;
@@ -180,31 +181,22 @@ public class ProtobufSerialization {
return convertFromResult(searchResult).toByteArray();
}
- static Result deserializeToSearchResult(byte[] payload, Query query, VespaBackEndSearcher searcher, int partId, int distKey)
+ static InvokerResult deserializeToSearchResult(byte[] payload, Query query, VespaBackEndSearcher searcher, int partId, int distKey)
throws InvalidProtocolBufferException {
var protobuf = SearchProtocol.SearchReply.parseFrom(payload);
- return convertToResult(query, protobuf, searcher.getDocumentDatabase(query), partId, distKey, searcher.getName());
+ return convertToResult(query, protobuf, searcher.getDocumentDatabase(query), partId, distKey);
}
- private static Result convertToResult(Query query,
- SearchProtocol.SearchReply protobuf,
- DocumentDatabase documentDatabase,
- int partId,
- int distKey,
- String source) {
- var result = new Result(query);
+ static InvokerResult convertToResult(Query query, SearchProtocol.SearchReply protobuf,
+ DocumentDatabase documentDatabase, int partId, int distKey)
+ {
+ InvokerResult result = new InvokerResult(query, protobuf.getHitsCount());
- result.setTotalHitCount(protobuf.getTotalHitCount());
- result.setCoverage(convertToCoverage(protobuf));
+ result.getResult().setTotalHitCount(protobuf.getTotalHitCount());
+ result.getResult().setCoverage(convertToCoverage(protobuf));
- int hitItems = protobuf.getHitsCount();
var haveGrouping = protobuf.getGroupingBlob() != null && !protobuf.getGroupingBlob().isEmpty();
if (haveGrouping) {
- hitItems++;
- }
- result.hits().ensureCapacity(hitItems);
-
- if (haveGrouping) {
BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer(protobuf.getGroupingBlob().asReadOnlyByteBuffer()));
int cnt = buf.getInt(null);
ArrayList<Grouping> list = new ArrayList<>(cnt);
@@ -215,26 +207,16 @@ public class ProtobufSerialization {
}
GroupingListHit hit = new GroupingListHit(list, documentDatabase.getDocsumDefinitionSet());
hit.setQuery(query);
- result.hits().add(hit);
+ result.getResult().hits().add(hit);
}
- var sorting = query.getRanking().getSorting();
for (var replyHit : protobuf.getHitsList()) {
- FastHit hit = new FastHit(replyHit.getGlobalId().toByteArray(), new Relevance(replyHit.getRelevance()), partId, distKey);
- hit.setQuery(query);
-
- if (!replyHit.getSortData().isEmpty()) {
- hit.setSortData(replyHit.getSortData().toByteArray(), sorting);
- }
- hit.setFillable();
- hit.setCached(false);
- hit.setSource(source);
-
- result.hits().add(hit);
- }
- if (sorting != null) {
- result.hits().setSorted(true);
+ LeanHit hit = (replyHit.getSortData().isEmpty())
+ ? new LeanHit(replyHit.getGlobalId().toByteArray(), partId, distKey, replyHit.getRelevance())
+ : new LeanHit(replyHit.getGlobalId().toByteArray(), partId, distKey, replyHit.getSortData().toByteArray());
+ result.getLeanHits().add(hit);
}
+
var slimeTrace = protobuf.getSlimeTrace();
if (slimeTrace != null && !slimeTrace.isEmpty()) {
var traces = new Value.ArrayValue();
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java
index 9f42e794f5e..59f17501c32 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java
@@ -6,6 +6,7 @@ import com.yahoo.compress.Compressor;
import com.yahoo.prelude.fastsearch.VespaBackEndSearcher;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
+import com.yahoo.search.dispatch.InvokerResult;
import com.yahoo.search.dispatch.SearchInvoker;
import com.yahoo.search.dispatch.rpc.Client.ProtobufResponse;
import com.yahoo.search.dispatch.searchcluster.Node;
@@ -60,7 +61,7 @@ public class RpcSearchInvoker extends SearchInvoker implements Client.ResponseRe
}
@Override
- protected Result getSearchResult(Execution execution) throws IOException {
+ protected InvokerResult getSearchResult(Execution execution) throws IOException {
long timeLeftMs = query.getTimeLeft();
if (timeLeftMs <= 0) {
return errorResult(query, ErrorMessage.createTimeout("Timeout while waiting for " + getName()));