diff options
Diffstat (limited to 'container-search/src/main/java/com')
4 files changed, 63 insertions, 33 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/Presentation.java b/container-search/src/main/java/com/yahoo/search/query/Presentation.java index afa87eb4a06..b949d1edabd 100644 --- a/container-search/src/main/java/com/yahoo/search/query/Presentation.java +++ b/container-search/src/main/java/com/yahoo/search/query/Presentation.java @@ -77,6 +77,9 @@ public class Presentation implements Cloneable { /** Whether to renders tensors in short form */ private boolean tensorShortForm = true; + /** Whether to renders tensors in short form */ + private boolean tensorDirectValues = false; // TODO: Flip default on Vespa 9 + /** Set of explicitly requested summary fields, instead of summary classes */ private Set<String> summaryFields = LazySet.newHashSet(); @@ -178,34 +181,61 @@ public class Presentation implements Cloneable { /** * Returns whether tensors should use short form in JSON and textual representations, see - * <a href="https://docs.vespa.ai/en/reference/document-json-format.html#tensor">https://docs.vespa.ai/en/reference/document-json-format.html#tensor</a> - * and <a href="https://docs.vespa.ai/en/reference/tensor.html#tensor-literal-form">https://docs.vespa.ai/en/reference/tensor.html#tensor-literal-form</a>. + * <a href="https://docs.vespa.ai/en/reference/document-json-format.html#tensor">https://docs.vespa.ai/en/reference/document-json-format.html#tensor</a>. * Default is true. */ public boolean getTensorShortForm() { return tensorShortForm; } + /** @deprecated use setTensorFormat(). */ + @Deprecated // TODO: Remove on Vespa 9 + public void setTensorShortForm(String value) { + setTensorFormat(value); + } /** * Sets whether tensors should use short form in JSON and textual representations from a string. * * @param value a string which must be either 'short' or 'long' * @throws IllegalArgumentException if any other value is passed */ - public void setTensorShortForm(String value) { - tensorShortForm = toTensorShortForm(value); - } - - private boolean toTensorShortForm(String value) { + public void setTensorFormat(String value) { switch (value) { - case "short": return true; - case "long": return false; - default: throw new IllegalArgumentException("Value must be 'long' or 'short', not '" + value + "'"); - } + case "short" : + tensorShortForm = true; + tensorDirectValues = false; + break; + case "long" : + tensorShortForm = false; + tensorDirectValues = false; + break; + case "short-value" : + tensorShortForm = true; + tensorDirectValues = true; + break; + case "long-value" : + tensorShortForm = false; + tensorDirectValues = true; + break; + default : throw new IllegalArgumentException("Value must be 'long', 'short', 'long-value', or 'short-value', not '" + value + "'"); + }; } public void setTensorShortForm(boolean tensorShortForm) { this.tensorShortForm = tensorShortForm; } + /** + * Returns whether tensor content should be rendered directly, or inside a JSON object containing a + * "type" entry having the tensor type, and a "cells"/"values"/"blocks" entry (depending on type), + * having the tensor content. See + * <a href="https://docs.vespa.ai/en/reference/document-json-format.html#tensor">https://docs.vespa.ai/en/reference/document-json-format.html#tensor</a>. + * Default is false: Render wrapped in a JSON object. + */ + public boolean getTensorDirectValues() { return tensorDirectValues; } + + public void setTensorDirectValues(boolean tensorDirectValues) { + this.tensorDirectValues = tensorDirectValues; + } + /** Prepares this for binary serialization. For internal use - see {@link Query#prepare} */ public void prepare() { if (highlight != null) @@ -214,8 +244,7 @@ public class Presentation implements Cloneable { @Override public boolean equals(Object o) { - if ( ! (o instanceof Presentation)) return false; - Presentation p = (Presentation) o; + if ( ! (o instanceof Presentation p)) return false; return QueryHelper.equals(bolding, p.bolding) && QueryHelper.equals(summary, p.summary); } diff --git a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java index d5dc8120f29..e4a83972fae 100644 --- a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java +++ b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java @@ -303,7 +303,7 @@ public class QueryProperties extends Properties { } else if (key.size() == 3 && key.get(1).equals(Presentation.FORMAT)) { if (key.last().equals(Presentation.TENSORS)) - query.getPresentation().setTensorShortForm(asString(value, "short")); + query.getPresentation().setTensorFormat(asString(value, "short")); // TODO: Switch default to short-value on Vespa 9 else throwIllegalParameter(key.last(), Presentation.FORMAT); } 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 31f99ab1927..352a31553e7 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 @@ -45,6 +45,7 @@ import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; import com.yahoo.search.result.NanNumber; import com.yahoo.tensor.Tensor; +import com.yahoo.tensor.TensorType; import com.yahoo.tensor.serialization.JsonFormat; import java.io.IOException; @@ -132,6 +133,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { volatile boolean jsonMapsAll = true; volatile boolean jsonWsetsAll = false; volatile boolean tensorShortForm = true; + volatile boolean tensorDirectValues = false; boolean convertDeep() { return (jsonDeepMaps || jsonWsets); } void init() { this.debugRendering = false; @@ -140,6 +142,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { this.jsonMapsAll = true; this.jsonWsetsAll = true; this.tensorShortForm = true; + this.tensorDirectValues = false; } void getSettings(Query q) { if (q == null) { @@ -154,7 +157,8 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { this.jsonMapsAll = props.getBoolean(WRAP_DEEP_MAPS, true); this.jsonWsetsAll = props.getBoolean(WRAP_WSETS, true); this.tensorShortForm = q.getPresentation().getTensorShortForm(); - } + this.tensorDirectValues = q.getPresentation().getTensorDirectValues(); + } } private volatile FieldConsumerSettings fieldConsumerSettings; @@ -776,7 +780,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } else if (field instanceof Tensor) { renderTensor(Optional.of((Tensor)field)); } else if (field instanceof FeatureData) { - generator().writeRawValue(((FeatureData)field).toJson(settings.tensorShortForm)); + generator().writeRawValue(((FeatureData)field).toJson(settings.tensorShortForm, settings.tensorDirectValues)); } else if (field instanceof Inspectable) { renderInspectorDirect(((Inspectable)field).inspect()); } else if (field instanceof JsonProducer) { @@ -814,24 +818,15 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private void renderTensor(Optional<Tensor> tensor) throws IOException { - if (tensor.isEmpty()) { - generator().writeStartObject(); - generator().writeArrayFieldStart("cells"); - generator().writeEndArray(); - generator().writeEndObject(); - return; - } - if (settings.tensorShortForm) { - generator().writeRawValue(new String(JsonFormat.encodeShortForm(tensor.get()), StandardCharsets.UTF_8)); - } else { - generator().writeRawValue(new String(JsonFormat.encode(tensor.get()), StandardCharsets.UTF_8)); - } + generator().writeRawValue(new String(JsonFormat.encode(tensor.orElse(Tensor.Builder.of(TensorType.empty).build()), + settings.tensorShortForm, settings.tensorDirectValues), + StandardCharsets.UTF_8)); } private JsonGenerator generator() { if (generator == null) throw new UnsupportedOperationException("Generator required but not assigned. " + - "All accept() methods must be overridden when sub-classing FieldConsumer"); + "All accept() methods must be overridden when sub-classing FieldConsumer"); return generator; } diff --git a/container-search/src/main/java/com/yahoo/search/result/FeatureData.java b/container-search/src/main/java/com/yahoo/search/result/FeatureData.java index 2cb5e0e07e9..421f19475a6 100644 --- a/container-search/src/main/java/com/yahoo/search/result/FeatureData.java +++ b/container-search/src/main/java/com/yahoo/search/result/FeatureData.java @@ -65,16 +65,20 @@ public class FeatureData implements Inspectable, JsonProducer { } public String toJson(boolean tensorShortForm) { + return toJson(tensorShortForm, false); + } + + public String toJson(boolean tensorShortForm, boolean tensorDirectValues) { if (this == empty) return "{}"; if (jsonForm != null) return jsonForm; - jsonForm = JsonRender.render(value, new Encoder(new StringBuilder(), true, tensorShortForm)).toString(); + jsonForm = JsonRender.render(value, new Encoder(new StringBuilder(), true, tensorShortForm, tensorDirectValues)).toString(); return jsonForm; } @Override public StringBuilder writeJson(StringBuilder target) { - return JsonRender.render(value, new Encoder(target, true, false)); + return JsonRender.render(value, new Encoder(target, true, false, false)); } /** @@ -173,17 +177,19 @@ public class FeatureData implements Inspectable, JsonProducer { private static class Encoder extends JsonRender.StringEncoder { private final boolean tensorShortForm; + private final boolean tensorDirectValues; - Encoder(StringBuilder out, boolean compact, boolean tensorShortForm) { + Encoder(StringBuilder out, boolean compact, boolean tensorShortForm, boolean tensorDirectValues) { super(out, compact); this.tensorShortForm = tensorShortForm; + this.tensorDirectValues = tensorDirectValues; } @Override public void encodeDATA(byte[] value) { // This could be done more efficiently ... Tensor tensor = TypedBinaryFormat.decode(Optional.empty(), GrowableByteBuffer.wrap(value)); - byte[] encodedTensor = tensorShortForm ? JsonFormat.encodeShortForm(tensor) : JsonFormat.encodeWithType(tensor); + byte[] encodedTensor = JsonFormat.encode(tensor, tensorShortForm, tensorDirectValues); target().append(new String(encodedTensor, StandardCharsets.UTF_8)); } |