aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java10
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/Docsum.java29
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java212
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/GroupingListHit.java8
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/hitfield/HitField.java1
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/templates/DefaultTemplateSet.java26
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/templates/TiledTemplateSet.java24
-rw-r--r--container-search/src/main/java/com/yahoo/search/Result.java3
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/vespa/HitConverter.java22
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java26
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java24
-rw-r--r--container-search/src/main/java/com/yahoo/search/result/Hit.java401
-rw-r--r--container-search/src/main/java/com/yahoo/search/result/HitGroup.java1
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java8
-rw-r--r--container-search/src/test/java/com/yahoo/search/federation/vespa/test/ResultBuilderTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/search/grouping/vespa/HitConverterTestCase.java22
-rw-r--r--container-search/src/test/java/com/yahoo/search/result/test/HitGroupTestCase.java10
-rwxr-xr-xmessagebus/src/main/java/com/yahoo/messagebus/ConfigAgent.java4
21 files changed, 384 insertions, 455 deletions
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 40364824774..91fbd1b2aca 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
@@ -155,8 +155,8 @@ public class ClusterSearcher extends Searcher {
if (! isRemote(searchClusterConfig.dispatcher(dispatcherIndex).host())) {
Backend b = createBackend(searchClusterConfig.dispatcher(dispatcherIndex));
FastSearcher searcher = searchDispatch(searchClusterIndex, fs4ResourcePool,
- searchClusterConfig, cacheParams, emulationConfig, docSumParams,
- documentDbConfig, b, dispatcher, dispatcherIndex);
+ cacheParams, emulationConfig, docSumParams,
+ documentDbConfig, b, dispatcher, dispatcherIndex);
addBackendSearcher(searcher);
}
} catch (UnknownHostException e) {
@@ -190,7 +190,6 @@ public class ClusterSearcher extends Searcher {
}
private static ClusterParams makeClusterParams(int searchclusterIndex,
- QrSearchersConfig.Searchcluster searchClusterConfig,
LegacyEmulationConfig emulConfig,
int dispatchIndex) {
return new ClusterParams(searchclusterIndex,
@@ -200,7 +199,6 @@ public class ClusterSearcher extends Searcher {
private static FastSearcher searchDispatch(int searchclusterIndex,
FS4ResourcePool fs4ResourcePool,
- QrSearchersConfig.Searchcluster searchClusterConfig,
CacheParams cacheParams,
LegacyEmulationConfig emulConfig,
SummaryParameters docSumParams,
@@ -208,7 +206,7 @@ public class ClusterSearcher extends Searcher {
Backend backend,
Dispatcher dispatcher,
int dispatcherIndex) {
- ClusterParams clusterParams = makeClusterParams(searchclusterIndex, searchClusterConfig,
+ ClusterParams clusterParams = makeClusterParams(searchclusterIndex,
emulConfig, dispatcherIndex);
return new FastSearcher(backend, fs4ResourcePool, dispatcher, docSumParams, clusterParams, cacheParams,
documentdbInfoConfig);
@@ -220,7 +218,7 @@ public class ClusterSearcher extends Searcher {
LegacyEmulationConfig emulConfig,
SummaryParameters docSumParams,
DocumentdbInfoConfig documentdbInfoConfig) {
- ClusterParams clusterParams = makeClusterParams(searchclusterIndex, searchClusterConfig, emulConfig, 0);
+ ClusterParams clusterParams = makeClusterParams(searchclusterIndex, emulConfig, 0);
VdsStreamingSearcher searcher = (VdsStreamingSearcher) VespaBackEndSearcher
.getSearcher("com.yahoo.vespa.streamingvisitors.VdsStreamingSearcher");
searcher.setSearchClusterConfigId(searchClusterConfig.rankprofiles().configid());
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/Docsum.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/Docsum.java
index 8181787e909..f5cec631734 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/Docsum.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/Docsum.java
@@ -18,7 +18,7 @@ public final class Docsum {
/** The offsets into the packet data of each field, given the fields index, computed lazily */
private final int[] fieldOffsets;
/** The largest stored offset */
- private int largestStoredOffset=-1;
+ private int largestStoredOffset = -1;
public Docsum(DocsumDefinition definition, byte[] packet) {
this.definition = definition;
@@ -28,39 +28,12 @@ public final class Docsum {
public DocsumDefinition getDefinition() { return definition; }
- public Integer getFieldIndex(String fieldName) {
- return definition.getFieldIndex(fieldName);
- }
-
public Object decode(int fieldIndex) {
ByteBuffer b=packetAsBuffer();
setAndReturnOffsetToField(b, fieldIndex);
return definition.getField(fieldIndex).decode(b);
}
- /** Fetches the field as raw utf-8 if it is a text field. Returns null otherwise */
- public FastHit.RawField fetchFieldAsUtf8(int fieldIndex) {
- DocsumField dataType = definition.getField(fieldIndex);
- if ( ! (dataType instanceof LongstringField || dataType instanceof XMLField || dataType instanceof StringField))
- return null;
-
- ByteBuffer b=packetAsBuffer();
- DocsumField field = definition.getField(fieldIndex);
- int fieldStart = setAndReturnOffsetToField(b, fieldIndex); // set buffer.pos = start of field
- if (field.isCompressed(b)) return null;
- int length = field.getLength(b); // scan to end of field
- if (field instanceof VariableLengthField) {
- int fieldLength = ((VariableLengthField) field).sizeOfLength();
- b.position(fieldStart + fieldLength); // reset to start of field
- length -= fieldLength;
- } else {
- b.position(fieldStart); // reset to start of field
- }
- byte[] bufferView = new byte[length];
- b.get(bufferView);
- return new FastHit.RawField(dataType, bufferView);
- }
-
public ByteBuffer packetAsBuffer() {
ByteBuffer buffer = ByteBuffer.wrap(packet);
buffer.order(ByteOrder.LITTLE_ENDIAN);
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
index 288fd084d0b..f1f5e2b7403 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
@@ -1,15 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.prelude.fastsearch;
-import com.google.common.annotations.Beta;
import com.yahoo.document.GlobalId;
import com.yahoo.fs4.QueryPacketData;
import com.yahoo.net.URI;
import com.yahoo.search.result.Hit;
import com.yahoo.search.result.Relevance;
import com.yahoo.data.access.Inspector;
-import com.yahoo.data.access.Type;
-import com.yahoo.data.access.simple.Value.StringValue;
/**
* A regular hit from a Vespa backend
@@ -56,46 +53,16 @@ public class FastHit extends Hit {
setPartId(0);
}
- @Override
- public String toString() {
- return super.toString() + " [fasthit, globalid: " + globalId + ", partId: "
- + partId + ", distributionkey: " + distributionKey + "]";
- }
-
- public static String asHexString(GlobalId gid) {
- StringBuilder sb = new StringBuilder();
- byte[] rawGid = gid.getRawId();
- for (byte b : rawGid) {
- String hex = Integer.toHexString(0xFF & b);
- if (hex.length() == 1) {
- sb.append('0');
- }
- sb.append(hex);
- }
- return sb.toString();
- }
-
- @Override
- public int hashCode() {
- if (getId() == null) {
- throw new IllegalStateException("This hit must have a 'uri' field, and this fild must be filled through " +
- "Execution.fill(Result)) before hashCode() is accessed.");
- } else {
- return super.hashCode();
- }
- }
-
- @Override
- public URI getId() {
- return getUri(); // Make sure we decode it if the id is encoded
- }
+ /** Returns false - this is a concrete hit containing requested content */
+ public boolean isMeta() { return false; }
/**
* Returns the explicitly set uri if available, returns "index:[source]/[partid]/[id]" otherwise
*
* @return uri of hit
*/
- public URI getUri() {
+ @Override
+ public URI getId() {
URI uri = super.getId();
if (uri != null) return uri;
@@ -107,45 +74,72 @@ public class FastHit extends Hit {
return super.getId();
}
- return getIndexUri();
- }
-
- /**
- * The uri of the index location of this hit ("index:[source]/[partid]/[id]").
- * This is the uri if no other uri is assigned
- *
- * @return uri to the index.
- */
- public URI getIndexUri() {
+ // Fallback to index:[source]/[partid]/[id]
if (indexUri != null) return indexUri;
-
- indexUri = new URI("index:" + getSourceNumber() + "/" + getPartId() + "/" + asHexString(getGlobalId()));
+ indexUri = new URI("index:" + getSource() + "/" + getPartId() + "/" + asHexString(getGlobalId()));
return indexUri;
}
/** Returns the global id of this document in the backend node which produced it */
- public GlobalId getGlobalId() {
- return globalId;
- }
+ public GlobalId getGlobalId() { return globalId; }
- public void setGlobalId(GlobalId globalId) {
- this.globalId = globalId;
- }
+ public void setGlobalId(GlobalId globalId) { this.globalId = globalId; }
- public int getPartId() {
- return partId;
- }
+ public int getPartId() { return partId; }
/**
* Sets the part id number, which specifies the node where this hit is
* found. The row count is used to decode the part id into a column and a
* row number: the number of n least significant bits required to hold the
* highest row number are the row bits, the rest are column bits.
- *
- * @param partId partition id
*/
public void setPartId(int partId) { this.partId = partId; }
+ /** Returns the index of the node this hit originated at */
+ public int getDistributionKey() { return distributionKey; }
+
+ /** Returns the index of the node this hit originated at */
+ public void setDistributionKey(int distributionKey) { this.distributionKey = distributionKey; }
+
+ /**
+ * Add the binary data common for the query packet to a Vespa backend and a
+ * summary fetch packet to a Vespa backend. This method can only be called
+ * once for a single hit.
+ *
+ * @param queryPacketData binary data from a query packet resulting in this hit
+ * @throws IllegalStateException if the method is called more than once
+ * @throws NullPointerException if trying to set query packet data to null
+ */
+ public void setQueryPacketData(QueryPacketData queryPacketData) {
+ if (this.queryPacketData != null)
+ throw new IllegalStateException("Query packet data already set to "
+ + this.queryPacketData + ", tried to set it to " + queryPacketData);
+ if (queryPacketData == null)
+ throw new NullPointerException("Query packet data reference can not be set to null.");
+ this.queryPacketData = queryPacketData;
+ }
+
+ /** Returns a serial encoding of the query which produced this hit, ot null if not available. */
+ public QueryPacketData getQueryPacketData() { return queryPacketData; }
+
+ CacheKey getCacheKey() { return cacheKey; }
+
+ void setCacheKey(CacheKey cacheKey) { this.cacheKey = cacheKey; }
+
+ /** For internal use */
+ public void addSummary(DocsumDefinition docsumDef, Inspector value) {
+ reserve(docsumDef.getFieldCount());
+ for (DocsumField field : docsumDef.getFields()) {
+ String fieldName = field.getName();
+ Inspector f = value.field(fieldName);
+ if (field.getEmulConfig().forceFillEmptyFields() || f.valid()) {
+ if (super.getField(fieldName) == null) {
+ setField(fieldName, field.convert(f));
+ }
+ }
+ }
+ }
+
/**
* <p>Returns a field value from this Hit. The value is either a stored value from the Document represented by
* this Hit, or a generated value added during later processing.</p>
@@ -182,89 +176,33 @@ public class FastHit extends Hit {
return super.getField(key);
}
- /** Returns false - this is a concrete hit containing requested content */
- public boolean isMeta() {
- return false;
- }
-
- /** Returns the index of the node this hit originated at */
- public int getDistributionKey() {
- return distributionKey;
- }
-
- /** Returns the index of the node this hit originated at */
- public void setDistributionKey(int distributionKey) {
- this.distributionKey = distributionKey;
- }
-
- /** For internal use */
- public void addSummary(DocsumDefinition docsumDef, Inspector value) {
- reserve(docsumDef.getFieldCount());
- for (DocsumField field : docsumDef.getFields()) {
- String fieldName = field.getName();
- Inspector f = value.field(fieldName);
- if (field.getEmulConfig().forceFillEmptyFields() || f.valid()) {
- setDocsumFieldIfNotPresent(fieldName, field.convert(f));
- }
- }
+ @Override
+ public String toString() {
+ return super.toString() + " [fasthit, globalid: " + globalId + ", partId: "
+ + partId + ", distributionkey: " + distributionKey + "]";
}
- private void setDocsumFieldIfNotPresent(String fieldName, Object value) {
- if (super.getField(fieldName) == null) {
- setField(fieldName, value);
+ @Override
+ public int hashCode() {
+ if (getId() == null) {
+ throw new IllegalStateException("This hit must have a 'uri' field, and this fild must be filled through " +
+ "Execution.fill(Result)) before hashCode() is accessed.");
+ } else {
+ return super.hashCode();
}
}
- /**
- * Add the binary data common for the query packet to a Vespa backend and a
- * summary fetch packet to a Vespa backend. This method can only be called
- * once for a single hit.
- *
- * @param queryPacketData binary data from a query packet resulting in this hit
- * @throws IllegalStateException if the method is called more than once
- * @throws NullPointerException if trying to set query packet data to null
- */
- public void setQueryPacketData(QueryPacketData queryPacketData) {
- if (this.queryPacketData != null)
- throw new IllegalStateException("Query packet data already set to "
- + this.queryPacketData + ", tried to set it to " + queryPacketData);
- if (queryPacketData == null)
- throw new NullPointerException("Query packet data reference can not be set to null.");
- this.queryPacketData = queryPacketData;
- }
-
- /**
- * Fetch binary data from the query packet which produced this hit. These
- * data may not be available, this method will then return null.
- *
- * @return wrapped binary data from a query packet, or null
- */
- public QueryPacketData getQueryPacketData() {
- return queryPacketData;
- }
-
- CacheKey getCacheKey() {
- return cacheKey;
- }
-
- void setCacheKey(CacheKey cacheKey) {
- this.cacheKey = cacheKey;
- }
-
- public static final class RawField {
-
- private final boolean needXmlEscape;
-
- private final byte[] contents;
-
- public RawField(DocsumField fieldType, byte[] contents) {
- needXmlEscape = ! (fieldType instanceof XMLField);
- this.contents = contents;
+ public static String asHexString(GlobalId gid) {
+ StringBuilder sb = new StringBuilder();
+ byte[] rawGid = gid.getRawId();
+ for (byte b : rawGid) {
+ String hex = Integer.toHexString(0xFF & b);
+ if (hex.length() == 1) {
+ sb.append('0');
+ }
+ sb.append(hex);
}
-
- public byte [] getUtf8() { return contents; }
- public boolean needXmlEscape() { return needXmlEscape; }
-
+ return sb.toString();
}
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/GroupingListHit.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/GroupingListHit.java
index c558a60adae..e57fe3a200e 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/GroupingListHit.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/GroupingListHit.java
@@ -7,8 +7,8 @@ import com.yahoo.fs4.QueryPacketData;
import com.yahoo.search.result.Hit;
import com.yahoo.searchlib.aggregation.Grouping;
-// TODO: Author!
public class GroupingListHit extends Hit {
+
private static final long serialVersionUID = -6645125887873082234L;
/** for unit tests only, may give problems if grouping contains docsums */
@@ -16,13 +16,12 @@ public class GroupingListHit extends Hit {
this(groupingList, null);
}
- public GroupingListHit(List<Grouping> groupingList,
- DocsumDefinitionSet defs)
- {
+ public GroupingListHit(List<Grouping> groupingList, DocsumDefinitionSet defs) {
super("meta:grouping", 0);
this.groupingList = groupingList;
this.defs = defs;
}
+
public boolean isMeta() { return true; }
public List<Grouping> getGroupingList() { return groupingList; }
@@ -40,4 +39,5 @@ public class GroupingListHit extends Hit {
public QueryPacketData getQueryPacketData() {
return queryPacketData;
}
+
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
index 7d5b91ab1e3..3abd97d814e 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
@@ -421,7 +421,6 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
GroupingListHit hit = new GroupingListHit(list, getDocsumDefinitionSet(query));
hit.setQuery(result.getQuery());
hit.setSource(getName());
- hit.setSourceNumber(sourceNumber);
hit.setQueryPacketData(queryPacketData);
result.hits().add(hit);
}
@@ -556,7 +555,6 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
}
private void extractDocumentInfo(FastHit hit, DocumentInfo document) {
- hit.setSourceNumber(sourceNumber);
hit.setSource(getName());
Number rank = document.getMetric();
diff --git a/container-search/src/main/java/com/yahoo/prelude/hitfield/HitField.java b/container-search/src/main/java/com/yahoo/prelude/hitfield/HitField.java
index 79d871d8c74..f6619a32a2b 100644
--- a/container-search/src/main/java/com/yahoo/prelude/hitfield/HitField.java
+++ b/container-search/src/main/java/com/yahoo/prelude/hitfield/HitField.java
@@ -391,6 +391,7 @@ public class HitField {
return bareContent.toString();
}
+ @Override
public String toString() {
return getContent();
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/DefaultTemplateSet.java b/container-search/src/main/java/com/yahoo/prelude/templates/DefaultTemplateSet.java
index ba7388a11a0..e8e7f6f2f93 100644
--- a/container-search/src/main/java/com/yahoo/prelude/templates/DefaultTemplateSet.java
+++ b/container-search/src/main/java/com/yahoo/prelude/templates/DefaultTemplateSet.java
@@ -5,16 +5,21 @@ import com.yahoo.concurrent.CopyOnWriteHashMap;
import com.yahoo.io.ByteWriter;
import com.yahoo.net.URI;
import com.yahoo.prelude.fastsearch.FastHit;
+import com.yahoo.prelude.hitfield.HitField;
+import com.yahoo.prelude.hitfield.JSONString;
+import com.yahoo.prelude.hitfield.XMLString;
import com.yahoo.search.Result;
import com.yahoo.search.grouping.result.HitRenderer;
import com.yahoo.search.result.*;
import com.yahoo.text.Utf8String;
+import com.yahoo.text.XML;
import com.yahoo.text.XMLWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
+import java.util.stream.Collectors;
/**
* <p>A template set which provides XML rendering of results and hits.</p>
@@ -171,8 +176,8 @@ public class DefaultTemplateSet extends UserTemplate<XMLWriter> {
/**
* Writes a hit's default attributes like 'type', 'source', 'relevancy'.
*/
- protected void renderHitAttributes(Hit hit,XMLWriter writer) throws IOException {
- writer.attribute(TYPE,hit.getTypeString());
+ protected void renderHitAttributes(Hit hit, XMLWriter writer) throws IOException {
+ writer.attribute(TYPE, hit.types().stream().collect(Collectors.joining(" ")));
if (hit.getRelevance() != null) {
writer.attribute(RELEVANCY, hit.getRelevance().toString());
}
@@ -263,11 +268,18 @@ public class DefaultTemplateSet extends UserTemplate<XMLWriter> {
}
protected void renderFieldContent(Context context, Hit hit, String name, XMLWriter writer) {
- String xmlval = hit.getFieldXML(name);
- if (xmlval == null) {
- xmlval = "(null)";
- }
- writer.escapedContent(xmlval,false);
+ writer.escapedContent(asXML(hit.getField(name)), false);
+ }
+
+ private String asXML(Object value) {
+ if (value == null)
+ return "(null)";
+ else if (value instanceof HitField)
+ return ((HitField)value).quotedContent(false);
+ else if (value instanceof StructuredData || value instanceof XMLString || value instanceof JSONString)
+ return value.toString();
+ else
+ return XML.xmlEscape(value.toString(), false, '\u001f');
}
private void renderSimpleField(String fieldName, Object fieldValue, XMLWriter writer) {
diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/TiledTemplateSet.java b/container-search/src/main/java/com/yahoo/prelude/templates/TiledTemplateSet.java
index 4e3b53f4523..6bba0f620ee 100644
--- a/container-search/src/main/java/com/yahoo/prelude/templates/TiledTemplateSet.java
+++ b/container-search/src/main/java/com/yahoo/prelude/templates/TiledTemplateSet.java
@@ -2,6 +2,9 @@
package com.yahoo.prelude.templates;
import com.yahoo.container.ConfigHack;
+import com.yahoo.prelude.hitfield.HitField;
+import com.yahoo.prelude.hitfield.JSONString;
+import com.yahoo.prelude.hitfield.XMLString;
import com.yahoo.prelude.templates.FormattingOptions.SubtypeFieldWithPrefix;
import com.yahoo.search.Result;
import com.yahoo.search.pagetemplates.model.Renderer;
@@ -9,12 +12,15 @@ import com.yahoo.search.pagetemplates.model.Source;
import com.yahoo.search.pagetemplates.result.SectionHitGroup;
import com.yahoo.search.result.Hit;
import com.yahoo.search.result.HitGroup;
+import com.yahoo.search.result.StructuredData;
+import com.yahoo.text.XML;
import com.yahoo.text.XMLWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
+import java.util.stream.Collectors;
/**
* A template set which implements the 'tiled' format.
@@ -142,13 +148,13 @@ public class TiledTemplateSet extends DefaultTemplateSet {
@Override
protected void renderHitAttributes(Hit hit, XMLWriter writer) throws IOException {
if (hit instanceof HitGroup) {
- String type = hit.getTypeString(); // TODO: This logic is somewhat crazy
- if("group".equals(type))
+ String type = hit.types().stream().collect(Collectors.joining(" "));
+ if ("group".equals(type))
type = String.valueOf(hit.getField("type"));
writer.attribute("type", type);
}
else {
- writer.attribute("type", hit.getTypeString());
+ writer.attribute("type", hit.types().stream().collect(Collectors.joining(" ")));
}
if (hit.getRelevance() != null)
@@ -328,9 +334,19 @@ public class TiledTemplateSet extends DefaultTemplateSet {
} else {
writer.openTag(name);
}
- writer.escapedContent(hit.getFieldXML(name),false).closeTag();
+ writer.escapedContent(asXML(hit.getField(name)),false).closeTag();
}
+ private String asXML(Object value) {
+ if (value == null)
+ return "(null)";
+ else if (value instanceof HitField)
+ return ((HitField)value).quotedContent(false);
+ else if (value instanceof StructuredData || value instanceof XMLString || value instanceof JSONString)
+ return value.toString();
+ else
+ return XML.xmlEscape(value.toString(), false, '\u001f');
+ }
public String toString() { return "tiled result template"; }
diff --git a/container-search/src/main/java/com/yahoo/search/Result.java b/container-search/src/main/java/com/yahoo/search/Result.java
index 7978798f53c..b8df086a92a 100644
--- a/container-search/src/main/java/com/yahoo/search/Result.java
+++ b/container-search/src/main/java/com/yahoo/search/Result.java
@@ -270,9 +270,6 @@ public final class Result extends com.yahoo.processing.Response implements Clone
hitBuffer.append(", relevancy: ");
hitBuffer.append(hit.getRelevance());
- hitBuffer.append(", addno: ");
- hitBuffer.append(hit.getAddNumber());
-
hitBuffer.append(", source: ");
hitBuffer.append(hit.getSource());
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/vespa/HitConverter.java b/container-search/src/main/java/com/yahoo/search/grouping/vespa/HitConverter.java
index a095f6dc686..617c037d2a7 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/vespa/HitConverter.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/vespa/HitConverter.java
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.grouping.vespa;
-import com.yahoo.fs4.QueryPacketData;
import com.yahoo.prelude.fastsearch.DocsumDefinitionSet;
import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.prelude.fastsearch.GroupingListHit;
@@ -52,22 +51,13 @@ class HitConverter implements ResultBuilder.HitConverter {
hit.setFillable();
hit.setSearcherSpecificMetaData(searcher, summaryClass);
- Hit ctxHit = (Hit)groupHit.getContext();
- if (ctxHit == null) {
+ GroupingListHit hitContext = (GroupingListHit)groupHit.getContext();
+ if (hitContext == null)
throw new NullPointerException("Hit has no context.");
- }
- hit.setSource(ctxHit.getSource());
- hit.setSourceNumber(ctxHit.getSourceNumber());
- hit.setQuery(ctxHit.getQuery());
-
- if (ctxHit instanceof GroupingListHit) {
- // in a live system the ctxHit can only by GroupingListHit, but because the code used Hit prior to version
- // 5.10 we need to check to avoid breaking existing unit tests -- both internally and with customers
- QueryPacketData queryPacketData = ((GroupingListHit)ctxHit).getQueryPacketData();
- if (queryPacketData != null) {
- hit.setQueryPacketData(queryPacketData);
- }
- }
+ hit.setSource(hitContext.getSource());
+ hit.setQuery(hitContext.getQuery());
+ if (hitContext.getQueryPacketData() != null)
+ hit.setQueryPacketData(hitContext.getQueryPacketData());
return hit;
}
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java
index 7859358fe50..f0c7b1a183f 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java
@@ -7,6 +7,9 @@ import com.yahoo.io.ByteWriter;
import com.yahoo.net.URI;
import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.prelude.fastsearch.GroupingListHit;
+import com.yahoo.prelude.hitfield.HitField;
+import com.yahoo.prelude.hitfield.JSONString;
+import com.yahoo.prelude.hitfield.XMLString;
import com.yahoo.prelude.templates.UserTemplate;
import com.yahoo.processing.rendering.AsynchronousSectionedRenderer;
import com.yahoo.processing.response.Data;
@@ -17,6 +20,7 @@ import com.yahoo.search.grouping.result.HitRenderer;
import com.yahoo.search.query.context.QueryContext;
import com.yahoo.search.result.*;
import com.yahoo.text.Utf8String;
+import com.yahoo.text.XML;
import com.yahoo.text.XMLWriter;
import com.yahoo.yolean.trace.TraceNode;
import com.yahoo.yolean.trace.TraceVisitor;
@@ -31,6 +35,7 @@ import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
// TODO: Rename to XmlRenderer and make this a deprecated empty subclass.
@@ -201,10 +206,18 @@ public final class DefaultRenderer extends AsynchronousSectionedRenderer<Result>
}
private void renderFieldContent(XMLWriter writer, Hit hit, String fieldName) {
- String xmlval = hit.getFieldXML(fieldName);
- if (xmlval == null)
- xmlval = "(null)";
- writer.escapedContent(xmlval, false);
+ writer.escapedContent(asXML(hit.getField(fieldName)), false);
+ }
+
+ private String asXML(Object value) {
+ if (value == null)
+ return "(null)";
+ else if (value instanceof HitField)
+ return ((HitField)value).quotedContent(false);
+ else if (value instanceof StructuredData || value instanceof XMLString || value instanceof JSONString)
+ return value.toString();
+ else
+ return XML.xmlEscape(value.toString(), false, '\u001f');
}
private void renderSyntheticRelevanceField(XMLWriter writer, Hit hit) {
@@ -238,10 +251,9 @@ public final class DefaultRenderer extends AsynchronousSectionedRenderer<Result>
}
private void renderHitAttributes(XMLWriter writer, Hit hit) {
- writer.attribute(TYPE, hit.getTypeString());
- if (hit.getRelevance() != null) {
+ writer.attribute(TYPE, hit.types().stream().collect(Collectors.joining(" ")));
+ if (hit.getRelevance() != null)
writer.attribute(RELEVANCY, hit.getRelevance().toString());
-}
writer.attribute(SOURCE, hit.getSource());
}
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java
index 6613211a91e..dc72061e224 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java
@@ -7,6 +7,9 @@ import com.yahoo.log.LogLevel;
import com.yahoo.net.URI;
import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.prelude.fastsearch.GroupingListHit;
+import com.yahoo.prelude.hitfield.HitField;
+import com.yahoo.prelude.hitfield.JSONString;
+import com.yahoo.prelude.hitfield.XMLString;
import com.yahoo.prelude.templates.Context;
import com.yahoo.prelude.templates.DefaultTemplateSet;
import com.yahoo.prelude.templates.MapContext;
@@ -17,6 +20,7 @@ import com.yahoo.search.grouping.result.HitRenderer;
import com.yahoo.search.query.context.QueryContext;
import com.yahoo.search.result.*;
import com.yahoo.text.Utf8String;
+import com.yahoo.text.XML;
import com.yahoo.text.XMLWriter;
import com.yahoo.yolean.trace.TraceNode;
import com.yahoo.yolean.trace.TraceVisitor;
@@ -28,6 +32,7 @@ import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
/**
* @author tonytv
@@ -284,11 +289,18 @@ public final class SyncDefaultRenderer extends Renderer {
}
private void renderFieldContent(XMLWriter writer, Hit hit, String fieldName) {
- String xmlval = hit.getFieldXML(fieldName);
- if (xmlval == null) {
- xmlval = "(null)";
- }
- writer.escapedContent(xmlval, false);
+ writer.escapedContent(asXML(hit.getField(fieldName)), false);
+ }
+
+ private String asXML(Object value) {
+ if (value == null)
+ return "(null)";
+ else if (value instanceof HitField)
+ return ((HitField)value).quotedContent(false);
+ else if (value instanceof StructuredData || value instanceof XMLString || value instanceof JSONString)
+ return value.toString();
+ else
+ return XML.xmlEscape(value.toString(), false, '\u001f');
}
private void renderSyntheticRelevanceField(XMLWriter writer, Hit hit) {
@@ -326,7 +338,7 @@ public final class SyncDefaultRenderer extends Renderer {
}
private void renderHitAttributes(XMLWriter writer, Hit hit) {
- writer.attribute(TYPE, hit.getTypeString());
+ writer.attribute(TYPE, hit.types().stream().collect(Collectors.joining(" ")));
if (hit.getRelevance() != null) {
writer.attribute(RELEVANCY, hit.getRelevance().toString());
}
diff --git a/container-search/src/main/java/com/yahoo/search/result/Hit.java b/container-search/src/main/java/com/yahoo/search/result/Hit.java
index 0d8f575b1f6..0664720c7d7 100644
--- a/container-search/src/main/java/com/yahoo/search/result/Hit.java
+++ b/container-search/src/main/java/com/yahoo/search/result/Hit.java
@@ -13,7 +13,15 @@ import com.yahoo.search.Query;
import com.yahoo.search.Searcher;
import com.yahoo.text.XML;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
/**
* <p>A search hit. The identifier of the hit is the uri
@@ -38,6 +46,9 @@ import java.util.*;
*/
public class Hit extends ListenableFreezableClass implements Data, Comparable<Hit>, Cloneable {
+ // Collection fields in hits are, when possible lazy because much of the work of a container
+ // consists of allocating and then garbage collecting hits
+
private static final String DOCUMENT_ID = "documentid";
/** A collection of string keyed object properties. */
@@ -53,7 +64,7 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
private URI id;
/** The types of this hit */
- private Set<String> types = new ArraySet<>(2);
+ private Set<String> types = new ArraySet<>(1);
/** The relevance of this hit */
private Relevance relevance;
@@ -245,16 +256,16 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
* @throws IllegalArgumentException if the given relevance is not between 0 and 1000
*/
public Hit(String id, Relevance relevance, String source, Query query) {
- this.id=new URI(id);
+ this.id = new URI(id);
this.relevance = relevance;
- this.source=source;
+ this.source = source;
this.query = query;
}
/** Calls setId(new URI(id)) */
public void setId(String id) {
- if (this.id!=null) throw new IllegalStateException("Attempt to change id of " + this + " to " + id);
- if (id==null) throw new NullPointerException("Attempt to assign id of " + this + " to null");
+ if (this.id != null) throw new IllegalStateException("Attempt to change id of " + this + " to " + id);
+ if (id == null) throw new NullPointerException("Attempt to assign id of " + this + " to null");
assignId(new URI(id));
}
@@ -266,7 +277,7 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
* @throws IllegalStateException if the uri of this hit is already set
*/
public void setId(URI id) {
- if (this.id!=null) throw new IllegalStateException("Attempt to change id of " + this + " to " + id);
+ if (this.id != null) throw new IllegalStateException("Attempt to change id of " + this + " to " + id);
assignId(id);
}
@@ -276,8 +287,8 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
* using this method.
*/
protected final void assignId(URI id) {
- if (id==null) throw new NullPointerException("Attempt to assign id of " + this + " to null");
- this.id=id;
+ if (id == null) throw new NullPointerException("Attempt to assign id of " + this + " to null");
+ this.id = id;
}
/** Returns the hit id */
@@ -293,22 +304,16 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
String id = null;
Object idField = getField(DOCUMENT_ID);
- if (idField != null) {
+ if (idField != null)
id = idField.toString();
- }
- if (id == null) {
+ if (id == null)
id = getId() == null ? null : getId().toString();
- }
return id;
}
- /**
- * Sets the relevance of this hit
- *
- * @param relevance the relevance of this hit
- */
+ /** Sets the relevance of this hit */
public void setRelevance(Relevance relevance) {
- if (relevance==null) throw new NullPointerException("Cannot assign null as relevance");
+ if (relevance == null) throw new NullPointerException("Cannot assign null as relevance");
this.relevance = relevance;
}
@@ -396,19 +401,30 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
/** Returns the name of the source creating this hit */
public String getSource() { return source; }
- /** Returns the fields of this as a read-only map. This is more costly than the preferred iterator(), as
+ /**
+ * Returns the fields of this as a read-only map. This is more costly than the preferred iterator(), as
* it uses Collections.unmodifiableMap()
+ *
* @return An readonly map of the fields
- **/
- //TODO Should it be deprecated ?
- public final Map<String,Object> fields() { return getUnmodifiableFieldMap(); }
+ */
+ // TODO Should it be deprecated ?
+ public final Map<String, Object> fields() { return getUnmodifiableFieldMap(); }
- /** Aallocate room for the given number of fields to avoid resizing. */
+ /** Allocate room for the given number of fields to avoid resizing. */
public void reserve(int minSize) {
getFieldMap(minSize);
}
/**
+ * Sets the value of a field
+ *
+ * @return the previous value, or null if none
+ */
+ public Object setField(String key, Object value) {
+ return getFieldMap().put(key, value);
+ }
+
+ /**
* Returns an iterator over the fields of this
*
* @return an iterator for traversing the fields of this hit
@@ -418,37 +434,79 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
/** Returns a field value */
public Object getField(String value) { return fields != null ? fields.get(value) : null; }
+ /** Removes all fields of this */
+ public void clearFields() {
+ getFieldMap().clear();
+ }
+
/**
- * Generate a HitField from a field if the field exists.
- *
- * @deprecated do not use
+ * Removes a field from this
+ *
+ * @return the removed value of the field, or null if none
*/
- // TODO: Remove on Vespa 7
- @Deprecated
- public HitField buildHitField(String key) {
- return buildHitField(key, false);
+ public Object removeField(String field) {
+ return getFieldMap().remove(field);
}
/**
- * Generate a HitField from a field if the field exists.
- *
- * @deprecated do not use
+ * Returns the keys of the fields of this hit as a modifiable view.
+ * This follows the rules of key sets returned from maps: Key removals are reflected
+ * in the map, add and addAll is not supported.
*/
- // TODO: Remove on Vespa 7
- @Deprecated
+ public Set<String> fieldKeys() {
+ return getFieldMap().keySet();
+ }
+
+ /**
+ * Changes the key under which a value is found. This is useful because it allows keys to be changed
+ * without accessing the value (which may be lazily created).
+ */
+ public void changeFieldKey(String oldKey, String newKey) {
+ Map<String,Object> fieldMap = getFieldMap();
+ Object value = fieldMap.remove(oldKey);
+ fieldMap.put(newKey, value);
+ }
+
+ private Map<String, Object> getFieldMap() {
+ return getFieldMap(16);
+ }
+
+ private Map<String, Object> getFieldMap(int minSize) {
+ if (fields == null) {
+ // Compensate for loadfactor and then some, rounded up....
+ fields = new LinkedHashMap<>(2*minSize);
+ }
+ return fields;
+ }
+
+ private Map<String, Object> getUnmodifiableFieldMap() {
+ if (unmodifiableFieldMap == null) {
+ if (fields == null) {
+ return Collections.emptyMap();
+ } else {
+ unmodifiableFieldMap = Collections.unmodifiableMap(fields);
+ }
+ }
+ return unmodifiableFieldMap;
+ }
+
+ /** Generate a HitField from a field if the field exists */
+ public HitField buildHitField(String key) {
+ return buildHitField(key, false);
+ }
+
+ /** Generate a HitField from a field if the field exists */
+ @SuppressWarnings("deprecation")
public HitField buildHitField(String key, boolean forceNoPreTokenize) {
return buildHitField(key, forceNoPreTokenize, false);
}
+ // TODO: Remove third parameter on Vespa 7
+ @Deprecated
public HitField buildHitField(String key, boolean forceNoPreTokenize, boolean forceStringHandling) {
Object o = getField(key);
- if (o == null) {
- return null;
- }
-
- if (o instanceof HitField) {
- return (HitField) o;
- }
+ if (o == null) return null;
+ if (o instanceof HitField) return (HitField)o;
HitField h;
if (forceNoPreTokenize) {
@@ -469,79 +527,13 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
return h;
}
- /**
- * Sets the value of a field
- *
- * @return the previous value, or null if none
- */
- public Object setField(String key, Object value) {
- return getFieldMap().put(key, value);
- }
-
/** Returns the types of this as a modifiable set. Modifications to this set are directly reflected in this hit */
public Set<String> types() { return types; }
- /**
- * Returns all types of this hit as a space-separated string
- *
- * @return all the types of this hit on the form "type1 type2 type3"
- * (in no particular order). An empty string (never null) if
- * no types are added
- */
+ /** @deprecated do not use */
+ @Deprecated
public String getTypeString() {
- StringBuilder buffer = new StringBuilder(types.size() * 7);
-
- for (Iterator<String> i = types.iterator(); i.hasNext();) {
- buffer.append(i.next());
- if (i.hasNext())
- buffer.append(" ");
- }
- return buffer.toString();
- }
-
- /**
- * Returns true if the argument is a hit having the same uri as this
- */
- public boolean equals(Object object) {
- if (!(object instanceof Hit)) {
- return false;
- }
- return getId().equals(((Hit) object).getId());
- }
-
- /**
- * Returns the hashCode of this hit, which is the hashcode of its uri.
- */
- public int hashCode() {
- if (getId() == null)
- throw new IllegalStateException("Id has not been set.");
-
- return getId().hashCode();
- }
-
- /** Compares this hit to another hit */
- public int compareTo(Hit other) {
- // higher relevance is better
- int result = other.getRelevance().compareTo(getRelevance());
- if (result != 0) {
- return result;
- }
- // lower addnumber is better
- result = this.getAddNumber() - other.getAddNumber();
- if (result != 0) {
- return result;
- }
-
- // if all else fails, compare URIs (alphabetically)
- if (this.getId() == null && other.getId() == null) {
- return 0;
- } else if (other.getId() == null) {
- return -1;
- } else if (this.getId() == null) {
- return 1;
- } else {
- return this.getId().compareTo(other.getId());
- }
+ return types().stream().collect(Collectors.joining(" "));
}
/**
@@ -549,13 +541,19 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
*
* Used to order equal relevant hit by add order. -1 if this hit
* has never been added to a result.
+ *
+ * @deprecated do not use
*/
+ @Deprecated // TODO: Make package private on Vespa 7
public int getAddNumber() { return addNumber; }
/**
* Sets the add number, assigned when adding the hit to a Result,
- * used to order equal relevant hit by add order
+ * used to order equal relevant hit by add order.
+ *
+ * @deprecated do not use
*/
+ @Deprecated // TODO: Make package private on Vespa 7
public void setAddNumber(int addNumber) { this.addNumber = addNumber; }
/**
@@ -578,82 +576,37 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
return isMeta() || auxiliary;
}
- public void setAuxiliary(boolean auxiliary) { this.auxiliary=auxiliary; }
-
- /** Removes all fields from this */
- public void clearFields() {
- getFieldMap().clear();
- }
-
- /** Removes a field from this */
- public Object removeField(String field) {
- return getFieldMap().remove(field);
- }
-
- /**
- * Returns the keys of the fields of this hit as a modifiable view.
- * This follows the rules of key sets returned from maps: Key removals are reflected
- * in the map, add and addAll is not supported.
- */
- public Set<String> fieldKeys() {
- return getFieldMap().keySet();
- }
-
- /**
- * Changes the key under which a value is found. This is useful because it allows keys to be changed
- * without accessing the value (which may be lazily created).
- */
- public void changeFieldKey(String oldKey,String newKey) {
- Map<String,Object> fieldMap = getFieldMap();
- Object value=fieldMap.remove(oldKey);
- fieldMap.put(newKey,value);
- }
-
- /**
- * Returns a string describing this hit
- */
- public String toString() {
- return "hit " + getId() + " (relevance " + getRelevance() + ")";
- }
-
- public Hit clone() {
- Hit hit = (Hit) super.clone();
-
- hit.fields = fields != null ? new LinkedHashMap<>(fields) : null;
- hit.unmodifiableFieldMap = null;
- hit.types = new LinkedHashSet<>(types);
- if (filled != null) {
- hit.setFilledInternal(new HashSet<>(filled));
- }
-
- return hit;
- }
+ public void setAuxiliary(boolean auxiliary) { this.auxiliary = auxiliary; }
+ /** @deprecated do not use */
+ @Deprecated // TODO: Remove on Vespa 7
public int getSourceNumber() { return sourceNumber; }
+ /** @deprecated do not use */
+ @Deprecated // TODO: Remove on Vespa 7
public void setSourceNumber(int number) { this.sourceNumber = number; }
/** Returns the query which produced this hit, or null if not known */
public Query getQuery() { return query; }
+ /** Returns the query which produced this hit as a request, or null if not known */
public Request request() { return query; }
- // TODO: rethink hit tagging
- // hit group -> need option to retag
- // hit -> should only set query once
+ /** Sets the query which produced this. This is ignored (except if this is a HitGroup) if a query is already set */
public final void setQuery(Query query) {
if (this.query == null || this instanceof HitGroup) {
this.query = query;
}
}
- // TODO: Deprecate
/**
* Returns a field of this hit XML escaped and without token
* delimiters.
*
+ * @deprecated do not use
* @return a field of this hit, or null if the property is not set
*/
+ @Deprecated // TODO: Remove on Vespa 7
public String getFieldXML(String key) {
Object p = getField(key);
@@ -661,9 +614,7 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
return null;
} else if (p instanceof HitField) {
return ((HitField)p).quotedContent(false);
- } else if (p instanceof StructuredData) {
- return p.toString();
- } else if (p instanceof XMLString || p instanceof JSONString) {
+ } else if (p instanceof StructuredData || p instanceof XMLString || p instanceof JSONString) {
return p.toString();
} else {
return XML.xmlEscape(p.toString(), false, '\u001f');
@@ -672,8 +623,6 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
/**
* @deprecated do not use
- *
- * @return a field without bolding markup
*/
@Deprecated // TODO: Remove on Vespa 7
public String getUnboldedField(String key, boolean escape) {
@@ -694,11 +643,7 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
}
}
- /**
- * Set meta data describing how a given searcher should treat this hit.
- * It is currently recommended that the invoker == searcher.
- * <b>Internal. Do not use!</b>
- */
+ /** Attach some data to this hit for this searcher */
public void setSearcherSpecificMetaData(Searcher searcher, Object data) {
if (searcherSpecificMetaData == null) {
searcherSpecificMetaData = Collections.singletonMap(searcher, data);
@@ -717,21 +662,17 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
}
}
- /**
- * get meta data describing how a given searcher should treat this hit.
- * It is currently recommended that the invoker == searcher
- * <b>Internal. Do not use!</b>
- */
+ /** Returns data attached to this hit for this searcher, or null if none */
public Object getSearcherSpecificMetaData(Searcher searcher) {
return searcherSpecificMetaData != null ? searcherSpecificMetaData.get(searcher) : null;
}
/**
- * For vespa internal use only.
- * This is only for the ones specially interested. It will replace the backing
- * for filled.
+ * Internal - do not use
+ *
* @param filled the backing set
*/
+ // TODO: Make package private on Vespa 7
protected final void setFilledInternal(Set<String> filled) {
this.filled = filled;
unmodifiableFilled = (filled != null) ? Collections.unmodifiableSet(filled) : null;
@@ -744,33 +685,15 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
*
* @return the set of filled summaries.
*/
+ // TODO: Make package private on Vespa 7
protected final Set<String> getFilledInternal() {
return filled;
}
- private Map<String,Object> getFieldMap() {
- return getFieldMap(16);
- }
-
- private Map<String,Object> getFieldMap(int minSize) {
- if (fields == null) {
- // Compensate for loadfactor and then some, rounded up....
- fields = new LinkedHashMap<>(2*minSize);
- }
- return fields;
- }
-
- private Map<String,Object> getUnmodifiableFieldMap() {
- if (unmodifiableFieldMap == null) {
- if (fields == null) {
- return Collections.emptyMap();
- } else {
- unmodifiableFieldMap = Collections.unmodifiableMap(fields);
- }
- }
- return unmodifiableFieldMap;
- }
-
+ /**
+ * @deprecated do not use
+ */
+ @Deprecated // TODO: Remove on Vespa 7
public static String stripCharacter(char strip, String toStripFrom) {
StringBuilder builder = null;
@@ -797,10 +720,72 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
}
}
+ /** Releases the resources held by this, making it irreversibly unusable */
protected void close() {
query = null;
fields = null;
unmodifiableFieldMap = null;
}
+ /** Returns true if the argument is a hit having the same uri as this */
+ @Override
+ public boolean equals(Object object) {
+ if ( ! (object instanceof Hit))
+ return false;
+ return getId().equals(((Hit) object).getId());
+ }
+
+ /** Returns the hashCode of this hit, which is the hashcode of its uri. */
+ @Override
+ public int hashCode() {
+ if (getId() == null)
+ throw new IllegalStateException("Id has not been set.");
+
+ return getId().hashCode();
+ }
+
+ /** Compares this hit to another hit */
+ @SuppressWarnings("deprecation")
+ @Override
+ public int compareTo(Hit other) {
+ // higher relevance is before
+ int result = other.getRelevance().compareTo(getRelevance());
+ if (result != 0)
+ return result;
+
+ // lower addnumber is before
+ result = this.getAddNumber() - other.getAddNumber();
+ if (result != 0)
+ return result;
+
+ // if all else fails, compare URIs (alphabetically)
+ if (this.getId() == null && other.getId() == null)
+ return 0;
+ else if (other.getId() == null)
+ return -1;
+ else if (this.getId() == null)
+ return 1;
+ else
+ return this.getId().compareTo(other.getId());
+ }
+
+ @Override
+ public Hit clone() {
+ Hit hit = (Hit) super.clone();
+
+ hit.fields = fields != null ? new LinkedHashMap<>(fields) : null;
+ hit.unmodifiableFieldMap = null;
+ hit.types = new LinkedHashSet<>(types);
+ if (filled != null) {
+ hit.setFilledInternal(new HashSet<>(filled));
+ }
+
+ return hit;
+ }
+
+ @Override
+ public String toString() {
+ return "hit " + getId() + " (relevance " + getRelevance() + ")";
+ }
+
}
diff --git a/container-search/src/main/java/com/yahoo/search/result/HitGroup.java b/container-search/src/main/java/com/yahoo/search/result/HitGroup.java
index 8ad8e6a732f..42d62cc0ec5 100644
--- a/container-search/src/main/java/com/yahoo/search/result/HitGroup.java
+++ b/container-search/src/main/java/com/yahoo/search/result/HitGroup.java
@@ -682,6 +682,7 @@ public class HitGroup extends Hit implements DataList<Hit>, Cloneable, Iterable<
// -------------- State bookkeeping
/** Ensures result invariants. Must be called when a hit is added to this result. */
+ @SuppressWarnings("deprecation")
private void handleNewHit(Hit hit) {
if (!hit.isAuxiliary())
concreteHitCount++;
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 c179851ba00..9b2de75e272 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
@@ -107,7 +107,7 @@ public class SlimeSummaryTestCase {
DocsumDefinitionSet set = createDocsumDefinitionSet(summary_cf);
byte[] docsum = makeTimeout();
FastHit hit = new FastHit();
- assertEquals("Hit hit index:0/0/000000000000000000000000 (relevance null) [fasthit, globalid: 0 0 0 0 0 0 0 0 0 0 0 0, partId: 0, distributionkey: 0] failed: Timed out....", set.lazyDecode("default", docsum, hit));
+ assertEquals("Hit hit index:null/0/000000000000000000000000 (relevance null) [fasthit, globalid: 0 0 0 0 0 0 0 0 0 0 0 0, partId: 0, distributionkey: 0] failed: Timed out....", set.lazyDecode("default", docsum, hit));
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java
index f8aa5e01853..e8af1b8e0ac 100644
--- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java
@@ -72,7 +72,7 @@ public class DocsumDefinitionTestCase {
assertEquals("1", hit.getField("EXTINFOSOURCE").toString());
assertEquals("10", hit.getField("LANG1").toString());
assertEquals("352", hit.getField("WORDS").toString());
- assertEquals("index:0/0/" + FastHit.asHexString(hit.getGlobalId()), hit.getId().toString());
+ assertEquals("index:null/0/" + FastHit.asHexString(hit.getGlobalId()), hit.getId().toString());
}
public static GlobalId createGlobalId(int docId) {
diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java
index 7d905d286fc..2a91319a905 100644
--- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java
@@ -187,13 +187,13 @@ public class FastSearcherTestCase {
assertEquals(100, fastSearcher.getCacheControl().capacity()); // Default cache =100MB
- Result result = doSearch(fastSearcher,new Query("?query=ignored"), 0, 10);
+ Result result = doSearch(fastSearcher, new Query("?query=ignored"), 0, 10);
Execution execution = new Execution(chainedAsSearchChain(fastSearcher), Execution.Context.createContextStub());
assertEquals(2, result.getHitCount());
execution.fill(result);
- assertCorrectHit1((FastHit) result.hits().get(0));
- assertCorrectTypes1((FastHit) result.hits().get(0));
+ assertCorrectHit1((FastHit)result.hits().get(0));
+ assertCorrectTypes1((FastHit)result.hits().get(0));
for (int idx = 0; idx < result.getHitCount(); idx++) {
assertTrue(!result.hits().get(idx).isCached());
}
@@ -545,7 +545,7 @@ public class FastSearcherTestCase {
hit.getField("TITLE"));
assertEquals("352", hit.getField("WORDS").toString());
assertEquals(2003., hit.getRelevance().getScore(), 0.01d);
- assertEquals("index:0/234/" + FastHit.asHexString(hit.getGlobalId()), hit.getId().toString());
+ assertEquals("index:testhittype/234/" + FastHit.asHexString(hit.getGlobalId()), hit.getId().toString());
assertEquals("9190", hit.getField("BYTES").toString());
assertEquals("testhittype", hit.getSource());
}
diff --git a/container-search/src/test/java/com/yahoo/search/federation/vespa/test/ResultBuilderTestCase.java b/container-search/src/test/java/com/yahoo/search/federation/vespa/test/ResultBuilderTestCase.java
index 494e3f06a61..50186e03ae8 100644
--- a/container-search/src/test/java/com/yahoo/search/federation/vespa/test/ResultBuilderTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/federation/vespa/test/ResultBuilderTestCase.java
@@ -75,7 +75,7 @@ public class ResultBuilderTestCase {
assertEquals("reward_for_thumb", g1.get(1).getField("id").toString());
assertEquals(10, g2.size());
HitGroup g3 = (HitGroup) g2.get(3);
- assertEquals("badge", g3.getTypeString());
+ assertEquals("badge", g3.types().iterator().next());
assertEquals(2, g3.size());
assertEquals("badge/Topic Explorer 5", g3.get(0).getField("name").toString());
}
diff --git a/container-search/src/test/java/com/yahoo/search/grouping/vespa/HitConverterTestCase.java b/container-search/src/test/java/com/yahoo/search/grouping/vespa/HitConverterTestCase.java
index 49f5642af4e..d21562a2569 100644
--- a/container-search/src/test/java/com/yahoo/search/grouping/vespa/HitConverterTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/grouping/vespa/HitConverterTestCase.java
@@ -19,6 +19,8 @@ import com.yahoo.searchlib.aggregation.FS4Hit;
import com.yahoo.searchlib.aggregation.VdsHit;
import org.junit.Test;
+import java.util.Collections;
+
import static org.junit.Assert.*;
/**
@@ -33,20 +35,19 @@ public class HitConverterTestCase {
@Test
public void requireThatHitsAreConverted() {
HitConverter converter = new HitConverter(new MySearcher(), new Query());
- Hit hit = converter.toSearchHit("default", new FS4Hit(1, createGlobalId(2), 3).setContext(new Hit("hit:ctx")));
+ Hit hit = converter.toSearchHit("default", new FS4Hit(1, createGlobalId(2), 3).setContext(context()));
assertNotNull(hit);
- assertEquals(new URI("index:0/1/" + FastHit.asHexString(createGlobalId(2))), hit.getId());
+ assertEquals(new URI("index:null/1/" + FastHit.asHexString(createGlobalId(2))), hit.getId());
- hit = converter.toSearchHit("default", new FS4Hit(4, createGlobalId(5), 6).setContext(new Hit("hit:ctx")));
+ hit = converter.toSearchHit("default", new FS4Hit(4, createGlobalId(5), 6).setContext(context()));
assertNotNull(hit);
- assertEquals(new URI("index:0/4/" + FastHit.asHexString(createGlobalId(5))), hit.getId());
+ assertEquals(new URI("index:null/4/" + FastHit.asHexString(createGlobalId(5))), hit.getId());
}
@Test
public void requireThatContextDataIsCopied() {
- Hit ctxHit = new Hit("hit:ctx");
+ Hit ctxHit = context();
ctxHit.setSource("69");
- ctxHit.setSourceNumber(69);
Query ctxQuery = new Query();
ctxHit.setQuery(ctxQuery);
@@ -58,13 +59,12 @@ public class HitConverterTestCase {
assertEquals(createGlobalId(2), ((FastHit)hit).getGlobalId());
assertSame(ctxQuery, hit.getQuery());
assertEquals(ctxHit.getSource(), hit.getSource());
- assertEquals(ctxHit.getSourceNumber(), hit.getSourceNumber());
}
@Test
public void requireThatHitTagIsCopiedFromGroupingListContext() {
QueryPacketData ctxTag = new QueryPacketData();
- GroupingListHit ctxHit = new GroupingListHit(null, null);
+ GroupingListHit ctxHit = context();
ctxHit.setQueryPacketData(ctxTag);
HitConverter converter = new HitConverter(new MySearcher(), new Query());
@@ -78,7 +78,7 @@ public class HitConverterTestCase {
public void requireThatSummaryClassIsSet() {
Searcher searcher = new MySearcher();
HitConverter converter = new HitConverter(searcher, new Query());
- Hit hit = converter.toSearchHit("69", new FS4Hit(1, createGlobalId(2), 3).setContext(new Hit("hit:ctx")));
+ Hit hit = converter.toSearchHit("69", new FS4Hit(1, createGlobalId(2), 3).setContext(context()));
assertNotNull(hit);
assertTrue(hit instanceof FastHit);
assertEquals("69", hit.getSearcherSpecificMetaData(searcher));
@@ -108,6 +108,10 @@ public class HitConverterTestCase {
}
}
+ private static GroupingListHit context() {
+ return new GroupingListHit(Collections.emptyList(), null);
+ }
+
private static DocumentdbInfoConfig.Documentdb sixtynine() {
DocumentdbInfoConfig.Documentdb.Builder summaryConfig = new DocumentdbInfoConfig.Documentdb.Builder();
summaryConfig.name("none");
diff --git a/container-search/src/test/java/com/yahoo/search/result/test/HitGroupTestCase.java b/container-search/src/test/java/com/yahoo/search/result/test/HitGroupTestCase.java
index b8f033444c8..f7c8a2a80b0 100644
--- a/container-search/src/test/java/com/yahoo/search/result/test/HitGroupTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/result/test/HitGroupTestCase.java
@@ -25,16 +25,6 @@ import static org.junit.Assert.assertTrue;
public class HitGroupTestCase {
@Test
- public void testStringStripping() {
- assertEquals("avabarne", Hit.stripCharacter('j', "javabjarne"));
- assertEquals("", Hit.stripCharacter('j', ""));
- assertEquals("", Hit.stripCharacter('j', "j"));
- assertEquals("frank", Hit.stripCharacter('j', "frank"));
- assertEquals("foo", Hit.stripCharacter('j', "fooj"));
- assertEquals("", Hit.stripCharacter('j', "jjjjj"));
- }
-
- @Test
public void testErrorsConsistencyUsingErrorOperations() {
HitGroup hits = new HitGroup();
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/ConfigAgent.java b/messagebus/src/main/java/com/yahoo/messagebus/ConfigAgent.java
index 1f866bb5752..286587e66e0 100755
--- a/messagebus/src/main/java/com/yahoo/messagebus/ConfigAgent.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/ConfigAgent.java
@@ -13,9 +13,10 @@ import com.yahoo.messagebus.routing.RoutingTableSpec;
* This class implements subscription to message bus config. To use configuration one must implement the {@link
* ConfigHandler} interface.
*
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ * @author Simon Thoresen
*/
public class ConfigAgent implements ConfigSubscriber.SingleSubscriber<MessagebusConfig>{
+
private final ConfigURI configURI;
private final ConfigHandler handler;
private ConfigSubscriber subscriber;
@@ -111,4 +112,5 @@ public class ConfigAgent implements ConfigSubscriber.SingleSubscriber<Messagebus
subscriber.close();
}
}
+
}