aboutsummaryrefslogtreecommitdiffstats
path: root/container-search
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
parent74a39bfa696568cf2d94b9c3a773f4fc0c2d0d54 (diff)
Revert "Revert "Revert "Revert "Use a LeanHit until merging is done." MERGEOK"""
Diffstat (limited to 'container-search')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java12
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FS4SearchInvoker.java63
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java3
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java11
-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
-rw-r--r--container-search/src/test/java/com/yahoo/search/dispatch/LeanHitTest.java42
-rw-r--r--container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java16
-rw-r--r--container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java68
14 files changed, 323 insertions, 151 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
index e637e168030..4ffcc0a4330 100644
--- a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
@@ -184,8 +184,7 @@ public class ClusterSearcher extends Searcher {
: !host.equals(HostName.getLocalhost());
}
- private static ClusterParams makeClusterParams(int searchclusterIndex,
- int dispatchIndex) {
+ private static ClusterParams makeClusterParams(int searchclusterIndex, int dispatchIndex) {
return new ClusterParams("sc" + searchclusterIndex + ".num" + dispatchIndex);
}
@@ -195,11 +194,10 @@ public class ClusterSearcher extends Searcher {
DocumentdbInfoConfig documentdbInfoConfig,
Backend backend,
Dispatcher dispatcher,
- int dispatcherIndex) {
- ClusterParams clusterParams = makeClusterParams(searchclusterIndex,
- dispatcherIndex);
- return new FastSearcher(backend, fs4ResourcePool, dispatcher, docSumParams, clusterParams,
- documentdbInfoConfig);
+ int dispatcherIndex)
+ {
+ ClusterParams clusterParams = makeClusterParams(searchclusterIndex, dispatcherIndex);
+ return new FastSearcher(backend, fs4ResourcePool, dispatcher, docSumParams, clusterParams, documentdbInfoConfig);
}
private static VdsStreamingSearcher vdsCluster(String serverId,
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FS4SearchInvoker.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FS4SearchInvoker.java
index 33715921e6d..f3867288b29 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FS4SearchInvoker.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FS4SearchInvoker.java
@@ -18,6 +18,8 @@ import com.yahoo.prelude.ConfigurationException;
import com.yahoo.processing.request.CompoundName;
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.dispatch.ResponseMonitor;
import com.yahoo.search.dispatch.SearchInvoker;
import com.yahoo.search.dispatch.searchcluster.Node;
@@ -89,7 +91,7 @@ public class FS4SearchInvoker extends SearchInvoker implements ResponseMonitor<F
}
@Override
- protected Result getSearchResult(Execution execution) throws IOException {
+ protected InvokerResult getSearchResult(Execution execution) throws IOException {
if (pendingSearchError != null) {
return errorResult(query, pendingSearchError);
}
@@ -117,11 +119,10 @@ public class FS4SearchInvoker extends SearchInvoker implements ResponseMonitor<F
if (query.getPresentation().getSummary() == null)
query.getPresentation().setSummary(searcher.getDefaultDocsumClass());
- Result result = new Result(query);
+ InvokerResult result = new InvokerResult(query, resultPacket.getDocumentCount());
- ensureResultHitCapacity(result, resultPacket);
- addMetaInfo(query, queryPacket.getQueryPacketData(), resultPacket, result);
- addUnfilledHits(result, resultPacket.getDocuments(), queryPacket.getQueryPacketData());
+ addMetaInfo(query, queryPacket.getQueryPacketData(), resultPacket, result.getResult());
+ addUnfilledHits(result.getLeanHits(), resultPacket.getDocuments(), queryPacket.getQueryPacketData());
return result;
}
@@ -138,14 +139,6 @@ public class FS4SearchInvoker extends SearchInvoker implements ResponseMonitor<F
return queryPacket;
}
- private void ensureResultHitCapacity(Result result, QueryResultPacket resultPacket) {
- int hitCount = resultPacket.getDocumentCount();
- if (resultPacket.getGroupData() != null) {
- hitCount++;
- }
- result.hits().ensureCapacity(hitCount);
- }
-
private void addMetaInfo(Query query, QueryPacketData queryPacketData, QueryResultPacket resultPacket, Result result) {
result.setTotalHitCount(resultPacket.getTotalDocumentCount());
@@ -192,47 +185,21 @@ public class FS4SearchInvoker extends SearchInvoker implements ResponseMonitor<F
/**
* Creates unfilled hits from a List of DocumentInfo instances.
*/
- private void addUnfilledHits(Result result, List<DocumentInfo> documents, QueryPacketData queryPacketData) {
- Query myQuery = result.getQuery();
- Sorting sorting = myQuery.getRanking().getSorting();
+ private void addUnfilledHits(List<LeanHit> result, List<DocumentInfo> documents, QueryPacketData queryPacketData) {
Optional<Integer> channelDistributionKey = distributionKey();
for (DocumentInfo document : documents) {
-
- try {
- FastHit hit = new FastHit();
- hit.setQuery(myQuery);
- if (queryPacketData != null)
- hit.setQueryPacketData(queryPacketData);
-
- hit.setFillable();
- hit.setCached(false);
-
- extractDocumentInfo(hit, document, sorting);
- channelDistributionKey.ifPresent(hit::setDistributionKey);
-
- result.hits().add(hit);
- } catch (ConfigurationException e) {
- log.log(LogLevel.WARNING, "Skipping hit", e);
- } catch (Exception e) {
- log.log(LogLevel.ERROR, "Skipping malformed hit", e);
- }
+ byte [] sortData = document.getSortData();
+ LeanHit hit = (sortData == null)
+ ? new LeanHit(document.getRawGlobalId(), document.getPartId(), channelDistributionKey.orElse(document.getDistributionKey()), document.getMetric())
+ : new LeanHit(document.getRawGlobalId(), document.getPartId(), channelDistributionKey.orElse(document.getDistributionKey()), document.getSortData());
+ if (queryPacketData != null) {
+ hit.setQueryPacketData(queryPacketData);
+ }
+ result.add(hit);
}
}
- private void extractDocumentInfo(FastHit hit, DocumentInfo document, Sorting sorting) {
- hit.setSource(getName());
-
- Number rank = document.getMetric();
-
- hit.setRelevance(new Relevance(rank.doubleValue()));
-
- hit.setDistributionKey(document.getDistributionKey());
- hit.setGlobalId(document.getRawGlobalId());
- hit.setPartId(document.getPartId());
- hit.setSortData(document.getSortData(), sorting);
- }
-
@Override
public void release() {
if (channel != null) {
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
index 63f3c8acc20..f7f2d08d713 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
@@ -75,6 +75,9 @@ public class FastHit extends Hit {
distributionKey = 0;
}
+ public FastHit(byte [] gid, double relevance, int partId, int distributionKey) {
+ this(gid, new Relevance(relevance), partId, distributionKey);
+ }
public FastHit(byte [] gid, Relevance relevance, int partId, int distributionKey) {
super(relevance);
this.globalId = gid;
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
index 6d3ae440152..6b0041a9e86 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
@@ -22,6 +22,8 @@ import com.yahoo.search.grouping.GroupingRequest;
import com.yahoo.search.grouping.request.GroupingOperation;
import com.yahoo.search.query.Ranking;
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 java.io.IOException;
@@ -141,12 +143,21 @@ public class FastSearcher extends VespaBackEndSearcher {
QueryRewrite.rewriteSddocname(query);
}
+ private void injectSource(HitGroup hits) {
+ for (Hit hit : hits.asUnorderedHits()) {
+ if (hit instanceof FastHit) {
+ hit.setSource(getName());
+ }
+ }
+ }
+
@Override
public Result doSearch2(Query query, Execution execution) {
if (dispatcher.searchCluster().groupSize() == 1)
forceSinglePassGrouping(query);
try(SearchInvoker invoker = getSearchInvoker(query)) {
Result result = invoker.search(query, execution);
+ injectSource(result.hits());
if (query.properties().getBoolean(Ranking.RANKFEATURES, false)) {
// There is currently no correct choice for which
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()));
diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/LeanHitTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/LeanHitTest.java
new file mode 100644
index 00000000000..3478038e427
--- /dev/null
+++ b/container-search/src/test/java/com/yahoo/search/dispatch/LeanHitTest.java
@@ -0,0 +1,42 @@
+package com.yahoo.search.dispatch;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class LeanHitTest {
+ byte [] gidA = {'a'};
+ byte [] gidB = {'b'};
+ byte [] gidC = {'c'};
+ private void verifyTransitiveOrdering(LeanHit a, LeanHit b, LeanHit c) {
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(c) < 0);
+ assertTrue(a.compareTo(c) < 0);
+ assertTrue(b.compareTo(a) > 0);
+ assertTrue(c.compareTo(b) > 0);
+ assertTrue(c.compareTo(a) > 0);
+ }
+ @Test
+ public void testOrderingByRelevance() {
+ assertEquals(0, new LeanHit(gidA, 0, 0, 1).compareTo(new LeanHit(gidA, 0, 0, 1)));
+ verifyTransitiveOrdering(new LeanHit(gidA, 0, 0, 1),
+ new LeanHit(gidA, 0, 0, 0),
+ new LeanHit(gidA, 0, 0, -1));
+ }
+ @Test
+ public void testOrderingByGid() {
+ assertEquals(0, new LeanHit(gidA, 0, 0, 1).compareTo(new LeanHit(gidA, 0, 0, 1)));
+
+ verifyTransitiveOrdering(new LeanHit(gidA, 0, 0, 1),
+ new LeanHit(gidB, 0, 0, 1),
+ new LeanHit(gidC, 0, 0, 1));
+ }
+ @Test
+ public void testOrderingBySortData() {
+ assertEquals(0, new LeanHit(gidA, 0, 0, gidA).compareTo(new LeanHit(gidA, 0, 0, gidA)));
+ verifyTransitiveOrdering(new LeanHit(gidA, 0, 0, gidA),
+ new LeanHit(gidA, 0, 0, gidB),
+ new LeanHit(gidA, 0, 0, gidC));
+ }
+}
diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java b/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java
index 4b2f63d6b89..2fe434d6f3f 100644
--- a/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java
+++ b/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java
@@ -1,6 +1,7 @@
// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
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.dispatch.searchcluster.Node;
@@ -37,13 +38,20 @@ class MockInvoker extends SearchInvoker {
}
@Override
- protected Result getSearchResult(Execution execution) throws IOException {
- Result ret = new Result(query);
+ protected InvokerResult getSearchResult(Execution execution) throws IOException {
+ InvokerResult ret = new InvokerResult(query, 10);
if (coverage != null) {
- ret.setCoverage(coverage);
+ ret.getResult().setCoverage(coverage);
}
if (hits != null) {
- ret.hits().addAll(hits);
+ for (Hit h : hits) {
+ if (h instanceof FastHit) {
+ FastHit fh = (FastHit) h;
+ ret.getLeanHits().add(new LeanHit(fh.getRawGlobalId(), fh.getPartId(), fh.getDistributionKey(), fh.getRelevance().getScore()));
+ } else {
+ ret.getResult().hits().add(h);
+ }
+ }
}
return ret;
}
diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java
index 0b1d0d07e7a..b736ca1e6df 100644
--- a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java
+++ b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java
@@ -2,22 +2,32 @@
package com.yahoo.search.dispatch.rpc;
+import ai.vespa.searchlib.searchprotocol.protobuf.SearchProtocol;
+import com.google.protobuf.ByteString;
import com.yahoo.document.GlobalId;
import com.yahoo.document.idstring.IdString;
import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.search.Query;
+import com.yahoo.search.dispatch.InvokerResult;
+import com.yahoo.search.dispatch.LeanHit;
import org.junit.Test;
import java.io.IOException;
import java.util.Collections;
+import java.util.List;
import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
/**
* @author ollivir
*/
public class ProtobufSerializationTest {
+ static final double DELTA = 0.000000000001;
+
@Test
public void testDocsumSerialization() throws IOException {
Query q = new Query("search/?query=test&hits=10&offset=3");
@@ -29,4 +39,62 @@ public class ProtobufSerializationTest {
assertThat(bytes.length, equalTo(41));
}
+
+ SearchProtocol.SearchReply createSearchReply(int numHits, boolean useSorting) {
+ SearchProtocol.SearchReply.Builder reply = SearchProtocol.SearchReply.newBuilder();
+ reply.setTotalHitCount(7);
+
+ for (int i = 0; i < numHits; i++) {
+ SearchProtocol.Hit.Builder hit = SearchProtocol.Hit.newBuilder();
+ byte [] gid = {'a','a','a','a','a','a','a','a','a','a','a', (byte)i};
+ hit.setGlobalId(ByteString.copyFrom(gid));
+ if (useSorting) {
+ gid[0] = 'b';
+ hit.setSortData(ByteString.copyFrom(gid));
+ } else {
+ hit.setRelevance(numHits - i);
+ }
+ reply.addHits(hit);
+ }
+ return reply.build();
+ }
+ @Test
+ public void testSearhReplyDecodingWithRelevance() {
+ Query q = new Query("search/?query=test");
+ InvokerResult result = ProtobufSerialization.convertToResult(q, createSearchReply(5, false), null, 1, 2);
+ assertEquals(result.getResult().getTotalHitCount(), 7);
+ List<LeanHit> hits = result.getLeanHits();
+ assertEquals(5, hits.size());
+ double expectedRelevance = 5;
+ int hitNum = 0;
+ for (LeanHit hit : hits) {
+ assertEquals('a', hit.getGid()[0]);
+ assertEquals(hitNum, hit.getGid()[11]);
+ assertEquals(expectedRelevance--, hit.getRelevance(), DELTA);
+ assertEquals(1, hit.getPartId());
+ assertEquals(2, hit.getDistributionKey());
+ assertFalse(hit.hasSortData());
+ hitNum++;
+ }
+ }
+ @Test
+ public void testSearhReplyDecodingWithSortData() {
+ Query q = new Query("search/?query=test");
+ InvokerResult result = ProtobufSerialization.convertToResult(q, createSearchReply(5, true), null, 1, 2);
+ assertEquals(result.getResult().getTotalHitCount(), 7);
+ List<LeanHit> hits = result.getLeanHits();
+ assertEquals(5, hits.size());
+ int hitNum = 0;
+ for (LeanHit hit : hits) {
+ assertEquals('a', hit.getGid()[0]);
+ assertEquals(hitNum, hit.getGid()[11]);
+ assertEquals(Double.NEGATIVE_INFINITY, hit.getRelevance(), DELTA);
+ assertEquals(1, hit.getPartId());
+ assertEquals(2, hit.getDistributionKey());
+ assertTrue(hit.hasSortData());
+ assertEquals('b', hit.getSortData()[0]);
+ assertEquals(hitNum, hit.getSortData()[11]);
+ hitNum++;
+ }
+ }
}