diff options
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(); } } + } |