From 049d1eb173f90f002e9f7251476fa0c8a71e6f7e Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Mon, 16 Sep 2019 22:57:02 +0200 Subject: Revert "Revert "Revert "Revert "Use a LeanHit until merging is done." MERGEOK""" --- .../search/dispatch/InterleavedSearchInvoker.java | 74 ++++++++-------------- .../com/yahoo/search/dispatch/InvokerResult.java | 52 +++++++++++++++ .../java/com/yahoo/search/dispatch/LeanHit.java | 63 ++++++++++++++++++ .../yahoo/search/dispatch/SearchErrorInvoker.java | 4 +- .../com/yahoo/search/dispatch/SearchInvoker.java | 13 ++-- .../search/dispatch/rpc/ProtobufSerialization.java | 50 +++++---------- .../search/dispatch/rpc/RpcSearchInvoker.java | 3 +- 7 files changed, 167 insertions(+), 92 deletions(-) create mode 100644 container-search/src/main/java/com/yahoo/search/dispatch/InvokerResult.java create mode 100644 container-search/src/main/java/com/yahoo/search/dispatch/LeanHit.java (limited to 'container-search/src/main/java/com/yahoo/search') 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 merged = Collections.emptyList(); - List auxiliary = new ArrayList<>(); + protected InvokerResult getSearchResult(Execution execution) throws IOException { + InvokerResult result = new InvokerResult(query, query.getHits()); + List 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 mergeResult(Result result, Result partialResult, List current, List auxiliaryHits) { - collectCoverage(partialResult.getCoverage(true)); + private List mergeResult(Result result, InvokerResult partialResult, List current) { + collectCoverage(partialResult.getResult().getCoverage(true)); - result.mergeWith(partialResult); - List 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 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 partial = partialResult.getLeanHits(); if (partial.isEmpty()) { return current; } int needed = query.getOffset() + query.getHits(); - List merged = new ArrayList<>(needed); + List 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 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 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 { + 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 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,30 +181,21 @@ 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); @@ -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())); -- cgit v1.2.3