diff options
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search')
3 files changed, 111 insertions, 166 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java index 77b759973b8..aa5726bd52c 100644 --- a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java +++ b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java @@ -4,6 +4,7 @@ package com.yahoo.search.handler; import com.google.inject.Inject; import com.yahoo.collections.Tuple2; import com.yahoo.component.ComponentSpecification; +import com.yahoo.component.Vtag; import com.yahoo.component.chain.Chain; import com.yahoo.component.chain.ChainsConfigurer; import com.yahoo.component.chain.model.ChainsModel; @@ -25,7 +26,6 @@ import com.yahoo.log.LogLevel; import com.yahoo.net.UriTools; import com.yahoo.prelude.IndexFacts; import com.yahoo.prelude.IndexModel; -import com.yahoo.prelude.VespaSVersionRetriever; import com.yahoo.prelude.query.QueryException; import com.yahoo.prelude.query.parser.ParseException; import com.yahoo.prelude.query.parser.SpecialTokenRegistry; @@ -363,7 +363,7 @@ public class SearchHandler extends LoggingRequestHandler { execution.fill(result, result.getQuery().getPresentation().getSummary()); traceExecutionTimes(query, result); - traceVespaSVersion(query); + traceVespaVersion(query); traceRequestAttributes(query); return result; } @@ -519,8 +519,8 @@ public class SearchHandler extends LoggingRequestHandler { } } - private void traceVespaSVersion(Query query) { - query.trace("Vespa version: " + VespaSVersionRetriever.getVersion(), false, 4); + private void traceVespaVersion(Query query) { + query.trace("Vespa version: " + Vtag.currentVersion.toString(), false, 4); } public SearchChainRegistry getSearchChainRegistry() { diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/SortingDegrader.java b/container-search/src/main/java/com/yahoo/search/querytransform/SortingDegrader.java index 0c7871eb6e6..2597e440d17 100644 --- a/container-search/src/main/java/com/yahoo/search/querytransform/SortingDegrader.java +++ b/container-search/src/main/java/com/yahoo/search/querytransform/SortingDegrader.java @@ -69,6 +69,8 @@ public class SortingDegrader extends Searcher { } private void setDegradation(Query query) { + query.trace("Using sorting degrading for performance - totalHits will be wrong. " + + "Turn off with sorting.degrading=false.", 2); Sorting.FieldOrder primarySort = query.getRanking().getSorting().fieldOrders().get(0); // ensured above MatchPhase matchPhase = query.getRanking().getMatchPhase(); diff --git a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java index 1d400056d52..7df859c6070 100644 --- a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java +++ b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java @@ -22,7 +22,6 @@ import org.json.JSONObject; import com.fasterxml.jackson.core.JsonEncoding; import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -77,15 +76,12 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { boolean booleanValue() { switch (this) { - case YES: - return true; - case NO: - return false; - default: - throw new IllegalStateException(); + case YES: return true; + case NO: return false; + default: throw new IllegalStateException(); } } - }; + } // if this must be optimized, simply use com.fasterxml.jackson.core.SerializableString private static final String BUCKET_LIMITS = "limits"; @@ -173,8 +169,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } } - private void doVisit(final long timestamp, final Object payload, final boolean hasChildren) - throws IOException, JsonGenerationException { + private void doVisit(final long timestamp, final Object payload, final boolean hasChildren) throws IOException { boolean dirty = false; if (timestamp != 0L) { header(); @@ -216,7 +211,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } } - private void conditionalStartObject() throws IOException, JsonGenerationException { + private void conditionalStartObject() throws IOException { if (!isInsideOpenObject()) { generator.writeStartObject(); } else { @@ -303,7 +298,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { generator = null; renderedChildren = null; debugRendering = false; - timeSource = () -> System.currentTimeMillis(); + timeSource = System::currentTimeMillis; stream = null; } @@ -320,21 +315,19 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private void renderTiming() throws IOException { - if (!getResult().getQuery().getPresentation().getTiming()) { - return; - } + if (!getResult().getQuery().getPresentation().getTiming()) return; - final double milli = .001d; - final long now = timeSource.getAsLong(); - final long searchTime = now - getResult().getElapsedTime().first(); - final double searchSeconds = searchTime * milli; + double milli = .001d; + long now = timeSource.getAsLong(); + long searchTime = now - getResult().getElapsedTime().first(); + double searchSeconds = searchTime * milli; generator.writeObjectFieldStart(TIMING); if (getResult().getElapsedTime().firstFill() != 0L) { - final long queryTime = getResult().getElapsedTime().weightedSearchTime(); - final long summaryFetchTime = getResult().getElapsedTime().weightedFillTime(); - final double querySeconds = queryTime * milli; - final double summarySeconds = summaryFetchTime * milli; + long queryTime = getResult().getElapsedTime().weightedSearchTime(); + long summaryFetchTime = getResult().getElapsedTime().weightedFillTime(); + double querySeconds = queryTime * milli; + double summarySeconds = summaryFetchTime * milli; generator.writeNumberField(QUERY_TIME, querySeconds); generator.writeNumberField(SUMMARY_FETCH_TIME, summarySeconds); } @@ -344,18 +337,16 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private boolean getDebugRendering(Query q) { - return q == null ? false : q.properties().getBoolean(DEBUG_RENDERING_KEY, false); + return q != null && q.properties().getBoolean(DEBUG_RENDERING_KEY, false); } - private void renderTrace(Trace trace) throws JsonGenerationException, IOException { - if (!trace.traceNode().children().iterator().hasNext()) { - return; - } + private void renderTrace(Trace trace) throws IOException { + if (!trace.traceNode().children().iterator().hasNext()) return; + try { long basetime = trace.traceNode().timestamp(); - if (basetime == 0L) { + if (basetime == 0L) basetime = getResult().getElapsedTime().first(); - } trace.accept(new TraceRenderer(basetime)); } catch (TraceRenderWrapper e) { throw new IOException(e); @@ -365,53 +356,49 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { @Override public void beginList(DataList<?> list) throws IOException { Preconditions.checkArgument(list instanceof HitGroup, - "Expected subclass of com.yahoo.search.result.HitGroup, got %s.", - list.getClass()); + "Expected subclass of com.yahoo.search.result.HitGroup, got %s.", + list.getClass()); moreChildren(); - renderHitGroupHead((HitGroup) list); } - protected void moreChildren() throws IOException, JsonGenerationException { - if (!renderedChildren.isEmpty()) { + protected void moreChildren() throws IOException { + if (!renderedChildren.isEmpty()) childrenArray(); - } + renderedChildren.push(0); } - private void childrenArray() throws IOException, JsonGenerationException { - if (renderedChildren.peek() == 0) { + private void childrenArray() throws IOException { + if (renderedChildren.peek() == 0) generator.writeArrayFieldStart(CHILDREN); - } renderedChildren.push(renderedChildren.pop() + 1); } - private void lessChildren() throws IOException, JsonGenerationException { + private void lessChildren() throws IOException { int lastRenderedChildren = renderedChildren.pop(); if (lastRenderedChildren > 0) { generator.writeEndArray(); } } - private void renderHitGroupHead(HitGroup hitGroup) throws JsonGenerationException, IOException { - final ErrorHit errorHit = hitGroup.getErrorHit(); - + private void renderHitGroupHead(HitGroup hitGroup) throws IOException { generator.writeStartObject(); + renderHitContents(hitGroup); - if (getRecursionLevel() == 1) { + if (getRecursionLevel() == 1) renderCoverage(); - } - if (errorHit != null) { + + ErrorHit errorHit = hitGroup.getErrorHit(); + if (errorHit != null) renderErrors(errorHit.errors()); - } // the framework will invoke begin methods as needed from here } - private void renderErrors(Set<ErrorMessage> errors) throws JsonGenerationException, IOException { - if (errors.isEmpty()) { - return; - } + private void renderErrors(Set<ErrorMessage> errors) throws IOException { + if (errors.isEmpty()) return; + generator.writeArrayFieldStart(ERRORS); for (ErrorMessage e : errors) { String summary = e.getMessage(); @@ -441,11 +428,10 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } - private void renderCoverage() throws JsonGenerationException, IOException { + private void renderCoverage() throws IOException { Coverage c = getResult().getCoverage(false); - if (c == null) { - return; - } + if (c == null) return; + generator.writeObjectFieldStart(COVERAGE); generator.writeNumberField(COVERAGE_COVERAGE, c.getResultPercentage()); generator.writeNumberField(COVERAGE_DOCUMENTS, c.getDocs()); @@ -456,10 +442,8 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { generator.writeEndObject(); } - private void renderHit(Hit hit) throws JsonGenerationException, IOException { - if (!shouldRender(hit)) { - return; - } + private void renderHit(Hit hit) throws IOException { + if (!shouldRender(hit)) return; childrenArray(); generator.writeStartObject(); @@ -468,54 +452,45 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private boolean shouldRender(Hit hit) { - if (hit instanceof DefaultErrorHit) { - return false; - } - - return true; + return ! (hit instanceof DefaultErrorHit); } - private boolean fieldsStart(boolean hasFieldsField) throws JsonGenerationException, IOException { - if (hasFieldsField) { - return true; - } + private boolean fieldsStart(boolean hasFieldsField) throws IOException { + if (hasFieldsField) return true; generator.writeObjectFieldStart(FIELDS); return true; } - private void fieldsEnd(boolean hasFieldsField) throws JsonGenerationException, IOException { - if (!hasFieldsField) { - return; - } + private void fieldsEnd(boolean hasFieldsField) throws IOException { + if (!hasFieldsField) return; generator.writeEndObject(); } - private void renderHitContents(Hit hit) throws JsonGenerationException, IOException { + private void renderHitContents(Hit hit) throws IOException { String id = hit.getDisplayId(); - Set<String> types = hit.types(); - String source = hit.getSource(); - - if (id != null) { + if (id != null) generator.writeStringField(ID, id); - } + generator.writeNumberField(RELEVANCE, hit.getRelevance().getScore()); - if (types.size() > 0) { + + if (hit.types().size() > 0) { // TODO: Remove types rendering on Vespa 7 generator.writeArrayFieldStart(TYPES); - for (String t : types) { + for (String t : hit.types()) { generator.writeString(t); } generator.writeEndArray(); } - if (source != null) { + + String source = hit.getSource(); + if (source != null) generator.writeStringField(SOURCE, hit.getSource()); - } + renderSpecialCasesForGrouping(hit); renderAllFields(hit); } - private void renderAllFields(Hit hit) throws JsonGenerationException, - IOException { + private void renderAllFields(Hit hit) throws IOException { boolean hasFieldsField = false; hasFieldsField |= renderTotalHitCount(hit, hasFieldsField); @@ -523,8 +498,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { fieldsEnd(hasFieldsField); } - private boolean renderStandardFields(Hit hit, boolean initialHasFieldsField) - throws JsonGenerationException, IOException { + private boolean renderStandardFields(Hit hit, boolean initialHasFieldsField) throws IOException { boolean hasFieldsField = initialHasFieldsField; for (String fieldName : hit.fieldKeys()) { if (!shouldRender(fieldName, hit)) continue; @@ -538,55 +512,39 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private boolean shouldRender(String fieldName, Hit hit) { - if (debugRendering) { - return true; - } - if (fieldName.startsWith(VESPA_HIDDEN_FIELD_PREFIX)) { - return false; - } + if (debugRendering) return true; + + if (fieldName.startsWith(VESPA_HIDDEN_FIELD_PREFIX)) return false; RenderDecision r = lazyRenderAwareCheck(fieldName, hit); - if (r != RenderDecision.DO_NOT_KNOW) { - return r.booleanValue(); - } + if (r != RenderDecision.DO_NOT_KNOW) return r.booleanValue(); // this will trigger field decoding, so it is important the lazy decoding magic is done first Object field = hit.getField(fieldName); - if (field instanceof CharSequence && ((CharSequence) field).length() == 0) { - return false; - } - if (field instanceof StringFieldValue && ((StringFieldValue) field).getString().isEmpty()) { - // StringFieldValue cannot hold a null, so checking length directly is OK - return false; - } - if (field instanceof NanNumber) { - return false; - } + if (field instanceof CharSequence && ((CharSequence) field).length() == 0) return false; + + // StringFieldValue cannot hold a null, so checking length directly is OK: + if (field instanceof StringFieldValue && ((StringFieldValue) field).getString().isEmpty()) return false; + + if (field instanceof NanNumber) return false; return true; } private RenderDecision lazyRenderAwareCheck(String fieldName, Hit hit) { - if (!(hit instanceof FastHit)) return RenderDecision.DO_NOT_KNOW; + if ( ! (hit instanceof FastHit)) return RenderDecision.DO_NOT_KNOW; FastHit asFastHit = (FastHit) hit; if (asFastHit.fieldIsNotDecoded(fieldName)) { - FastHit.RawField r = asFastHit.fetchFieldAsUtf8(fieldName); - if (r != null) { - byte[] utf8 = r.getUtf8(); - if (utf8.length == 0) { - return RenderDecision.NO; - } else { - return RenderDecision.YES; - } - } + FastHit.RawField rawField = asFastHit.fetchFieldAsUtf8(fieldName); + if (rawField != null) + return rawField.getUtf8().length == 0 ? RenderDecision.NO : RenderDecision.YES; } return RenderDecision.DO_NOT_KNOW; } - private void renderSpecialCasesForGrouping(Hit hit) - throws JsonGenerationException, IOException { + private void renderSpecialCasesForGrouping(Hit hit) throws IOException { if (hit instanceof AbstractList) { renderGroupingListSyntheticFields((AbstractList) hit); } else if (hit instanceof Group) { @@ -594,8 +552,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } } - private void renderGroupingGroupSyntheticFields(Hit hit) - throws JsonGenerationException, IOException { + private void renderGroupingGroupSyntheticFields(Hit hit) throws IOException { renderGroupMetadata(((Group) hit).getGroupId()); if (hit instanceof RootGroup) { renderContinuations(Collections.singletonMap( @@ -603,22 +560,18 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } } - private void renderGroupingListSyntheticFields(AbstractList a) - throws JsonGenerationException, IOException { + private void renderGroupingListSyntheticFields(AbstractList a) throws IOException { writeGroupingLabel(a); renderContinuations(a.continuations()); } - private void writeGroupingLabel(AbstractList a) - throws JsonGenerationException, IOException { + private void writeGroupingLabel(AbstractList a) throws IOException { generator.writeStringField(LABEL, a.getLabel()); } - private void renderContinuations(Map<String, Continuation> continuations) - throws JsonGenerationException, IOException { - if (continuations.isEmpty()) { - return; - } + private void renderContinuations(Map<String, Continuation> continuations) throws IOException { + if (continuations.isEmpty()) return; + generator.writeObjectFieldStart(CONTINUATION); for (Map.Entry<String, Continuation> e : continuations.entrySet()) { generator.writeStringField(e.getKey(), e.getValue().toString()); @@ -626,17 +579,14 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { generator.writeEndObject(); } - private void renderGroupMetadata(GroupId id) throws JsonGenerationException, - IOException { - if (!(id instanceof ValueGroupId || id instanceof BucketGroupId)) { - return; - } + private void renderGroupMetadata(GroupId id) throws IOException { + if (!(id instanceof ValueGroupId || id instanceof BucketGroupId)) return; if (id instanceof ValueGroupId) { - final ValueGroupId<?> valueId = (ValueGroupId<?>) id; + ValueGroupId<?> valueId = (ValueGroupId<?>) id; generator.writeStringField(GROUPING_VALUE, getIdValue(valueId)); - } else if (id instanceof BucketGroupId) { - final BucketGroupId<?> bucketId = (BucketGroupId<?>) id; + } else { + BucketGroupId<?> bucketId = (BucketGroupId<?>) id; generator.writeObjectFieldStart(BUCKET_LIMITS); generator.writeStringField(BUCKET_FROM, getBucketFrom(bucketId)); generator.writeStringField(BUCKET_TO, getBucketTo(bucketId)); @@ -645,40 +595,33 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private static String getIdValue(ValueGroupId<?> id) { - return (id instanceof RawId ? Arrays.toString(((RawId) id).getValue()) - : id.getValue()).toString(); + return (id instanceof RawId ? Arrays.toString(((RawId) id).getValue()) : id.getValue()).toString(); } private static String getBucketFrom(BucketGroupId<?> id) { - return (id instanceof RawBucketId ? Arrays.toString(((RawBucketId) id) - .getFrom()) : id.getFrom()).toString(); + return (id instanceof RawBucketId ? Arrays.toString(((RawBucketId) id).getFrom()) : id.getFrom()).toString(); } private static String getBucketTo(BucketGroupId<?> id) { - return (id instanceof RawBucketId ? Arrays.toString(((RawBucketId) id) - .getTo()) : id.getTo()).toString(); + return (id instanceof RawBucketId ? Arrays.toString(((RawBucketId) id).getTo()) : id.getTo()).toString(); } - private boolean renderTotalHitCount(Hit hit, boolean hasFieldsField) - throws JsonGenerationException, IOException { - if (getRecursionLevel() == 1 && hit instanceof HitGroup) { - fieldsStart(hasFieldsField); - generator.writeNumberField(TOTAL_COUNT, getResult() - .getTotalHitCount()); - return true; - } else { - return false; - } + private boolean renderTotalHitCount(Hit hit, boolean hasFieldsField) throws IOException { + if ( ! (getRecursionLevel() == 1 && hit instanceof HitGroup)) return false; + + fieldsStart(hasFieldsField); + generator.writeNumberField(TOTAL_COUNT, getResult().getTotalHitCount()); + return true; } - private void renderField(String fieldName, Hit hit) throws JsonGenerationException, IOException { + private void renderField(String fieldName, Hit hit) throws IOException { generator.writeFieldName(fieldName); - if (!tryDirectRendering(fieldName, hit)) { + if ( ! tryDirectRendering(fieldName, hit)) { renderFieldContents(hit.getField(fieldName)); } } - private void renderFieldContents(Object field) throws JsonGenerationException, IOException { + private void renderFieldContents(Object field) throws IOException { if (field == null) { generator.writeNull(); } else if (field instanceof Number) { @@ -711,7 +654,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } } - private void renderNumberField(Number field) throws JsonGenerationException, IOException { + private void renderNumberField(Number field) throws IOException { if (field instanceof Integer) { generator.writeNumber(field.intValue()); } else if (field instanceof Float) { @@ -734,8 +677,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { /** * Really a private method, but package access for testability. */ - boolean tryDirectRendering(String fieldName, Hit hit) - throws IOException, JsonGenerationException { + boolean tryDirectRendering(String fieldName, Hit hit) throws IOException { boolean renderedAsUtf8 = false; if (hit instanceof FastHit) { FastHit f = (FastHit) hit; @@ -755,8 +697,8 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { @Override public void data(Data data) throws IOException { Preconditions.checkArgument(data instanceof Hit, - "Expected subclass of com.yahoo.search.result.Hit, got %s.", - data.getClass()); + "Expected subclass of com.yahoo.search.result.Hit, got %s.", + data.getClass()); renderHit((Hit) data); } @@ -785,8 +727,8 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { private Result getResult() { Response r = getResponse(); Preconditions.checkArgument(r instanceof Result, - "JsonRenderer can only render instances of com.yahoo.search.Result, got instance of %s.", - r.getClass()); + "JsonRenderer can only render instances of com.yahoo.search.Result, got instance of %s.", + r.getClass()); return (Result) r; } @@ -841,4 +783,5 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { void setTimeSource(LongSupplier timeSource) { this.timeSource = timeSource; } + } |