diff options
author | Jon Bratseth <bratseth@verizonmedia.com> | 2019-06-28 08:56:48 -0500 |
---|---|---|
committer | Jon Bratseth <bratseth@verizonmedia.com> | 2019-06-28 08:56:48 -0500 |
commit | 781d6dfd8afdcb1da0ce29ef37ccbc0c45dc155d (patch) | |
tree | 18846b64a9ea079196591f93bd2856a8b5459b4d /container-search | |
parent | 38be09692fbc8e286ed1b669771e1c2d66e1db6c (diff) | |
parent | 4f9ad5d65f0e7fac3796830b90c2f8b9128523ce (diff) |
Merge with master
Diffstat (limited to 'container-search')
18 files changed, 181 insertions, 46 deletions
diff --git a/container-search/abi-spec.json b/container-search/abi-spec.json index 06713d14d88..cc06710480d 100644 --- a/container-search/abi-spec.json +++ b/container-search/abi-spec.json @@ -436,6 +436,7 @@ "public void lock()", "public boolean isLocked()", "public int getTermCount()", + "public java.util.Optional extractSingleChild()", "public bridge synthetic com.yahoo.prelude.query.Item clone()", "public bridge synthetic java.lang.Object clone()" ], @@ -854,7 +855,8 @@ "abstract" ], "methods": [ - "public void <init>()" + "public void <init>()", + "public java.util.Optional extractSingleChild()" ], "fields": [] }, @@ -944,6 +946,7 @@ "public void addItem(com.yahoo.prelude.query.Item)", "public void addItem(int, com.yahoo.prelude.query.Item)", "public com.yahoo.prelude.query.Item setItem(int, com.yahoo.prelude.query.Item)", + "public java.util.Optional extractSingleChild()", "public com.yahoo.prelude.query.WordItem getWordItem(int)", "public com.yahoo.prelude.query.BlockItem getBlockItem(int)", "protected void encodeThis(java.nio.ByteBuffer)", @@ -974,6 +977,7 @@ "public void setIndexName(java.lang.String)", "public void setWeight(int)", "public void addItem(com.yahoo.prelude.query.Item)", + "public java.util.Optional extractSingleChild()", "public com.yahoo.prelude.query.WordItem getWordItem(int)", "protected void encodeThis(java.nio.ByteBuffer)", "public int encode(java.nio.ByteBuffer)", @@ -1239,6 +1243,7 @@ "protected void appendHeadingString(java.lang.StringBuilder)", "protected void appendBodyString(java.lang.StringBuilder)", "protected void adding(com.yahoo.prelude.query.Item)", + "public java.util.Optional extractSingleChild()", "public com.yahoo.prelude.query.Item$ItemType getItemType()", "public java.lang.String getName()", "public java.lang.String getFieldName()" @@ -7146,12 +7151,14 @@ "methods": [ "public void <init>(com.yahoo.data.access.Inspector)", "public com.yahoo.data.access.Inspector inspect()", - "public java.lang.String toString()", "public java.lang.String toJson()", "public java.lang.StringBuilder writeJson(java.lang.StringBuilder)", "public java.lang.Double getDouble(java.lang.String)", "public com.yahoo.tensor.Tensor getTensor(java.lang.String)", - "public java.util.Set featureNames()" + "public java.util.Set featureNames()", + "public java.lang.String toString()", + "public int hashCode()", + "public boolean equals(java.lang.Object)" ], "fields": [] }, 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 3f45e8e8f00..5130cf7ff34 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 @@ -145,7 +145,6 @@ public class ClusterSearcher extends Searcher { documentDbConfig); addBackendSearcher(searcher); } else { - System.out.println("Dispatchers: " + searchClusterConfig.dispatcher().size()); for (int dispatcherIndex = 0; dispatcherIndex < searchClusterConfig.dispatcher().size(); dispatcherIndex++) { try { if ( ! isRemote(searchClusterConfig.dispatcher(dispatcherIndex).host())) { diff --git a/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java b/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java index 907eabe60ce..64f759dcf9c 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.Optional; /** @@ -379,4 +380,13 @@ public abstract class CompositeItem extends Item { return terms; } + /** + * Will return its single child if itself can safely be omitted. + * + * @return a valid Item or empty Optional if it can not be done + */ + public Optional<Item> extractSingleChild() { + return getItemCount() == 1 ? Optional.of(getItem(0)) : Optional.empty(); + } + } diff --git a/container-search/src/main/java/com/yahoo/prelude/query/NonReducibleCompositeItem.java b/container-search/src/main/java/com/yahoo/prelude/query/NonReducibleCompositeItem.java index 84aa177369a..97d724953ea 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/NonReducibleCompositeItem.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/NonReducibleCompositeItem.java @@ -1,6 +1,8 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.prelude.query; +import java.util.Optional; + /** * A composite item which specifies semantics which are not maintained * if an instance with a single child is replaced by the single child. @@ -12,4 +14,8 @@ package com.yahoo.prelude.query; * @author bratseth */ public abstract class NonReducibleCompositeItem extends CompositeItem { + @Override + public Optional<Item> extractSingleChild() { + return Optional.empty(); + } } diff --git a/container-search/src/main/java/com/yahoo/prelude/query/PhraseItem.java b/container-search/src/main/java/com/yahoo/prelude/query/PhraseItem.java index 26da5eec7eb..4de0af1f408 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/PhraseItem.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/PhraseItem.java @@ -5,6 +5,7 @@ import com.yahoo.prelude.query.textualrepresentation.Discloser; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.Optional; /** * A term which contains a phrase - a collection of word terms @@ -127,6 +128,13 @@ public class PhraseItem extends CompositeIndexedItem { } } + @Override + public Optional<Item> extractSingleChild() { + Optional<Item> extracted = super.extractSingleChild(); + extracted.ifPresent(e -> e.setWeight(this.getWeight())); + return extracted; + } + private void addIndexedItem(IndexedItem word) { word.setIndexName(this.getIndexName()); super.addItem((Item) word); diff --git a/container-search/src/main/java/com/yahoo/prelude/query/PhraseSegmentItem.java b/container-search/src/main/java/com/yahoo/prelude/query/PhraseSegmentItem.java index a19a6e53963..53a57a968f5 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/PhraseSegmentItem.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/PhraseSegmentItem.java @@ -5,6 +5,7 @@ import com.yahoo.prelude.query.textualrepresentation.Discloser; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.Optional; /** @@ -55,10 +56,12 @@ public class PhraseSegmentItem extends IndexedSegmentItem { super(rawWord, current, isFromQuery, stemmed, substring); } + @Override public ItemType getItemType() { return ItemType.PHRASE; } + @Override public String getName() { return "SPHRASE"; } @@ -87,6 +90,7 @@ public class PhraseSegmentItem extends IndexedSegmentItem { * * @throws IllegalArgumentException if the given item is not a WordItem or PhraseItem */ + @Override public void addItem(Item item) { if (item instanceof WordItem) { addWordItem((WordItem) item); @@ -95,6 +99,13 @@ public class PhraseSegmentItem extends IndexedSegmentItem { } } + @Override + public Optional<Item> extractSingleChild() { + Optional<Item> extracted = super.extractSingleChild(); + extracted.ifPresent(e -> e.setWeight(this.getWeight())); + return extracted; + } + private void addWordItem(WordItem word) { word.setIndexName(this.getIndexName()); super.addItem(word); diff --git a/container-search/src/main/java/com/yahoo/prelude/query/QueryCanonicalizer.java b/container-search/src/main/java/com/yahoo/prelude/query/QueryCanonicalizer.java index 31e69e5b7cd..88bae76b26d 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/QueryCanonicalizer.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/QueryCanonicalizer.java @@ -4,7 +4,10 @@ package com.yahoo.prelude.query; import com.yahoo.search.Query; import com.yahoo.search.query.QueryTree; -import java.util.*; +import java.util.HashSet; +import java.util.ListIterator; +import java.util.Optional; +import java.util.Set; /** * Query normalizer and sanity checker. @@ -82,15 +85,11 @@ public class QueryCanonicalizer { if (composite.getItemCount() == 0) parentIterator.remove(); - if (composite.getItemCount() == 1 && ! (composite instanceof NonReducibleCompositeItem)) { - if (composite instanceof PhraseItem || composite instanceof PhraseSegmentItem) - composite.getItem(0).setWeight(composite.getWeight()); - parentIterator.set(composite.getItem(0)); - } + composite.extractSingleChild().ifPresent(extractedChild -> parentIterator.set(extractedChild)); return CanonicalizationResult.success(); } - + private static void collapseLevels(CompositeItem composite) { if (composite instanceof RankItem || composite instanceof NotItem) { collapseLevels(composite, composite.getItemIterator()); // collapse the first item only diff --git a/container-search/src/main/java/com/yahoo/prelude/query/SameElementItem.java b/container-search/src/main/java/com/yahoo/prelude/query/SameElementItem.java index aa446140da0..d2c19339298 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/SameElementItem.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/SameElementItem.java @@ -6,6 +6,7 @@ import com.yahoo.protect.Validator; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.Optional; /** * This represents a query where all terms are required to match in the same element id. @@ -54,6 +55,16 @@ public class SameElementItem extends NonReducibleCompositeItem { Validator.ensureNonEmpty("Struct fieldname", asTerm.getIndexName()); Validator.ensureNonEmpty("Query term", asTerm.getIndexedString()); } + + @Override + public Optional<Item> extractSingleChild() { + if (getItemCount() == 1) { + WordItem child = (WordItem) getItem(0); + child.setIndexName(getFieldName() + "." + child.getIndexName()); + return Optional.of(child); + } + return Optional.empty(); + } @Override public ItemType getItemType() { diff --git a/container-search/src/main/java/com/yahoo/prelude/querytransform/QueryRewrite.java b/container-search/src/main/java/com/yahoo/prelude/querytransform/QueryRewrite.java index 2d941681f2a..84c793a6df1 100644 --- a/container-search/src/main/java/com/yahoo/prelude/querytransform/QueryRewrite.java +++ b/container-search/src/main/java/com/yahoo/prelude/querytransform/QueryRewrite.java @@ -6,7 +6,6 @@ import com.yahoo.prelude.query.CompositeItem; import com.yahoo.prelude.query.EquivItem; import com.yahoo.prelude.query.Item; import com.yahoo.prelude.query.NearItem; -import com.yahoo.prelude.query.NonReducibleCompositeItem; import com.yahoo.prelude.query.NotItem; import com.yahoo.prelude.query.NullItem; import com.yahoo.prelude.query.OrItem; @@ -215,7 +214,7 @@ public class QueryRewrite { parent.setItem(i, newChild); } } - return ((numChildren == 1) && !(parent instanceof NonReducibleCompositeItem)) ? parent.getItem(0) : item; + return parent.extractSingleChild().orElse(item); } private static Item rewriteSddocname(Item item) { diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java b/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java index 1bca3df4d77..0d47ef77ce5 100644 --- a/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java +++ b/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java @@ -45,7 +45,11 @@ public class SoftTimeout implements Cloneable { this.enabled = enable; } - public Boolean getEnable() { return enabled; } + /** Returns whether softtimeout is enabled. Defauyt is true. */ + public Boolean getEnable() { + if (enabled == null) return Boolean.TRUE; + return enabled; + } /** Override the adaptive factor determined on the content nodes */ public void setFactor(double factor) { 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 2f241f9c7a3..4bcb48447db 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 @@ -18,6 +18,7 @@ import com.yahoo.document.datatypes.StringFieldValue; import com.yahoo.document.datatypes.TensorFieldValue; import com.yahoo.document.json.JsonWriter; import com.yahoo.lang.MutableBoolean; +import com.yahoo.prelude.fastsearch.FastHit; import com.yahoo.processing.Response; import com.yahoo.processing.execution.Execution.Trace; import com.yahoo.processing.rendering.AsynchronousSectionedRenderer; @@ -39,6 +40,7 @@ import com.yahoo.search.result.Coverage; import com.yahoo.search.result.DefaultErrorHit; import com.yahoo.search.result.ErrorHit; import com.yahoo.search.result.ErrorMessage; +import com.yahoo.search.result.FeatureData; import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; import com.yahoo.search.result.NanNumber; @@ -781,7 +783,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } private void renderFieldContents(Object field) throws IOException { - if (field instanceof Inspectable) { + if (field instanceof Inspectable && ! (field instanceof FeatureData)) { renderInspector(((Inspectable)field).inspect()); } else { renderFieldContentsDirect(field); @@ -799,6 +801,8 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { generator.writeTree((TreeNode) field); } else if (field instanceof Tensor) { renderTensor(Optional.of((Tensor)field)); + } else if (field instanceof FeatureData) { + generator.writeRawValue(((FeatureData)field).toJson()); } else if (field instanceof Inspectable) { renderInspectorDirect(((Inspectable)field).inspect()); } else if (field instanceof JsonProducer) { @@ -811,8 +815,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { // the null below is the field which has already been written ((FieldValue) field).serialize(null, new JsonWriter(generator)); } else if (field instanceof JSONArray || field instanceof JSONObject) { - // org.json returns null if the object would not result in - // syntactically correct JSON + // org.json returns null if the object would not result in syntactically correct JSON String s = field.toString(); if (s == null) { generator.writeNull(); diff --git a/container-search/src/main/java/com/yahoo/search/rendering/Renderer.java b/container-search/src/main/java/com/yahoo/search/rendering/Renderer.java index c9b890e64f5..a5b51e60861 100644 --- a/container-search/src/main/java/com/yahoo/search/rendering/Renderer.java +++ b/container-search/src/main/java/com/yahoo/search/rendering/Renderer.java @@ -40,7 +40,7 @@ abstract public class Renderer extends com.yahoo.processing.rendering.Renderer<R public final ListenableFuture<Boolean> render(OutputStream stream, Result response, Execution execution, Request request) { Writer writer = null; try { - writer = createWriter(stream,response); + writer = createWriter(stream, response); render(writer, response); } catch (IOException e) { @@ -50,7 +50,7 @@ abstract public class Renderer extends com.yahoo.processing.rendering.Renderer<R if (writer !=null) try { writer.close(); } catch (IOException e2) {}; } - SettableFuture<Boolean> completed=SettableFuture.create(); + SettableFuture<Boolean> completed = SettableFuture.create(); completed.set(true); return completed; } 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 7e5d6b12f30..1fd8f6e7e17 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 @@ -18,7 +18,7 @@ import java.util.Set; /** * A wrapper for structured data representing feature values: A map of floats and tensors. - * This class is not thread safe even when it is only consumed. + * This class is immutable but not thread safe. */ public class FeatureData implements Inspectable, JsonProducer { @@ -26,6 +26,8 @@ public class FeatureData implements Inspectable, JsonProducer { private Set<String> featureNames = null; + private String jsonForm = null; + public FeatureData(Inspector value) { this.value = value; } @@ -39,14 +41,11 @@ public class FeatureData implements Inspectable, JsonProducer { public Inspector inspect() { return value; } @Override - public String toString() { - if (value.type() == Type.EMPTY) return ""; - return toJson(); - } - - @Override public String toJson() { - return writeJson(new StringBuilder()).toString(); + if (jsonForm != null) return jsonForm; + + jsonForm = writeJson(new StringBuilder()).toString(); + return jsonForm; } @Override @@ -95,6 +94,22 @@ public class FeatureData implements Inspectable, JsonProducer { return featureNames; } + @Override + public String toString() { + if (value.type() == Type.EMPTY) return ""; + return toJson(); + } + + @Override + public int hashCode() { return toJson().hashCode(); } + + @Override + public boolean equals(Object other) { + if (other == this) return true; + if ( ! (other instanceof FeatureData)) return false; + return ((FeatureData)other).toJson().equals(this.toJson()); + } + /** A JSON encoder which encodes DATA as a tensor */ private static class Encoder extends JsonRender.StringEncoder { diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java index ad4d0cf82e5..e6cc3ac9e54 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java @@ -3,9 +3,11 @@ package com.yahoo.prelude.fastsearch; import com.google.common.collect.ImmutableSet; import com.yahoo.config.subscription.ConfigGetter; +import com.yahoo.data.access.slime.SlimeAdapter; import com.yahoo.prelude.hitfield.RawData; import com.yahoo.prelude.hitfield.XMLString; import com.yahoo.prelude.hitfield.JSONString; +import com.yahoo.search.result.FeatureData; import com.yahoo.search.result.Hit; import com.yahoo.search.result.NanNumber; import com.yahoo.search.result.StructuredData; @@ -17,9 +19,11 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import com.yahoo.slime.BinaryFormat; import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; import com.yahoo.slime.Slime; import com.yahoo.tensor.Tensor; import com.yahoo.tensor.serialization.TypedBinaryFormat; @@ -62,6 +66,7 @@ public class SlimeSummaryTestCase { assertNull(hit.getField("jsonstring_field")); assertNull(hit.getField("tensor_field1")); assertNull(hit.getField("tensor_field2")); + assertNull(hit.getField("summaryfeatures")); } @Test @@ -75,7 +80,7 @@ public class SlimeSummaryTestCase { @Test public void testDecoding() { Tensor tensor1 = Tensor.from("tensor(x{},y{}):{{x:foo,y:bar}:0.1}"); - Tensor tensor2 = Tensor.from("tensor(x[],y[1]):{{x:0,y:0}:-0.3}"); + Tensor tensor2 = Tensor.from("tensor(x[1],y[1]):{{x:0,y:0}:-0.3}"); DocsumDefinitionSet docsum = createDocsumDefinitionSet(summary_cf); FastHit hit = new FastHit(); assertNull(docsum.lazyDecode("default", fullSummary(tensor1, tensor2), hit)); @@ -111,6 +116,12 @@ public class SlimeSummaryTestCase { } assertEquals(tensor1, hit.getField("tensor_field1")); assertEquals(tensor2, hit.getField("tensor_field2")); + FeatureData featureData = (FeatureData)hit.getField("summaryfeatures"); + assertEquals("double_feature,tensor1_feature,tensor2_feature", + featureData.featureNames().stream().sorted().collect(Collectors.joining(","))); + assertEquals(0.5, featureData.getDouble("double_feature"), 0.00000001); + assertEquals(tensor1, featureData.getTensor("tensor1_feature")); + assertEquals(tensor2, featureData.getTensor("tensor2_feature")); } @Test @@ -238,7 +249,9 @@ public class SlimeSummaryTestCase { assertFields(expected, hit); // --- Add full summary - assertNull(fullDocsum.lazyDecode("default", fullishSummary(), hit)); + Tensor tensor1 = Tensor.from("tensor(x{},y{}):{{x:foo,y:bar}:0.1}"); + Tensor tensor2 = Tensor.from("tensor(x[1],y[1]):{{x:0,y:0}:-0.3}"); + assertNull(fullDocsum.lazyDecode("default", fullishSummary(tensor1, tensor2), hit)); expected.put("integer_field", 4); expected.put("short_field", (short)2); expected.put("byte_field", (byte)1); @@ -247,7 +260,15 @@ public class SlimeSummaryTestCase { expected.put("int64_field", 8L); expected.put("string_field", "string_value"); expected.put("longstring_field", "longstring_value"); - assertFields(expected, hit); + expected.put("tensor_field1", tensor1); + expected.put("tensor_field2", tensor2); + + Slime slime = new Slime(); + Cursor summaryFeatures = slime.setObject(); + summaryFeatures.setDouble("double_feature", 0.5); + summaryFeatures.setData("tensor1_feature", TypedBinaryFormat.encode(tensor1)); + summaryFeatures.setData("tensor2_feature", TypedBinaryFormat.encode(tensor2)); + expected.put("summaryfeatures", new FeatureData(new SlimeAdapter(slime.get()))); hit.removeField("string_field"); hit.removeField("integer_field"); @@ -272,7 +293,7 @@ public class SlimeSummaryTestCase { fail("Multiple callbacks for " + name); traversed.put(name, value); }); - assertEquals(expected, traversed); + assertEqualMaps(expected, traversed); // raw utf8 field traverser Map<String, Object> traversedUtf8 = new HashMap<>(); hit.forEachFieldAsRaw(new Utf8FieldTraverser(traversedUtf8)); @@ -288,7 +309,7 @@ public class SlimeSummaryTestCase { // fieldKeys assertEquals(expected.keySet(), hit.fieldKeys()); // fields - assertEquals(expected, hit.fields()); + assertEqualMaps(expected, hit.fields()); // fieldIterator int fieldIteratorFieldCount = 0; for (Iterator<Map.Entry<String, Object>> i = hit.fieldIterator(); i.hasNext(); ) { @@ -302,6 +323,15 @@ public class SlimeSummaryTestCase { assertEquals(field.getValue(), hit.getField(field.getKey())); } + private void assertEqualMaps(Map<String, Object> expected, Map<String, Object> actual) { + assertEquals("Map sizes", expected.size(), actual.size()); + assertEquals("Keys", expected.keySet(), actual.keySet()); + for (var expectedEntry : expected.entrySet()) { + assertEquals("Key '" + expectedEntry.getKey() + "'", + expectedEntry.getValue(), actual.get(expectedEntry.getKey())); + } + } + private byte[] emptySummary() { Slime slime = new Slime(); slime.setObject(); @@ -339,7 +369,7 @@ public class SlimeSummaryTestCase { return encode((slime)); } - private byte[] fullishSummary() { + private byte[] fullishSummary(Tensor tensor1, Tensor tensor2) { Slime slime = new Slime(); Cursor docsum = slime.setObject(); docsum.setLong("integer_field", 4); @@ -352,6 +382,7 @@ public class SlimeSummaryTestCase { //docsum.setData("data_field", "data_value".getBytes(StandardCharsets.UTF_8)); docsum.setString("longstring_field", "longstring_value"); //docsum.setData("longdata_field", "longdata_value".getBytes(StandardCharsets.UTF_8)); + addTensors(tensor1, tensor2, docsum); return encode((slime)); } @@ -374,11 +405,23 @@ public class SlimeSummaryTestCase { field.setLong("foo", 1); field.setLong("bar", 2); } + + addTensors(tensor1, tensor2, docsum); + return encode((slime)); + } + + private void addTensors(Tensor tensor1, Tensor tensor2, Cursor docsum) { if (tensor1 != null) docsum.setData("tensor_field1", TypedBinaryFormat.encode(tensor1)); if (tensor2 != null) docsum.setData("tensor_field2", TypedBinaryFormat.encode(tensor2)); - return encode((slime)); + + if (tensor1 !=null && tensor2 != null) { + Cursor summaryFeatures = docsum.setObject("summaryfeatures"); + summaryFeatures.setDouble("double_feature", 0.5); + summaryFeatures.setData("tensor1_feature", TypedBinaryFormat.encode(tensor1)); + summaryFeatures.setData("tensor2_feature", TypedBinaryFormat.encode(tensor2)); + } } private byte[] encode(Slime slime) { diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/summary.cfg b/container-search/src/test/java/com/yahoo/prelude/fastsearch/summary.cfg index e46904b17d0..e074eadcbc2 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/summary.cfg +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/summary.cfg @@ -3,7 +3,7 @@ documentdb[0].name test documentdb[0].summaryclass[1] documentdb[0].summaryclass[0].name default documentdb[0].summaryclass[0].id 0 -documentdb[0].summaryclass[0].fields[14] +documentdb[0].summaryclass[0].fields[15] documentdb[0].summaryclass[0].fields[0].name integer_field documentdb[0].summaryclass[0].fields[0].type integer documentdb[0].summaryclass[0].fields[1].name short_field @@ -32,3 +32,5 @@ documentdb[0].summaryclass[0].fields[12].name tensor_field1 documentdb[0].summaryclass[0].fields[12].type tensor documentdb[0].summaryclass[0].fields[13].name tensor_field2 documentdb[0].summaryclass[0].fields[13].type tensor +documentdb[0].summaryclass[0].fields[14].name summaryfeatures +documentdb[0].summaryclass[0].fields[14].type featuredata diff --git a/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java b/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java index 6754494ba4e..dff6d4c26c3 100644 --- a/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java @@ -13,7 +13,7 @@ public class SoftTimeoutTestCase { @Test public void testDefaultsInQuery() { Query query=new Query("?query=test"); - assertNull(query.getRanking().getSoftTimeout().getEnable()); + assertTrue(query.getRanking().getSoftTimeout().getEnable()); assertNull(query.getRanking().getSoftTimeout().getFactor()); assertNull(query.getRanking().getSoftTimeout().getTailcost()); } @@ -21,7 +21,7 @@ public class SoftTimeoutTestCase { @Test public void testQueryOverride() { Query query=new Query("?query=test&ranking.softtimeout.factor=0.7&ranking.softtimeout.tailcost=0.3"); - assertNull(query.getRanking().getSoftTimeout().getEnable()); + assertTrue(query.getRanking().getSoftTimeout().getEnable()); assertEquals(Double.valueOf(0.7), query.getRanking().getSoftTimeout().getFactor()); assertEquals(Double.valueOf(0.3), query.getRanking().getSoftTimeout().getTailcost()); query.prepare(); diff --git a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java index 9fb2e627e9c..a245d61bafb 100644 --- a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java @@ -36,6 +36,7 @@ import com.yahoo.search.grouping.result.RootGroup; import com.yahoo.search.grouping.result.StringId; import com.yahoo.search.result.Coverage; import com.yahoo.search.result.ErrorMessage; +import com.yahoo.search.result.FeatureData; import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; import com.yahoo.search.result.NanNumber; @@ -51,6 +52,7 @@ import com.yahoo.slime.Cursor; import com.yahoo.slime.Slime; import com.yahoo.tensor.Tensor; import com.yahoo.tensor.TensorType; +import com.yahoo.tensor.serialization.TypedBinaryFormat; import com.yahoo.text.Utf8; import com.yahoo.yolean.trace.TraceNode; import org.json.JSONArray; @@ -123,7 +125,7 @@ public class JsonRendererTestCase { } @Test - public void testDataTypes() throws IOException, InterruptedException, ExecutionException, JSONException { + public void testDataTypes() throws IOException, InterruptedException, ExecutionException { String expected = "{" + " \"root\": {" + " \"children\": [" @@ -139,7 +141,13 @@ public class JsonRendererTestCase { + " \"predicate\": \"a in [b]\"," + " \"tensor1\": { \"cells\": [ { \"address\": {\"x\": \"a\"}, \"value\":2.0 } ] }," + " \"tensor2\": { \"cells\": [] }," - + " \"tensor3\": { \"cells\": [ { \"address\": {\"x\": \"a\", \"y\": \"0\"}, \"value\":2.0 }, { \"address\": {\"x\": \"a\", \"y\": \"1\"}, \"value\":-1.0 } ] }" + + " \"tensor3\": { \"cells\": [ { \"address\": {\"x\": \"a\", \"y\": \"0\"}, \"value\":2.0 }, { \"address\": {\"x\": \"a\", \"y\": \"1\"}, \"value\":-1.0 } ] }," + + " \"summaryfeatures\": {" + + " \"scalar1\":1.5," + + " \"scalar2\":2.5," + + " \"tensor1\":{\"type\":\"tensor(x[3])\",\"cells\":[{\"address\":{\"x\":\"0\"},\"value\":1.5},{\"address\":{\"x\":\"1\"},\"value\":2.0},{\"address\":{\"x\":\"2\"},\"value\":2.5}]}," + + " \"tensor2\":{\"type\":\"tensor()\",\"cells\":[{\"address\":{},\"value\":0.5}]}" + + " }" + " }," + " \"id\": \"datatypestuff\"," + " \"relevance\": 1.0" @@ -166,12 +174,24 @@ public class JsonRendererTestCase { h.setField("tensor2", new TensorFieldValue(TensorType.empty)); h.setField("tensor3", Tensor.from("{ {x:a, y:0}: 2.0, {x:a, y:1}: -1 }")); h.setField("object", new Thingie()); + h.setField("summaryfeatures", createSummaryFeatures()); r.hits().add(h); r.setTotalHitCount(1L); String summary = render(r); assertEqualJson(expected, summary); } + private FeatureData createSummaryFeatures() { + Slime slime = new Slime(); + Cursor features = slime.setObject(); + features.setDouble("scalar1", 1.5); + features.setDouble("scalar2", 2.5); + Tensor tensor1 = Tensor.from("tensor(x[3]):[1.5, 2, 2.5]"); + features.setData("tensor1", TypedBinaryFormat.encode(tensor1)); + Tensor tensor2 = Tensor.from(0.5); + features.setData("tensor2", TypedBinaryFormat.encode(tensor2)); + return new FeatureData(new SlimeAdapter(slime.get())); + } @Test public void testTracing() throws IOException, InterruptedException, ExecutionException { @@ -679,12 +699,10 @@ public class JsonRendererTestCase { + "}"; Result r = newEmptyResult(); Hit h = new Hit("moredatatypestuff"); - h.setField("byte", Byte.valueOf((byte) 8)); - h.setField("short", Short.valueOf((short) 16)); - h.setField("bigInteger", new BigInteger( - "340282366920938463463374607431768211455")); - h.setField("bigDecimal", new BigDecimal( - "340282366920938463463374607431768211456.5")); + h.setField("byte", (byte)8); + h.setField("short", (short)16); + h.setField("bigInteger", new BigInteger("340282366920938463463374607431768211455")); + h.setField("bigDecimal", new BigDecimal("340282366920938463463374607431768211456.5")); h.setField("nanNumber", NanNumber.NaN); r.hits().add(h); r.setTotalHitCount(1L); diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java index 70d50b23bed..00a17f963c6 100644 --- a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java @@ -303,7 +303,7 @@ public class YqlParserTestCase { assertCanonicalParse("select foo from bar where baz contains sameElement(key contains \"a\", value.f2 = 10);", "baz:{key:a value.f2:10}"); assertCanonicalParse("select foo from bar where baz contains sameElement(key contains \"a\");", - "baz:{key:a}"); + "baz.key:a"); } @Test |