summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search')
-rw-r--r--container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java8
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/SortingDegrader.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java267
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;
}
+
}