summaryrefslogtreecommitdiffstats
path: root/container-search
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@verizonmedia.com>2019-06-28 08:56:48 -0500
committerJon Bratseth <bratseth@verizonmedia.com>2019-06-28 08:56:48 -0500
commit781d6dfd8afdcb1da0ce29ef37ccbc0c45dc155d (patch)
tree18846b64a9ea079196591f93bd2856a8b5459b4d /container-search
parent38be09692fbc8e286ed1b669771e1c2d66e1db6c (diff)
parent4f9ad5d65f0e7fac3796830b90c2f8b9128523ce (diff)
Merge with master
Diffstat (limited to 'container-search')
-rw-r--r--container-search/abi-spec.json13
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java1
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java10
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/NonReducibleCompositeItem.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/PhraseItem.java8
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/PhraseSegmentItem.java11
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/QueryCanonicalizer.java13
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/SameElementItem.java11
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/querytransform/QueryRewrite.java3
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java9
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/Renderer.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/result/FeatureData.java31
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java57
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/fastsearch/summary.cfg4
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java4
-rw-r--r--container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java34
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java2
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