diff options
Diffstat (limited to 'container-search/src/main/java/com/yahoo/prelude')
45 files changed, 76 insertions, 3376 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/Index.java b/container-search/src/main/java/com/yahoo/prelude/Index.java index 109ecfd29f8..8433939090b 100644 --- a/container-search/src/main/java/com/yahoo/prelude/Index.java +++ b/container-search/src/main/java/com/yahoo/prelude/Index.java @@ -53,7 +53,6 @@ public class Index { private boolean uriIndex = false; private boolean hostIndex = false; private StemMode stemMode = StemMode.NONE; - private Attribute[] matchGroup = null; private boolean isAttribute = false; private boolean isDefaultPosition = false; private boolean dynamicSummary=false; @@ -165,8 +164,6 @@ public class Index { setAttribute(true); } else if (commandString.equals("default-position")) { setDefaultPosition(true); - } else if (commandString.startsWith("match-group ")) { - setMatchGroup(commandString.substring(12).split(" ")); } else if (commandString.equals("plain-tokens")) { setPlainTokens(true); } else if (commandString.equals("multivalue")) { @@ -269,19 +266,6 @@ public class Index { return "(null)".equals(name); } - public Attribute[] getMatchGroup() { // TODO: Not in use on Vespa 6 - return matchGroup; - } - - public void setMatchGroup(String[] attributes) { - Attribute[] a = new Attribute[attributes.length]; - - for (int i = 0; i < attributes.length; i++) { - a[i] = new Attribute(attributes[i].trim()); - } - this.matchGroup = a; - } - public boolean isAttribute() { return isAttribute; } diff --git a/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java b/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java index 448d8e7855f..2fcd2466dd8 100644 --- a/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java +++ b/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java @@ -44,12 +44,8 @@ public class IndexFacts { /** * The name of the default search definition, which is the union of all * known document types. - * - * @deprecated do not use */ - // TODO: Make this package private in Vespa 7 - @Deprecated // OK - public static final String unionName = "unionOfAllKnown"; + static final String unionName = "unionOfAllKnown"; /** A search definition which contains the union of all settings. */ @SuppressWarnings("deprecation") @@ -106,31 +102,6 @@ public class IndexFacts { return clusters != null ? clusters : Collections.<String>emptyList(); } - /** - * Public only for testing. - * - * @deprecated set at creation time - */ - // TODO: Remove on Vespa 7 - @Deprecated // OK - public void setClusters(Map<String, List<String>> clusters) { - ensureNotFrozen(); - this.clusters = clusters; - clusterByDocument = invert(clusters); - } - - /** - * @deprecated set indexes at creation time instead - */ - // TODO: Remove on Vespa 7 - @Deprecated // OK - public void setSearchDefinitions(Map<String, SearchDefinition> searchDefinitions, - SearchDefinition unionSearchDefinition) { - ensureNotFrozen(); - this.searchDefinitions = searchDefinitions; - this.unionSearchDefinition = unionSearchDefinition; - } - private boolean isInitialized() { return searchDefinitions.size() > 0; } @@ -312,58 +283,6 @@ public class IndexFacts { } } - - /** - * Add a string to be accepted as an index name when parsing a - * query. - * - * For testing only. - * - * @param sdName name of search definition containing index, if null, modify default set - * @param indexName name of index, actual or otherwise - * @deprecated set indexes at creation time instead - */ - // TODO: Remove on Vespa 7 - @Deprecated // OK - public void addIndex(String sdName, String indexName) { - ensureNotFrozen(); - - SearchDefinition sd; - if (sdName == null) { - sd = unionSearchDefinition; - } else if (searchDefinitions.containsKey(sdName)) { - sd = searchDefinitions.get(sdName); - } else { - sd = new SearchDefinition(sdName); - searchDefinitions.put(sdName, sd); - } - sd.getOrCreateIndex(indexName); - unionSearchDefinition.getOrCreateIndex(indexName); - } - - /** - * Adds an index to the specified index, and the default index settings, - * overriding any current settings for this index - * @deprecated set indexes at creation time instead - */ - // TODO: Remove on Vespa 7 - @Deprecated // OK - public void addIndex(String sdName, Index index) { - ensureNotFrozen(); - - SearchDefinition sd; - if (sdName == null) { - sd = unionSearchDefinition; - } else if (searchDefinitions.containsKey(sdName)) { - sd = searchDefinitions.get(sdName); - } else { - sd = new SearchDefinition(sdName); - searchDefinitions.put(sdName, sd); - } - sd.addIndex(index); - unionSearchDefinition.addIndex(index); - } - public String getDefaultPosition(String sdName) { SearchDefinition sd; if (sdName == null) { diff --git a/container-search/src/main/java/com/yahoo/prelude/IndexModel.java b/container-search/src/main/java/com/yahoo/prelude/IndexModel.java index d2950078868..dd2bd1ee2f1 100644 --- a/container-search/src/main/java/com/yahoo/prelude/IndexModel.java +++ b/container-search/src/main/java/com/yahoo/prelude/IndexModel.java @@ -39,8 +39,10 @@ public final class IndexModel { /** * Use IndexModel as a pure wrapper for the parameters given. + * + * @deprecated use the constructor without the third parameter */ - // TODO: Deprecate on Vespa 7 and remove on Vespa 8 + @Deprecated // TODO: Remove Vespa 8 public IndexModel(Map<String, List<String>> masterClusters, Map<String, SearchDefinition> searchDefinitions, SearchDefinition unionSearchDefinition) { @@ -90,7 +92,6 @@ public final class IndexModel { IndexInfoConfig.Indexinfo.Command command = j.next(); sd.addCommand(command.indexname(),command.command()); } - sd.fillMatchGroups(); searchDefinitions.put(info.name(), sd); } @@ -127,7 +128,6 @@ public final class IndexModel { } } - union.fillMatchGroups(); return union; } @@ -135,7 +135,8 @@ public final class IndexModel { public Map<String, SearchDefinition> getSearchDefinitions() { return searchDefinitions; } - // TODO: Deprecate on Vespa 7 and make package scope on Vespa 8 + /** @deprecated do not use */ + @Deprecated // TODO: Remove on Vespa 8 public SearchDefinition getUnionSearchDefinition() { return unionSearchDefinition; } } diff --git a/container-search/src/main/java/com/yahoo/prelude/Pong.java b/container-search/src/main/java/com/yahoo/prelude/Pong.java index ba3ff2eda00..cef64c293af 100644 --- a/container-search/src/main/java/com/yahoo/prelude/Pong.java +++ b/container-search/src/main/java/com/yahoo/prelude/Pong.java @@ -46,7 +46,7 @@ public class Pong { public int getErrorSize() { return errors.size(); } - + /** Returns the number of active documents in the backend responding in this Pong, if available */ public Optional<Long> activeDocuments() { if ( ! pongPacket.isPresent()) return Optional.empty(); diff --git a/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java b/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java index aa76bd5912a..7859a9698d9 100644 --- a/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java +++ b/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java @@ -96,19 +96,4 @@ public class SearchDefinition { } } - public void fillMatchGroups() { - for (Index i : indices.values()) { - Attribute[] matchGroup = i.getMatchGroup(); - if (matchGroup == null) { - continue; - } - for (Attribute a : matchGroup) { - Index m = getIndex(a.name); - if (m != null) { - a.setTokenizedContent(!m.isAttribute()); - } - } - } - } - } 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 fd150f975c3..92b6eef906e 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 @@ -11,7 +11,6 @@ import com.yahoo.concurrent.Receiver.MessageState; import com.yahoo.container.QrSearchersConfig; import com.yahoo.container.handler.VipStatus; import com.yahoo.fs4.mplex.Backend; -import com.yahoo.container.search.LegacyEmulationConfig; import com.yahoo.net.HostName; import com.yahoo.search.dispatch.Dispatcher; import com.yahoo.prelude.fastsearch.FS4ResourcePool; @@ -100,7 +99,6 @@ public class ClusterSearcher extends Searcher { QrSearchersConfig qrsConfig, ClusterConfig clusterConfig, DocumentdbInfoConfig documentDbConfig, - LegacyEmulationConfig emulationConfig, QrMonitorConfig monitorConfig, DispatchConfig dispatchConfig, ClusterInfoConfig clusterInfoConfig, @@ -133,7 +131,7 @@ public class ClusterSearcher extends Searcher { SummaryParameters docSumParams = new SummaryParameters(qrsConfig .com().yahoo().prelude().fastsearch().FastSearcher().docsum() .defaultclass()); - + for (DocumentdbInfoConfig.Documentdb docDb : documentDbConfig.documentdb()) { String docTypeName = docDb.name(); documentTypes.add(docTypeName); @@ -146,7 +144,7 @@ public class ClusterSearcher extends Searcher { if (searchClusterConfig.indexingmode() == STREAMING) { VdsStreamingSearcher searcher = vdsCluster(fs4ResourcePool.getServerId(), searchClusterIndex, - searchClusterConfig, cacheParams, emulationConfig, docSumParams, + searchClusterConfig, cacheParams, docSumParams, documentDbConfig); addBackendSearcher(searcher); } else { @@ -156,7 +154,7 @@ public class ClusterSearcher extends Searcher { if ( ! isRemote(searchClusterConfig.dispatcher(dispatcherIndex).host())) { Backend dispatchBackend = createBackend(searchClusterConfig.dispatcher(dispatcherIndex)); FastSearcher searcher = searchDispatch(searchClusterIndex, fs4ResourcePool, - cacheParams, emulationConfig, docSumParams, + cacheParams, docSumParams, documentDbConfig, dispatchBackend, dispatcher, dispatcherIndex); addBackendSearcher(searcher); } @@ -192,22 +190,21 @@ public class ClusterSearcher extends Searcher { } private static ClusterParams makeClusterParams(int searchclusterIndex, - LegacyEmulationConfig emulConfig, int dispatchIndex) { - return new ClusterParams("sc" + searchclusterIndex + ".num" + dispatchIndex, emulConfig); + return new ClusterParams("sc" + searchclusterIndex + ".num" + dispatchIndex); } private static FastSearcher searchDispatch(int searchclusterIndex, FS4ResourcePool fs4ResourcePool, CacheParams cacheParams, - LegacyEmulationConfig emulConfig, SummaryParameters docSumParams, DocumentdbInfoConfig documentdbInfoConfig, Backend backend, Dispatcher dispatcher, int dispatcherIndex) { - ClusterParams clusterParams = makeClusterParams(searchclusterIndex, emulConfig, dispatcherIndex); - return new FastSearcher(backend, fs4ResourcePool, dispatcher, docSumParams, clusterParams, cacheParams, + ClusterParams clusterParams = makeClusterParams(searchclusterIndex, + dispatcherIndex); + return new FastSearcher(backend, fs4ResourcePool, dispatcher, docSumParams, clusterParams, cacheParams, documentdbInfoConfig); } @@ -215,14 +212,13 @@ public class ClusterSearcher extends Searcher { int searchclusterIndex, QrSearchersConfig.Searchcluster searchClusterConfig, CacheParams cacheParams, - LegacyEmulationConfig emulConfig, SummaryParameters docSumParams, DocumentdbInfoConfig documentdbInfoConfig) { if (searchClusterConfig.searchdef().size() != 1) { throw new IllegalArgumentException("Search clusters in streaming search shall only contain a single searchdefinition : " + searchClusterConfig.searchdef()); } - ClusterParams clusterParams = makeClusterParams(searchclusterIndex, emulConfig, 0); + ClusterParams clusterParams = makeClusterParams(searchclusterIndex, 0); VdsStreamingSearcher searcher = (VdsStreamingSearcher) VespaBackEndSearcher .getSearcher("com.yahoo.vespa.streamingvisitors.VdsStreamingSearcher"); searcher.setSearchClusterConfigId(searchClusterConfig.rankprofiles().configid()); @@ -319,7 +315,7 @@ public class ClusterSearcher extends Searcher { if (invalidInDocTypes != null && !invalidInDocTypes.isEmpty()) { String plural = invalidInDocTypes.size() > 1 ? "s" : ""; - return new Result(query, + return new Result(query, ErrorMessage.createInvalidQueryParameter("Requested rank profile '" + rankProfile + "' is undefined for document type" + plural + " '" + StringUtils.join(invalidInDocTypes.iterator(), ", ") + "'")); @@ -384,7 +380,7 @@ public class ClusterSearcher extends Searcher { if (query.getTimeout() <= maxQueryTimeout) return; if (query.isTraceable(2)) { - query.trace("Query timeout (" + query.getTimeout() + " ms) > max query timeout (" + + query.trace("Query timeout (" + query.getTimeout() + " ms) > max query timeout (" + maxQueryTimeout + " ms). Setting timeout to " + maxQueryTimeout + " ms.", 2); } query.setTimeout(maxQueryTimeout); diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java index 3dfa506a967..2787447e791 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java @@ -1,8 +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.prelude.fastsearch; -import com.yahoo.container.search.LegacyEmulationConfig; - /** * Helper class for carrying around cluster-related * config parameters to the FastSearcher class. @@ -12,21 +10,12 @@ import com.yahoo.container.search.LegacyEmulationConfig; public class ClusterParams { public final String searcherName; - public final LegacyEmulationConfig emulation; - - /** - * For testcases only - */ - public ClusterParams(String name) { - this(name, new LegacyEmulationConfig(new LegacyEmulationConfig.Builder())); - } /** * Make up full ClusterParams */ - public ClusterParams(String name, LegacyEmulationConfig cfg) { + public ClusterParams(String name) { this.searcherName = name; - this.emulation = cfg; } } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinition.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinition.java index cdf696ebe1e..20615a099b6 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinition.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinition.java @@ -4,7 +4,6 @@ package com.yahoo.prelude.fastsearch; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.yahoo.data.access.Inspector; -import com.yahoo.container.search.LegacyEmulationConfig; import java.util.ArrayList; import java.util.HashMap; @@ -41,8 +40,7 @@ public class DocsumDefinition { this.fieldNameToIndex = fieldNameToIndexBuilder.build(); } - // TODO: Remove LegacyEmulationConfig (the config, not just the usage) on Vespa 7 - DocsumDefinition(DocumentdbInfoConfig.Documentdb.Summaryclass config, LegacyEmulationConfig emulConfig) { + DocsumDefinition(DocumentdbInfoConfig.Documentdb.Summaryclass config) { this.name = config.name(); List<DocsumField> fieldsBuilder = new ArrayList<>(); @@ -51,7 +49,7 @@ public class DocsumDefinition { for (DocumentdbInfoConfig.Documentdb.Summaryclass.Fields field : config.fields()) { // no, don't switch the order of the two next lines :) fieldNameToIndexBuilder.put(field.name(), fieldsBuilder.size()); - fieldsBuilder.add(DocsumField.create(field.name(), field.type(), emulConfig)); + fieldsBuilder.add(DocsumField.create(field.name(), field.type())); if (field.dynamic()) dynamic = true; } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinitionSet.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinitionSet.java index 07997f0c8f6..7745a71b24f 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinitionSet.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinitionSet.java @@ -7,7 +7,6 @@ import com.yahoo.data.access.Inspector; import com.yahoo.slime.Slime; import com.yahoo.data.access.slime.SlimeAdapter; import com.yahoo.prelude.ConfigurationException; -import com.yahoo.container.search.LegacyEmulationConfig; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -31,27 +30,15 @@ public final class DocsumDefinitionSet { private final static Logger log = Logger.getLogger(DocsumDefinitionSet.class.getName()); private final Map<String, DocsumDefinition> definitionsByName; - private final LegacyEmulationConfig emulationConfig; public DocsumDefinitionSet(DocumentdbInfoConfig.Documentdb config) { - this(config, new LegacyEmulationConfig(new LegacyEmulationConfig.Builder())); - } - - public DocsumDefinitionSet(DocumentdbInfoConfig.Documentdb config, LegacyEmulationConfig emulConfig) { - this(toDocsums(config, emulConfig), emulConfig); + this(toDocsums(config)); } public DocsumDefinitionSet(Collection<DocsumDefinition> docsumDefinitions) { - this(docsumDefinitions, new LegacyEmulationConfig(new LegacyEmulationConfig.Builder())); - } - - public DocsumDefinitionSet(Collection<DocsumDefinition> docsumDefinitions, LegacyEmulationConfig emulConfig) { this.definitionsByName = ImmutableMap.copyOf(docsumDefinitions.stream().collect(Collectors.toMap(DocsumDefinition::getName, p -> p))); - this.emulationConfig = emulConfig; } - public LegacyEmulationConfig legacyEmulationConfig() { return emulationConfig; } - /** * Returns the summary definition of the given name, or the default if not found. * @@ -111,10 +98,10 @@ public final class DocsumDefinitionSet { return definitionsByName.size(); } - private static Collection<DocsumDefinition> toDocsums(DocumentdbInfoConfig.Documentdb config, LegacyEmulationConfig emulConfig) { + private static Collection<DocsumDefinition> toDocsums(DocumentdbInfoConfig.Documentdb config) { Collection<DocsumDefinition> docsums = new ArrayList<>(); for (int i = 0; i < config.summaryclass().size(); ++i) - docsums.add(new DocsumDefinition(config.summaryclass(i), emulConfig)); + docsums.add(new DocsumDefinition(config.summaryclass(i))); if (docsums.isEmpty()) log.warning("No summary classes found in DocumentdbInfoConfig.Documentdb"); return docsums; diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumField.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumField.java index 777919286dd..4f52ef91725 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumField.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumField.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.prelude.fastsearch; -import com.yahoo.container.search.LegacyEmulationConfig; import com.yahoo.data.access.Inspector; import com.yahoo.log.LogLevel; @@ -31,19 +30,14 @@ public abstract class DocsumField { constructors.put(typename, constructor); } - DocsumField create(String typename, String name, LegacyEmulationConfig emulConfig) + DocsumField create(String typename, String name) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { DocsumField f = constructors.get(typename).newInstance(name); - f.emulConfig = emulConfig; return f; } } - private LegacyEmulationConfig emulConfig; - - final LegacyEmulationConfig getEmulConfig() { return emulConfig; } - static { fieldFactory = new FieldFactory(); @@ -75,14 +69,9 @@ public abstract class DocsumField { this.name = name; } - /* For unit test only */ public static DocsumField create(String name, String typename) { - return create(name, typename, new LegacyEmulationConfig(new LegacyEmulationConfig.Builder())); - } - - public static DocsumField create(String name, String typename, LegacyEmulationConfig emulConfig) { try { - return fieldFactory.create(typename, name, emulConfig); + return fieldFactory.create(typename, name); } catch (Exception e) { throw new RuntimeException("Unknown field type '" + typename + "'", e); } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocumentDatabase.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocumentDatabase.java index 0ae0983a1ae..aa492524c83 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocumentDatabase.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/DocumentDatabase.java @@ -2,7 +2,6 @@ package com.yahoo.prelude.fastsearch; import com.google.common.collect.ImmutableMap; -import com.yahoo.container.search.LegacyEmulationConfig; import java.util.ArrayList; import java.util.Collection; @@ -29,8 +28,8 @@ public class DocumentDatabase { private final ImmutableMap<String, RankProfile> rankProfiles; - public DocumentDatabase(DocumentdbInfoConfig.Documentdb documentDb, LegacyEmulationConfig emulConfig) { - this(documentDb.name(), new DocsumDefinitionSet(documentDb, emulConfig), toRankProfiles(documentDb.rankprofile())); + public DocumentDatabase(DocumentdbInfoConfig.Documentdb documentDb) { + this(documentDb.name(), new DocsumDefinitionSet(documentDb), toRankProfiles(documentDb.rankprofile())); } public DocumentDatabase(String name, DocsumDefinitionSet docsumDefinitionSet, Collection<RankProfile> rankProfiles) { 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 28d426cec06..8d73f6795d4 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 @@ -77,7 +77,6 @@ public class FastHit extends Hit { // Note: This constructor is only used for tests, production use is always of the empty constructor public FastHit(String uri, double relevance, String source) { setId(uri); - super.setField("uri", uri); // TODO: Remove on Vespa 7 setRelevance(new Relevance(relevance)); setSource(source); types().add("summary"); @@ -97,13 +96,6 @@ public class FastHit extends Hit { URI uri = super.getId(); if (uri != null) return uri; - // TODO: Remove on Vespa 7, this should be one of the last vestiges of URL field magic - Object uriField = getField("uri"); - if (uriField != null) { - setId(uriField.toString()); - return super.getId(); - } - // Fallback to index:[source]/[partid]/[id] if (indexUri != null) return indexUri; StringBuilder sb = new StringBuilder(64); @@ -315,21 +307,6 @@ public class FastHit extends Hit { return super.hasFields(); } - /** - * 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). - * - * @deprecated do not use - */ - @Deprecated // OK - @Override - @SuppressWarnings("deprecation") - public void changeFieldKey(String oldKey, String newKey) { - Object value = removeField(oldKey); - if (value != null) - setField(newKey, value); - } - private Object getSummaryValue(String name) { if (removedFields != null && removedFields.contains(name)) return null; @@ -357,13 +334,6 @@ public class FastHit extends Hit { } } - /** @deprecated do not use */ - // TODO: Make private on Vespa 7 - @Deprecated // OK - public static String asHexString(GlobalId gid) { - return asHexString(new StringBuilder(), gid).toString(); - } - private static StringBuilder asHexString(StringBuilder sb, GlobalId gid) { byte[] rawGid = gid.getRawId(); for (byte b : rawGid) { @@ -539,7 +509,7 @@ public class FastHit extends Hit { DocsumField fieldType = type.getField(name); if (fieldType == null) return null; Inspector fieldValue = data.field(name); - if ( ! fieldValue.valid() && ! fieldType.getEmulConfig().forceFillEmptyFields()) return null; + if ( ! fieldValue.valid()) return null; return fieldType.convert(fieldValue); } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FeatureDataField.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FeatureDataField.java index 28c63aa2d3a..1f60dd3d1cf 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FeatureDataField.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FeatureDataField.java @@ -3,7 +3,6 @@ package com.yahoo.prelude.fastsearch; import com.yahoo.data.access.Inspector; import com.yahoo.data.access.Type; -import com.yahoo.container.search.LegacyEmulationConfig; import com.yahoo.search.result.FeatureData; /** @@ -13,7 +12,7 @@ import com.yahoo.search.result.FeatureData; */ public class FeatureDataField extends LongstringField { - public FeatureDataField (String name) { + public FeatureDataField(String name) { super(name); } @@ -25,23 +24,12 @@ public class FeatureDataField extends LongstringField { @Override public Object convert(Inspector value) { if (! value.valid()) { - if (getEmulConfig().stringBackedFeatureData()) { - return ""; - } else if (getEmulConfig().forceFillEmptyFields()) { - return new FeatureData(com.yahoo.data.access.simple.Value.empty()); - } else { - return null; - } + return null; } if (value.type() == Type.STRING) { return value.asString(); } - FeatureData obj = new FeatureData(value); - if (getEmulConfig().stringBackedFeatureData()) { - return obj.toJson(); - } else { - return obj; - } + return new FeatureData(value); } } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/StructDataField.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/StructDataField.java index 9521854477a..18986667a6c 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/StructDataField.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/StructDataField.java @@ -4,7 +4,6 @@ package com.yahoo.prelude.fastsearch; import com.yahoo.search.result.StructuredData; import com.yahoo.data.access.Inspector; import com.yahoo.data.access.Type; -import com.yahoo.container.search.LegacyEmulationConfig; import com.yahoo.prelude.hitfield.JSONString; /** @@ -23,7 +22,7 @@ public class StructDataField extends JSONField { @Override public Object convert(Inspector value) { - if (getEmulConfig().stringBackedStructuredData() || value.type() == Type.STRING) { + if (value.type() == Type.STRING) { return super.convert(value); } return new StructuredData(value); 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 e8f5d7110f7..d6e87e58fd8 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 @@ -177,7 +177,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { if (documentdbInfoConfig != null) { for (DocumentdbInfoConfig.Documentdb docDb : documentdbInfoConfig.documentdb()) { - DocumentDatabase db = new DocumentDatabase(docDb, clusterParams.emulation); + DocumentDatabase db = new DocumentDatabase(docDb); if (documentDbs.isEmpty()) { defaultDocumentDb = db; } @@ -372,7 +372,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { s.append(" ranking.queryCache=true"); } if (query.getGroupingSessionCache() || query.getRanking().getQueryCache()) { - s.append(" sessionId=").append(query.getSessionId(false)); + s.append(" sessionId=").append(query.getSessionId()); } List<Grouping> grouping = GroupingExecutor.getGroupingList(query); diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/XMLField.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/XMLField.java index cb115502468..d768dda2657 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/XMLField.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/XMLField.java @@ -31,10 +31,10 @@ public class XMLField extends DocsumField { @Override public Object convert(Inspector value) { /* In Vespa 6 the backend will send an XML-formatted string to represent - * positions data. This will change in next version to sending an array - * of objects instead, suitable for the PositionsData class. + * positions data. This will change in next version to sending an object + * or an array of objects instead, suitable for the PositionsData class. */ - if (value.type() == Type.ARRAY) { + if (value.type() == Type.OBJECT || value.type() == Type.ARRAY) { return new PositionsData(value); } return convert(value.asString("")); diff --git a/container-search/src/main/java/com/yahoo/prelude/hitfield/FieldIterator.java b/container-search/src/main/java/com/yahoo/prelude/hitfield/FieldIterator.java index c8dc87aeb52..3c61678bbde 100644 --- a/container-search/src/main/java/com/yahoo/prelude/hitfield/FieldIterator.java +++ b/container-search/src/main/java/com/yahoo/prelude/hitfield/FieldIterator.java @@ -7,7 +7,7 @@ import java.util.ListIterator; /** * A specialized list iterator to manipulate FieldParts in HitField objects. * - * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + * @author Steinar Knutsen */ public class FieldIterator implements ListIterator<FieldPart> { 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 f6619a32a2b..2702da099be 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 @@ -24,7 +24,7 @@ public class HitField { private boolean xmlProperty; private List<FieldPart> tokenizedContent = null; - private String content = null; + private String content; private Object original; @@ -48,7 +48,7 @@ public class HitField { /** * @param f The field name * @param c The field content - * @param cjk true if this is a cjk-document + * @param cjk true if the content is CJK text */ public HitField(String f, String c, boolean cjk) { this(f, c, cjk, false); @@ -57,7 +57,7 @@ public class HitField { /** * @param f The field name * @param c The field content - * @param cjk true if this is a cjk-document + * @param cjk true if the content is CJK text */ public HitField(String f, XMLString c, boolean cjk) { this(f, c.toString(), cjk, true); @@ -66,7 +66,7 @@ public class HitField { /** * @param f The field name * @param c The field content - * @param cjk true if this is a cjk-document + * @param cjk true if the content is CJK text * @param xmlProperty true if this should not quote XML syntax */ public HitField(String f, String c, boolean cjk, boolean xmlProperty) { @@ -279,9 +279,8 @@ public class HitField { // Must null content reference _before_ calling getContent() content = null; } - /** - * @return the content of this field - */ + + /** Returns the content of this field */ public String getContent() { if (content == null) { StringBuilder buf = new StringBuilder(); @@ -294,13 +293,8 @@ public class HitField { return content; } - /** - * @return the content of this field, using the arguments as bolding - * tags - */ - public String getContent(String boldOpenTag, - String boldCloseTag, - String separatorTag) { + /** Returns the content of this field, using the arguments as bolding tags */ + public String getContent(String boldOpenTag, String boldCloseTag, String separatorTag) { StringBuilder buf = new StringBuilder(); Iterator<FieldPart> iter = ensureTokenized().iterator(); while(iter.hasNext()) { @@ -372,8 +366,9 @@ public class HitField { } return xml.toString(); } + /** - * @return the content of the field, stripped of markup + * Returns the content of the field, stripped of markup */ public String bareContent(boolean XMLQuote, boolean inAttribute) { StringBuilder bareContent = new StringBuilder(); diff --git a/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java b/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java index 06db012309e..eee7b310d13 100644 --- a/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java +++ b/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java @@ -86,6 +86,7 @@ public class JSONString implements Inspectable { didInitContent = true; } + @Override public String toString() { if (value != null) { return renderFromInspector(); diff --git a/container-search/src/main/java/com/yahoo/prelude/hitfield/TokenFieldIterator.java b/container-search/src/main/java/com/yahoo/prelude/hitfield/TokenFieldIterator.java index 95100dd4d39..beda005152c 100644 --- a/container-search/src/main/java/com/yahoo/prelude/hitfield/TokenFieldIterator.java +++ b/container-search/src/main/java/com/yahoo/prelude/hitfield/TokenFieldIterator.java @@ -8,7 +8,7 @@ import java.util.NoSuchElementException; /** * A specialized list iterator to manipulate tokens in HitField objects. * - * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + * @author Steinar Knutsen */ public class TokenFieldIterator implements ListIterator<FieldPart> { diff --git a/container-search/src/main/java/com/yahoo/prelude/logging/AccessLogEntry.java b/container-search/src/main/java/com/yahoo/prelude/logging/AccessLogEntry.java deleted file mode 100644 index f9faf242350..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/logging/AccessLogEntry.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.logging; - -/** - * Hollow compatibility class for com.yahoo.container.logging.AccessLogEntry. - * - * @author Steinar Knutsen - * @deprecated do not use - */ -// TODO: Remove on Vespa 7 -@Deprecated // OK -public class AccessLogEntry extends com.yahoo.container.logging.AccessLogEntry { - - public AccessLogEntry() { - super(); - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/logging/package-info.java b/container-search/src/main/java/com/yahoo/prelude/logging/package-info.java deleted file mode 100644 index 01126ec3484..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/logging/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -package com.yahoo.prelude.logging; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java b/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java index f6f96ae215c..244d895f357 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java @@ -13,7 +13,7 @@ import static com.yahoo.prelude.query.parser.Token.Kind.NUMBER; * @author Steinar Knutsen * @deprecated since 5.11, YQL+ should be used for formal queries */ -@Deprecated // OK DO NOT REMOVE (we'll keep this around longer) +@Deprecated // DO NOT REMOVE (we'll keep this around longer) public class AdvancedParser extends StructuredParser { public AdvancedParser(ParserEnvironment environment) { diff --git a/container-search/src/main/java/com/yahoo/prelude/querytransform/IndexCombinatorSearcher.java b/container-search/src/main/java/com/yahoo/prelude/querytransform/IndexCombinatorSearcher.java deleted file mode 100644 index ff603a64725..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/querytransform/IndexCombinatorSearcher.java +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.querytransform; - -import static com.yahoo.prelude.querytransform.PhrasingSearcher.PHRASE_REPLACEMENT; - -import com.yahoo.component.chain.dependencies.After; -import com.yahoo.component.chain.dependencies.Before; -import com.yahoo.component.chain.dependencies.Provides; -import com.yahoo.log.LogLevel; -import com.yahoo.prelude.Index; -import com.yahoo.prelude.Index.Attribute; -import com.yahoo.prelude.IndexFacts; -import com.yahoo.prelude.query.*; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.searchchain.Execution; -import com.yahoo.search.searchchain.PhaseNames; - -import java.util.*; - -/** - * Searcher to rewrite queries to achieve mixed recall between indices and - * memory attributes. - * - * @author Steinar Knutsen - * @deprecated do not use - */ -// TODO: Remove on Vespa 7 (not necessary any more) -@After({PhaseNames.RAW_QUERY, PHRASE_REPLACEMENT}) -@Before(PhaseNames.TRANSFORMED_QUERY) -@Provides(IndexCombinatorSearcher.MIXED_RECALL_REWRITE) -@Deprecated // OK -public class IndexCombinatorSearcher extends Searcher { - - public static final String MIXED_RECALL_REWRITE = "MixedRecallRewrite"; - - private static class ArrayComparator implements Comparator<Attribute[]> { - /** - * Note, this ignores if there is a difference in whether to - * attributes have tokenized content. (If this is the case, - * we are having worse problems anyway.) - */ - public int compare(Attribute[] o1, Attribute[] o2 ) { - if (o1.length < o2.length) { - return -1; - } else if (o1.length > o2.length) { - return 1; - } - int limit = o1.length; - for (int i = 0; i < limit; ++i) { - int r = o1[i].name.compareTo(o2[i].name); - if (r != 0) { - return r; - } - } - return 0; - } - } - - private final ArrayComparator comparator = new ArrayComparator(); - - private enum RewriteStrategies { - NONE, CHEAP_AND, EXPENSIVE_AND, FLAT - } - - @Override - public Result search(Query query, Execution execution) { - Item root = query.getModel().getQueryTree().getRoot(); - IndexFacts.Session session = execution.context().getIndexFacts().newSession(query); - String oldQuery = (query.getTraceLevel() >= 2) ? root.toString() : ""; - - if (root instanceof BlockItem || root instanceof PhraseItem) { - root = convertSinglePhraseOrBlock(root, session); - } else if (root instanceof CompositeItem) { - root = rewrite((CompositeItem) root, session); - } - query.getModel().getQueryTree().setRoot(root); - - if ((query.getTraceLevel() >= 2) && !(oldQuery.equals(root.toString()))) { - query.trace("Rewriting for mixed recall between indices and attributes", true, 2); - } - return execution.search(query); - } - - private RewriteStrategies chooseRewriteStrategy(CompositeItem c, IndexFacts.Session session) { - if (c instanceof OrItem) { - return RewriteStrategies.FLAT; - } else if (!(c instanceof AndItem)) { - return RewriteStrategies.NONE; - } - Map<Attribute[], Integer> m = new TreeMap<>(comparator); - for (Iterator<Item> i = c.getItemIterator(); i.hasNext();) { - Item j = i.next(); - if (j instanceof BlockItem || j instanceof PhraseItem) { - Attribute[] attributes= getIndices((HasIndexItem) j, session); - if (attributes == null) { - continue; - } - Integer count = m.get(attributes); - if (count == null) { - count = 1; - } else { - count = count.intValue() + 1; - } - m.put(attributes, count); - } - } - - if (m.size() == 0) { - return RewriteStrategies.NONE; - } - - int singles = 0; - int pairs = 0; - int higher = 0; - // count the number of sets being associated with 1, 2 or more terms - for (Integer i : m.values()) { - switch (i.intValue()) { - case 1: - ++singles; - break; - case 2: - pairs += 2; - break; - default: - ++higher; - break; - } - } - if (higher == 0 && pairs + singles <= 2) { - return RewriteStrategies.EXPENSIVE_AND; - } else { - return RewriteStrategies.CHEAP_AND; - } - } - - private CompositeItem rewriteNot(NotItem not, IndexFacts.Session session) { - Item positive = not.getItem(0); - if (positive instanceof BlockItem || positive instanceof PhraseItem) { - positive = convertSinglePhraseOrBlock(positive, session); - not.setItem(0, positive); - } else if (positive instanceof CompositeItem) { - CompositeItem c = (CompositeItem) positive; - positive = rewrite(c, session); - not.setItem(0, positive); - } - - int length = not.getItemCount(); - // no need for keeping proximity in the negative branches, so we - // convert them one by one, _and_ always uses cheap transform - for (int i = 1; i < length; ++i) { - Item exclusion = not.getItem(i); - if (exclusion instanceof BlockItem || exclusion instanceof PhraseItem) { - exclusion = convertSinglePhraseOrBlock(exclusion, session); - not.setItem(i, exclusion); - } else if (exclusion instanceof CompositeItem) { - CompositeItem c = (CompositeItem) exclusion; - switch (chooseRewriteStrategy(c, session)) { - case NONE: - c = traverse(c, session); - break; - case CHEAP_AND: - case EXPENSIVE_AND: - c = cheapTransform(c, session); - break; - default: - c = flatTransform(c, session); - break; - } - not.setItem(i, c); - } - } - return not; - } - - private Item rewrite(CompositeItem c, IndexFacts.Session session) { - if (c instanceof NotItem) { - c = rewriteNot((NotItem) c, session); - return c; - } else { - switch (chooseRewriteStrategy(c, session)) { - case NONE: - c = traverse(c, session); - break; - case CHEAP_AND: - c = cheapTransform(c, session); - break; - case EXPENSIVE_AND: - c = expensiveTransform((AndItem) c, session); - break; - case FLAT: - c = flatTransform(c, session); - break; - default: - break; - } - } - return c; - } - - private CompositeItem traverse(CompositeItem c, IndexFacts.Session session) { - int length = c.getItemCount(); - for (int i = 0; i < length; ++i) { - Item word = c.getItem(i); - if (word instanceof CompositeItem && !(word instanceof PhraseItem) && !(word instanceof BlockItem)) { - c.setItem(i, rewrite((CompositeItem) word, session)); - } - } - return c; - } - - private CompositeItem expensiveTransform(AndItem c, IndexFacts.Session session) { - int[] indices = new int[2]; - int items = 0; - int length = c.getItemCount(); - Attribute[][] names = new Attribute[2][]; - CompositeItem result = null; - for (int i = 0; i < length; ++i) { - Item word = c.getItem(i); - if (word instanceof BlockItem || word instanceof PhraseItem) { - Attribute[] attributes = getIndices((HasIndexItem) word, session); - if (attributes == null) { - continue; - } - // this throwing an out of bounds if more than two candidates is intentional - names[items] = attributes; - indices[items++] = i; - } else if (word instanceof CompositeItem) { - c.setItem(i, rewrite((CompositeItem) word, session)); - } - } - switch (items) { - case 1: - result = linearAnd(c, names[0], indices[0]); - break; - case 2: - result = quadraticAnd(c, names[0], names[1], indices[0], indices[1]); - break; - default: - // should never happen - getLogger().log( - LogLevel.WARNING, - "Unexpected number of items for mixed recall, got " + items - + ", expected 1 or 2."); - break; - } - return result; - } - - private Attribute[] getIndices(HasIndexItem block, IndexFacts.Session session) { - return session.getIndex(block.getIndexName()).getMatchGroup(); - } - - private OrItem linearAnd(AndItem c, Attribute[] names, int brancherIndex) { - OrItem or = new OrItem(); - for (int i = 0; i < names.length; ++i) { - AndItem duck = (AndItem) c.clone(); - Item b = retarget(duck.getItem(brancherIndex), names[i]); - duck.setItem(brancherIndex, b); - or.addItem(duck); - } - return or; - } - - private OrItem quadraticAnd(AndItem c, Attribute[] firstNames, Attribute[] secondNames, int firstBrancher, int secondBrancher) { - OrItem or = new OrItem(); - for (int i = 0; i < firstNames.length; ++i) { - for (int j = 0; j < secondNames.length; ++j) { - AndItem duck = (AndItem) c.clone(); - Item b = retarget(duck.getItem(firstBrancher), firstNames[i]); - duck.setItem(firstBrancher, b); - b = retarget(duck.getItem(secondBrancher), secondNames[j]); - duck.setItem(secondBrancher, b); - or.addItem(duck); - } - } - return or; - } - - private CompositeItem flatTransform(CompositeItem c, IndexFacts.Session session) { - int maxIndex = c.getItemCount() - 1; - for (int i = maxIndex; i >= 0; --i) { - Item word = c.getItem(i); - if (word instanceof BlockItem || word instanceof PhraseItem) { - Attribute[] attributes = getIndices((HasIndexItem) word, session); - if (attributes == null) { - continue; - } - c.removeItem(i); - for (Attribute name : attributes) { - Item term = word.clone(); - Item forNewIndex = retarget(term, name); - c.addItem(forNewIndex); - } - } else if (word instanceof CompositeItem) { - c.setItem(i, rewrite((CompositeItem) word, session)); - } - } - return c; - } - - private CompositeItem cheapTransform(CompositeItem c, IndexFacts.Session session) { - if (c instanceof OrItem) { - return flatTransform(c, session); - } - int length = c.getItemCount(); - for (int i = 0; i < length; ++i) { - Item j = c.getItem(i); - if (j instanceof BlockItem || j instanceof PhraseItem) { - Attribute[] attributes = getIndices((HasIndexItem) j, session); - if (attributes == null) { - continue; - } - CompositeItem or = searchAllForItem(j, attributes); - c.setItem(i, or); - } else if (j instanceof CompositeItem) { - c.setItem(i, rewrite((CompositeItem) j, session)); - } - } - return c; - } - - private OrItem searchAllForItem(Item word, Attribute[] attributes) { - OrItem or = new OrItem(); - for (Attribute name : attributes) { - Item term = word.clone(); - term = retarget(term, name); - or.addItem(term); - } - return or; - } - - private Item retarget(Item word, Attribute newIndex) { - if (word instanceof PhraseItem && !newIndex.isTokenizedContent()) { - PhraseItem asPhrase = (PhraseItem) word; - WordItem newWord = new WordItem(asPhrase.getIndexedString(), newIndex.name, false); - return newWord; - } else if (word instanceof IndexedItem) { - word.setIndexName(newIndex.name); - } else if (word instanceof CompositeItem) { - CompositeItem asComposite = (CompositeItem) word; - for (Iterator<Item> i = asComposite.getItemIterator(); i.hasNext();) { - Item segment = i.next(); - segment.setIndexName(newIndex.name); - } - } - return word; - } - - private Item convertSinglePhraseOrBlock(Item item, IndexFacts.Session session) { - Item newItem; - Attribute[] attributes = getIndices((HasIndexItem) item, session); - if (attributes == null) { - return item; - } - newItem = searchAllForItem(item, attributes); - return newItem; - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java index 28d384b0f63..61ce9d98e69 100644 --- a/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java @@ -38,21 +38,20 @@ public class BlendingSearcher extends Searcher { public static final String BLENDING = "Blending"; - private final String documentId; + private final String blendingField; @Inject public BlendingSearcher(ComponentId id, QrSearchersConfig cfg) { super(id); QrSearchersConfig.Com.Yahoo.Prelude.Searcher.BlendingSearcher s = cfg.com().yahoo().prelude().searcher().BlendingSearcher(); - documentId = s.docid().length() > 0 ? s.docid() : null; - + blendingField = s.docid().length() > 0 ? s.docid() : null; } /** * Only for legacy tests. */ - public BlendingSearcher(String blendingDocumentId) { - this.documentId = blendingDocumentId; + public BlendingSearcher(String blendingField) { + this.blendingField = blendingField; } @Override @@ -107,7 +106,7 @@ public class BlendingSearcher extends Searcher { result.hits().setOrderer(groups.get(0).getOrderer()); return result; } else { - if (documentId != null) { + if (blendingField != null) { return blendResultsUniquely(result, q, offset, hits, groups, execution); } else { return blendResultsDirectly(result, q, offset, hits, groups, execution); @@ -125,6 +124,7 @@ public class BlendingSearcher extends Searcher { } private abstract class DocumentMerger { + protected Set<String> documentsToStrip; protected Result result; protected HitGroup group; @@ -137,22 +137,22 @@ public class BlendingSearcher extends Searcher { return result; } - //Since we cannot use prelude.hit#getProperty, we'll have to improvise private String getProperty(Hit hit, String field) { + if ("[id]".equals(field)) return hit.getId().toString(); Object o = hit.getField(field); return o == null ? null : o.toString(); } protected void storeID(Hit hit, Execution execution) { - String id = getProperty(hit, documentId); + String id = getProperty(hit, blendingField); if (id != null) { documentsToStrip.add(id); } else { if (!result.isFilled(result.getQuery().getPresentation().getSummary())) { fill(result, result.getQuery().getPresentation().getSummary(), execution); - id = getProperty(hit, documentId); + id = getProperty(hit, blendingField); if (id != null) { documentsToStrip.add(id); } @@ -161,14 +161,14 @@ public class BlendingSearcher extends Searcher { } protected boolean known(HitGroup source, Hit hit, Execution execution) { - String stripID = getProperty(hit, documentId); + String stripID = getProperty(hit, blendingField); if (stripID == null) { if (!source.isFilled(result.getQuery().getPresentation().getSummary())) { Result nResult = new Result(result.getQuery()); nResult.hits().add(source); fill(nResult, nResult.getQuery().getPresentation().getSummary(), execution); - stripID = getProperty(hit, documentId); + stripID = getProperty(hit, blendingField); if (stripID == null) { return false; } diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java deleted file mode 100644 index bc3c6665ae2..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.searcher; - -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.result.Hit; -import com.yahoo.search.searchchain.Execution; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -/** - * <p>Implements a document source. You pass in a query and a Result - * set. When this Searcher is called with that query it will return - * that result set.</p> - * - * <p>This supports multi-phase search.</p> - * - * <p>To avoid having to add type information for the fields, a quck hack is used to - * support testing of attribute prefetching. - * Any field in the configured hits which has a name starting by attribute - * will be returned when attribute prefetch filling is requested.</p> - * - * @author bratseth - * @deprecated use {@link com.yahoo.search.searchchain.testutil.DocumentSourceSearcher} - */ -@SuppressWarnings({"rawtypes"}) -// TODO: Remove on Vespa 7 -@Deprecated // OK -public class DocumentSourceSearcher extends Searcher { - - // as for the SuppressWarnings annotation above, we are inside - // com.yahoo.prelude, this is old stuff, really no point firing off those - // warnings here... - - private Result defaultFilledResult; - private Map<Query, Result> completelyFilledResults = new HashMap<>(); - private Map<Query, Result> attributeFilledResults = new HashMap<>(); - private Map<Query, Result> unFilledResults = new HashMap<>(); - - /** Time (in ms) at which the index of this searcher was last modified */ - long editionTimeStamp=0; - - private int queryCount; - - public DocumentSourceSearcher() { - addDefaultResults(); - } - - /** - * Adds a result which can be returned either as empty, - * filled or attribute only filled later. - * Summary fields starting by "a" are attributes, others are not. - * - * @return true when replacing an existing <query, result> pair. - */ - public boolean addResultSet(Query query, Result fullResult) { - Result emptyResult = new Result(query.clone()); - Result attributeResult = new Result(query.clone()); - emptyResult.setTotalHitCount(fullResult.getTotalHitCount()); - attributeResult.setTotalHitCount(fullResult.getTotalHitCount()); - int counter=0; - for (Iterator i = fullResult.hits().deepIterator();i.hasNext();) { - Hit fullHit = (Hit)i.next(); - - Hit emptyHit = fullHit.clone(); - emptyHit.clearFields(); - emptyHit.setFillable(); - emptyHit.setRelevance(fullHit.getRelevance()); - - Hit attributeHit = fullHit.clone(); - removePropertiesNotStartingByA(attributeHit); - attributeHit.setFillable(); - attributeHit.setRelevance(fullHit.getRelevance()); - for (Object propertyKeyObject : fullHit.fields().keySet()) { - String propertyKey=propertyKeyObject.toString(); - if (propertyKey.startsWith("attribute")) - attributeHit.setField(propertyKey, fullHit.getField(propertyKey)); - } - if (fullHit.getField(Hit.SDDOCNAME_FIELD)!=null) - attributeHit.setField(Hit.SDDOCNAME_FIELD, fullHit.getField(Hit.SDDOCNAME_FIELD)); - - // A simple summary lookup mechanism, similar to FastSearch's - emptyHit.setField("summaryid", String.valueOf(counter)); - attributeHit.setField("summaryid", String.valueOf(counter)); - fullHit.setField("summaryid", String.valueOf(counter)); - - counter++; - emptyResult.hits().add(emptyHit); - attributeResult.hits().add(attributeHit); - } - unFilledResults.put(getQueryKeyClone(query), emptyResult); - attributeFilledResults.put(getQueryKeyClone(query), attributeResult); - if (completelyFilledResults.put(getQueryKeyClone(query), fullResult.clone()) != null) { - setEditionTimeStamp(System.currentTimeMillis()); - return true; - } - return false; - } - - /** - * Returns a query clone which has source, offset and hits set to null. This is used by access to - * the maps using the query as key to achieve lookup independent of offset/hits value - */ - private Query getQueryKeyClone(Query query) { - Query key = query.clone(); - key.setWindow(0,0); - key.getModel().setSources(""); - return key; - } - - private void removePropertiesNotStartingByA(Hit hit) { - List<String> toRemove=new java.util.ArrayList<>(); - for (Iterator i= ((Set) hit.fields().keySet()).iterator(); i.hasNext(); ) { - String key=(String)i.next(); - if (!key.startsWith("a")) - toRemove.add(key); - } - for (Iterator<String> i=toRemove.iterator(); i.hasNext(); ) { - String propertyName=i.next(); - hit.removeField(propertyName); - } - } - - private void addDefaultResults() { - Query q = new Query("?query=default"); - Result r = new Result(q); - r.hits().add(new Hit("http://default-1.html")); - r.hits().add(new Hit("http://default-2.html")); - r.hits().add(new Hit("http://default-3.html")); - r.hits().add(new Hit("http://default-4.html")); - defaultFilledResult = r; - addResultSet(q, r); - } - - public long getEditionTimeStamp(){ - long myEditionTime; - synchronized(this){ - myEditionTime=this.editionTimeStamp; - } - return myEditionTime; - } - - public void setEditionTimeStamp(long editionTime) { - synchronized(this){ - this.editionTimeStamp=editionTime; - } - } - - public Result search(com.yahoo.search.Query query, Execution execution) { - queryCount++; - Result r; - r = unFilledResults.get(getQueryKeyClone(query)); - if (r == null) { - r = defaultFilledResult.clone(); - } else { - r = r.clone(); - } - r.setQuery(query); - r.hits().trim(query.getOffset(), query.getHits()); - return r; - } - - @Override - public void fill(com.yahoo.search.Result result, String summaryClass, Execution execution) { - Result filledResult; - if ("attributeprefetch".equals(summaryClass)) - filledResult=attributeFilledResults.get(getQueryKeyClone(result.getQuery())); - else - filledResult = completelyFilledResults.get(getQueryKeyClone(result.getQuery())); - - if (filledResult == null) { - filledResult = defaultFilledResult; - } - fillHits(filledResult,result,summaryClass); - } - - private void fillHits(Result source,Result target,String summaryClass) { - for (Iterator hitsToFill= target.hits().deepIterator() ; hitsToFill.hasNext();) { - Hit hitToFill = (Hit) hitsToFill.next(); - String summaryId= (String) hitToFill.getField("summaryid"); - if (summaryId==null) continue; // Can not fill this - Hit filledHit = lookupBySummaryId(source,summaryId); - if (filledHit==null) - throw new RuntimeException("Can't fill hit with summaryid '" + summaryId + "', not present"); - - for (Iterator props= filledHit.fieldIterator();props.hasNext();) { - Map.Entry propertyEntry = (Map.Entry)props.next(); - hitToFill.setField(propertyEntry.getKey().toString(), - propertyEntry.getValue()); - } - hitToFill.setFilled(summaryClass); - } - target.analyzeHits(); - } - - private Hit lookupBySummaryId(Result result,String summaryId) { - for (Iterator i= result.hits().deepIterator(); i.hasNext(); ) { - Hit hit=(Hit)i.next(); - if (summaryId.equals(hit.getField("summaryid"))) { - return hit; - } - } - return null; - } - - /** - * Returns the number of queries made to this searcher since the last - * reset. For testing - not reliable if multiple threads makes - * queries simultaneously - */ - public int getQueryCount() { - return queryCount; - } - - public void resetQueryCount() { - queryCount=0; - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java index 5c56379efc0..d11b8d86d29 100644 --- a/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java @@ -77,10 +77,9 @@ public class JuniperSearcher extends Searcher { @Override public void fill(Result result, String summaryClass, Execution execution) { - Result workResult = result; - int worstCase = workResult.getHitCount(); + int worstCase = result.getHitCount(); List<Hit> hits = new ArrayList<>(worstCase); - for (Iterator<Hit> i = workResult.hits().deepIterator(); i.hasNext();) { + for (Iterator<Hit> i = result.hits().deepIterator(); i.hasNext();) { Hit sniffHit = i.next(); if ( ! (sniffHit instanceof FastHit)) continue; @@ -89,26 +88,26 @@ public class JuniperSearcher extends Searcher { hits.add(hit); } - execution.fill(workResult, summaryClass); - highlight(workResult.getQuery().getPresentation().getBolding(), hits.iterator(), summaryClass, + execution.fill(result, summaryClass); + highlight(result.getQuery().getPresentation().getBolding(), hits.iterator(), summaryClass, execution.context().getIndexFacts().newSession(result.getQuery())); } private void highlight(boolean bolding, Iterator<Hit> hitsToHighlight, String summaryClass, IndexFacts.Session indexFacts) { while (hitsToHighlight.hasNext()) { - Hit sniffHit = hitsToHighlight.next(); - if ( ! (sniffHit instanceof FastHit)) continue; + Hit hit = hitsToHighlight.next(); + if ( ! (hit instanceof FastHit)) continue; - FastHit hit = (FastHit) sniffHit; - if (summaryClass != null && ! hit.isFilled(summaryClass)) continue; + FastHit fastHit = (FastHit) hit; + if (summaryClass != null && ! fastHit.isFilled(summaryClass)) continue; - Object searchDefinitionField = hit.getField(MAGIC_FIELD); + Object searchDefinitionField = fastHit.getField(MAGIC_FIELD); if (searchDefinitionField == null) continue; for (Index index : indexFacts.getIndexes(searchDefinitionField.toString())) { if (index.getDynamicSummary() || index.getHighlightSummary()) { - HitField fieldValue = hit.buildHitField(index.getName(), true, true); + HitField fieldValue = fastHit.buildHitField(index.getName(), true); if (fieldValue != null) insertTags(fieldValue, bolding, index.getDynamicSummary()); } @@ -116,9 +115,9 @@ public class JuniperSearcher extends Searcher { } } - private void insertTags(HitField oldProperty, boolean bolding, boolean dynteaser) { + private void insertTags(HitField field, boolean bolding, boolean dynteaser) { boolean insideHighlight = false; - for (ListIterator<FieldPart> i = oldProperty.listIterator(); i.hasNext();) { + for (ListIterator<FieldPart> i = field.listIterator(); i.hasNext();) { FieldPart f = i.next(); if (f instanceof SeparatorFieldPart) setSeparatorString(bolding, (SeparatorFieldPart) f); @@ -138,8 +137,7 @@ public class JuniperSearcher extends Searcher { break; case RAW_SEPARATOR_CHAR: newFieldParts = initFieldParts(newFieldParts); - addSeparator(bolding, dynteaser, f, toQuote, newFieldParts, - previous, j); + addSeparator(bolding, dynteaser, f, toQuote, newFieldParts, previous, j); previous = j + 1; break; default: diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/QuerySnapshotSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/QuerySnapshotSearcher.java deleted file mode 100644 index 4edb907d337..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/searcher/QuerySnapshotSearcher.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.searcher; - -import com.yahoo.search.result.Hit; -import com.yahoo.search.result.Relevance; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.searchchain.Execution; - -/** - * Save the query in the incoming state to a meta hit in the result. - * - * @author Steinar Knutsen - * @deprecated do not use - */ -// TODO: Remove on Vespa 7 -@Deprecated // OK -public class QuerySnapshotSearcher extends Searcher { - - public Result search(Query query, Execution execution) { - Query q = query.clone(); - Result r = execution.search(query); - Hit h = new Hit("meta:querysnapshot", new Relevance(Double.POSITIVE_INFINITY)); - h.setMeta(true); - h.setField("query", q); - r.hits().add(h); - return r; - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/QueryValidatingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/QueryValidatingSearcher.java deleted file mode 100644 index fd155354d1c..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/searcher/QueryValidatingSearcher.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.searcher; - -import com.yahoo.search.result.ErrorMessage; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.searchchain.Execution; - -/** - * Ensures hits is 1000 or less and offset is 1000 or less. - * - * @author Steinar Knutsen - * @deprecated do not use - */ -// TODO: Remove on Vespa 7 -@Deprecated // OK -public class QueryValidatingSearcher extends Searcher { - - public Result search(Query query, Execution execution) { - if (query.getHits() > 1000) { - Result result = new Result(query); - ErrorMessage error - = ErrorMessage.createInvalidQueryParameter("Too many hits (more than 1000) requested."); - result.hits().addError(error); - return result; - } - if (query.getOffset() > 1000) { - Result result = new Result(query); - ErrorMessage error - = ErrorMessage.createInvalidQueryParameter("Offset too high (above 1000)."); - result.hits().addError(error); - return result; - } - return execution.search(query); - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java b/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java index 89849f98461..4d46107726e 100644 --- a/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java @@ -15,7 +15,6 @@ import com.yahoo.search.searchchain.PhaseNames; import java.util.*; -import static com.yahoo.prelude.querytransform.IndexCombinatorSearcher.MIXED_RECALL_REWRITE; import static com.yahoo.prelude.querytransform.StemmingSearcher.STEMMING; /** @@ -24,7 +23,7 @@ import static com.yahoo.prelude.querytransform.StemmingSearcher.STEMMING; * @author bratseth */ @After(PhaseNames.RAW_QUERY) -@Before({PhaseNames.TRANSFORMED_QUERY, STEMMING, MIXED_RECALL_REWRITE}) +@Before({PhaseNames.TRANSFORMED_QUERY, STEMMING}) public class SemanticSearcher extends Searcher { private static final CompoundName rulesRulebase=new CompoundName("rules.rulebase"); diff --git a/container-search/src/main/java/com/yahoo/prelude/statistics/StatisticsSearcher.java b/container-search/src/main/java/com/yahoo/prelude/statistics/StatisticsSearcher.java index beb79acb893..3606e01ffe5 100644 --- a/container-search/src/main/java/com/yahoo/prelude/statistics/StatisticsSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/statistics/StatisticsSearcher.java @@ -3,7 +3,6 @@ package com.yahoo.prelude.statistics; import com.yahoo.component.chain.dependencies.Before; import com.yahoo.concurrent.CopyOnWriteHashMap; -import com.yahoo.container.Server; import com.yahoo.container.protect.Error; import com.yahoo.jdisc.Metric; import com.yahoo.log.LogLevel; @@ -18,9 +17,7 @@ import com.yahoo.search.result.ErrorHit; import com.yahoo.search.result.ErrorMessage; import com.yahoo.search.searchchain.Execution; import com.yahoo.search.searchchain.PhaseNames; -import com.yahoo.statistics.Callback; import com.yahoo.statistics.Counter; -import com.yahoo.statistics.Handle; import com.yahoo.statistics.Value; import java.util.HashMap; diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/Context.java b/container-search/src/main/java/com/yahoo/prelude/templates/Context.java deleted file mode 100644 index 7662ca832f9..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/Context.java +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import java.util.Collection; - -import com.yahoo.text.XML; - -/** - * A set of variable bindings for template rendering - * - * @author bratseth - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public abstract class Context { - - private boolean xmlEscape = true; - - // These may be wrapped in an object if it gets unruly like this... - private String boldOpenTag; - private String boldCloseTag; - private String separatorTag; - - private boolean utf8Output = false; - - //prevent sub-classing outside of this package. - Context() {} - - // set|getXmlEscape no longer final on cause of HitContext subclassing _and_ wrapping Context - /** Sets whether this context should xml-escape returned values */ - public void setXmlEscape(boolean xmlEscape) { this.xmlEscape=xmlEscape; } - - /** Returns whether this context xml-escapes returned values. Default is true */ - public boolean getXmlEscape() { return xmlEscape; } - - /** - * Makes a <b>secondary</b> binding - * - * @return the old value bound to this key, or null it the key was previously unbound - */ - public abstract Object put(String key,Object value); - - /** - * <p>Returns a value by looking it up in the primary, - * and thereafter in secondary sources.</p> - * - * <p>If xml escaping is on and this is a string, xml attribute escaping is done - * </p> - */ - abstract public Object get(String key); - - /** - * Removes a <b>secondary</b> binding - * - * @return the removed value, or null if it wasn't bound - */ - public abstract Object remove(Object key); - - - // These three may be collapsed to one method - public void setBoldOpenTag(String boldOpenTag) { - this.boldOpenTag = boldOpenTag; - } - public void setBoldCloseTag(String boldCloseTag) { - this.boldCloseTag = boldCloseTag; - } - public void setSeparatorTag(String separatorTag) { - this.separatorTag = separatorTag; - } - - - protected Object normalizeValue(Object value) { - if (value == null) { - return ""; - } else if (xmlEscape && value instanceof String) { - return XML.xmlEscape((String) value, true, null); - } else { - return value; - } - } - - public String getBoldOpenTag() { - return boldOpenTag; - } - - public String getBoldCloseTag() { - return boldCloseTag; - } - - public String getSeparatorTag() { - return separatorTag; - } - - public abstract Collection<? extends Object> getKeys(); - - /** - * Used by the template to decide whether to use UTF-8 optimizations. - * - * @return whether the result encoding is UTF-8 - */ - public boolean isUtf8Output() { - return utf8Output; - } - - /** - * Used by the template to decide whether to use UTF-8 optimizations. - * TODO: TVT: Make this package private again - * @param utf8Output whether the output encoding is UTF-8 - */ - public void setUtf8Output(boolean utf8Output) { - this.utf8Output = utf8Output; - } - -} 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 deleted file mode 100644 index 4d6406fe00d..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/DefaultTemplateSet.java +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -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> - * - * <p>This can be extended to create custom programmatic templates. - * Create a subclass which has static inner classes extending DefaultTemplate for the templates - * you wish to override and call the set method for those templates in the subclass template set - * constructor. Some of the default templates contained utility functions, and can be overridden - * in place of DefaultTemplate to gain access to these. See TiledTemplateSet for an example.</p> - * - * @author bratseth - * @deprecated use JsonRenderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public class DefaultTemplateSet extends UserTemplate<XMLWriter> { - - private static final Utf8String RESULT = new Utf8String("result"); - private static final Utf8String GROUP = new Utf8String("group"); - private static final Utf8String ID = new Utf8String("id"); - private static final Utf8String FIELD = new Utf8String("field"); - private static final Utf8String HIT = new Utf8String("hit"); - private static final Utf8String ERROR = new Utf8String("error"); - private static final Utf8String TOTAL_HIT_COUNT = new Utf8String("total-hit-count"); - private static final Utf8String QUERY_TIME = new Utf8String("querytime"); - private static final Utf8String SUMMARY_FETCH_TIME = new Utf8String("summaryfetchtime"); - private static final Utf8String SEARCH_TIME = new Utf8String("searchtime"); - private static final Utf8String NAME = new Utf8String("name"); - private static final Utf8String CODE = new Utf8String("code"); - private static final Utf8String COVERAGE_DOCS = new Utf8String("coverage-docs"); - private static final Utf8String COVERAGE_NODES = new Utf8String("coverage-nodes"); - private static final Utf8String COVERAGE_FULL = new Utf8String("coverage-full"); - private static final Utf8String COVERAGE = new Utf8String("coverage"); - private static final Utf8String RESULTS_FULL = new Utf8String("results-full"); - private static final Utf8String RESULTS = new Utf8String("results"); - private static final Utf8String TYPE = new Utf8String("type"); - private static final Utf8String RELEVANCY = new Utf8String("relevancy"); - private static final Utf8String SOURCE = new Utf8String("source"); - - private final CopyOnWriteHashMap<String, Utf8String> fieldNameMap = new CopyOnWriteHashMap<>(); - - - /** - * Create a template set with a name. This will be initialized with the default templates - - * use the set methods from the subclass constructor to override any of these with other template classes. - */ - protected DefaultTemplateSet(String name) { - super(name, - DEFAULT_MIMETYPE, - DEFAULT_ENCODING - ); - } - - public DefaultTemplateSet() { - this("default"); - } - - /** Uses an XML writer in this template */ - @Override - public XMLWriter wrapWriter(Writer writer) { - return XMLWriter.from(writer, 10, -1); - } - - @Override - public void header(Context context, XMLWriter writer) throws IOException { - Result result=(Result)context.get("result"); - // TODO: move setting this to Result - context.setUtf8Output("utf-8".equalsIgnoreCase(getRequestedEncoding(result.getQuery()))); - writer.xmlHeader(getRequestedEncoding(result.getQuery())); - writer.openTag(RESULT).attribute(TOTAL_HIT_COUNT,String.valueOf(result.getTotalHitCount())); - renderCoverageAttributes(result.getCoverage(false), writer); - renderTime(writer, result); - writer.closeStartTag(); - } - - private void renderTime(final XMLWriter writer, final Result result) { - if (!result.getQuery().getPresentation().getTiming()) { - return; - } - - final String threeDecimals = "%.3f"; - final double milli = .001d; - final long now = System.currentTimeMillis(); - final long searchTime = now - result.getElapsedTime().first(); - final double searchSeconds = ((double) searchTime) * milli; - - if (result.getElapsedTime().firstFill() != 0L) { - final long queryTime = result.getElapsedTime().weightedSearchTime(); - final long summaryFetchTime = result.getElapsedTime().weightedFillTime(); - final double querySeconds = ((double) queryTime) * milli; - final double summarySeconds = ((double) summaryFetchTime) * milli; - writer.attribute(QUERY_TIME, String.format(threeDecimals, querySeconds)); - writer.attribute(SUMMARY_FETCH_TIME, String.format(threeDecimals, summarySeconds)); - } - writer.attribute(SEARCH_TIME, String.format(threeDecimals, searchSeconds)); - } - - @Override - public void footer(Context context, XMLWriter writer) throws IOException { - writer.closeTag(); - } - - @Override - /** - * Renders the header of a hit.<br/> - * Post-condition: The hit tag is open in this XML writer - */ - public void hit(Context context, XMLWriter writer) throws IOException { - Hit hit=(Hit)context.get("hit"); - - if (hit instanceof HitGroup) { - renderHitGroup((HitGroup) hit, context, writer); - } else { - writer.openTag(HIT); - renderHitAttributes(hit,writer); - writer.closeStartTag(); - renderHitFields(context, hit, writer); - } - } - - - @Override - /** - * Renders the footer of a hit. - * - * Pre-condition: The hit tag is open in this XML writer.<br/> - * Post-condition: The hit tag is closed - */ - public void hitFooter(Context context, XMLWriter writer) throws IOException { - writer.closeTag(); - } - - @Override - public void error(Context context, XMLWriter writer) { - ErrorMessage error=((Result)context.get("result")).hits().getError(); - writer.openTag(ERROR).attribute(CODE,error.getCode()).content(error.getMessage(),false).closeTag(); - } - - @Override - public void noHits(Context context, XMLWriter writer) { - // no hits, do nothing :) - } - - protected static void renderCoverageAttributes(Coverage coverage, XMLWriter writer) { - if (coverage == null) return; - writer.attribute(COVERAGE_DOCS,coverage.getDocs()); - writer.attribute(COVERAGE_NODES,coverage.getNodes()); - writer.attribute(COVERAGE_FULL,coverage.getFull()); - writer.attribute(COVERAGE,coverage.getResultPercentage()); - writer.attribute(RESULTS_FULL,coverage.getFullResultSets()); - writer.attribute(RESULTS,coverage.getResultSets()); - } - - /** - * Writes a hit's default attributes like 'type', 'source', 'relevancy'. - */ - 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()); - } - writer.attribute(SOURCE, hit.getSource()); - } - - /** Opens (but does not close) the group hit tag */ - protected void renderHitGroup(HitGroup hit, Context context, XMLWriter writer) throws IOException { - if (HitRenderer.renderHeader(hit, writer)) { - // empty - } else if (hit.types().contains("grouphit")) { - // TODO Keep this? - renderHitGroupOfTypeGroupHit(context, hit, writer); - } else { - renderGroup(hit, writer); - } - } - - /** - * Renders a hit group. - */ - protected void renderGroup(HitGroup hit, XMLWriter writer) throws IOException { - writer.openTag(GROUP); - renderHitAttributes(hit, writer); - writer.closeStartTag(); - } - - // Can't name this renderGroupHit as GroupHit is a class having nothing to do with HitGroup. - // Confused yet? Good! - protected void renderHitGroupOfTypeGroupHit(Context context, HitGroup hit, XMLWriter writer) throws IOException { - writer.openTag(HIT); - renderHitAttributes(hit, writer); - renderId(hit.getId(), writer); - writer.closeStartTag(); - } - - - protected void renderId(URI uri, XMLWriter writer) { - if (uri != null) { - writer.openTag(ID).content(uri.stringValue(),false).closeTag(); - } - } - - /** - * Renders all fields of a hit. - * Simply calls {@link #renderField(Context, Hit, java.util.Map.Entry, XMLWriter)} for every field. - */ - protected void renderHitFields(Context context, Hit hit, XMLWriter writer) throws IOException { - renderSyntheticRelevancyField(hit, writer); - for (Iterator<Map.Entry<String, Object>> it = hit.fieldIterator(); it.hasNext(); ) { - renderField(context, hit, it.next(), writer); - } - } - - private void renderSyntheticRelevancyField(Hit hit, XMLWriter writer) { - final String relevancyFieldName = "relevancy"; - final Relevance relevance = hit.getRelevance(); - - if (shouldRenderField(hit, relevancyFieldName) && relevance != null) { - renderSimpleField(relevancyFieldName, relevance, writer); - } - } - - protected void renderField(Context context, Hit hit, Map.Entry<String, Object> entry, XMLWriter writer) throws IOException { - String fieldName = entry.getKey(); - - if (!shouldRenderField(hit, fieldName)) return; - if (fieldName.startsWith("$")) return; // Don't render fields that start with $ // TODO: Move to should render - - writeOpenFieldElement(fieldName, writer); - renderFieldContent(context, hit, fieldName, writer); - writeCloseFieldElement(writer); - } - - private void writeOpenFieldElement(String fieldName, XMLWriter writer) { - Utf8String utf8 = fieldNameMap.get(fieldName); - if (utf8 == null) { - utf8 = new Utf8String(fieldName); - fieldNameMap.put(fieldName, utf8); - } - writer.openTag(FIELD).attribute(NAME, utf8); - writer.closeStartTag(); - } - - private void writeCloseFieldElement(XMLWriter writer) { - writer.closeTag(); - } - - protected void renderFieldContent(Context context, Hit hit, String name, XMLWriter writer) { - 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) { - writeOpenFieldElement(fieldName, writer); - writer.content(fieldValue.toString(),false); - writeCloseFieldElement(writer); - } - - /** Returns whether a field should be rendered. This default implementation always returns true */ - protected boolean shouldRenderField(Hit hit, String fieldName) { - // skip depending on hit type - return true; - } - - - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/FormattingOptions.java b/container-search/src/main/java/com/yahoo/prelude/templates/FormattingOptions.java deleted file mode 100644 index 1f724aba112..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/FormattingOptions.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -/** - * Defines formatting options used with special kinds of hits. - * - * @author laboisse - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public class FormattingOptions { - - public static final String DEFAULT_TYPE_ATTRIBUTE_NAME = "type"; - - /** - * A structure that defines the tag name and attribute name for a field - * that sould be formatted as a field with a subtype. - * @author laboisse - * - */ - static class SubtypeField { - String tagName; - String attributeName; - String attributeValue; - } - - static class SubtypeFieldWithPrefix extends SubtypeField { - - /* Note: attributeValue should always be null for instances of this class */ - - int prefixLength; - } - - private Map<String, String> fieldsAsAttributes = new LinkedHashMap<>(); - - private Map<String, SubtypeField> fieldsWithSubtypes = new LinkedHashMap<>(); - private Map<String, SubtypeFieldWithPrefix> prefixedFieldsWithSubtypes = new LinkedHashMap<>(); - - private Set<String> fieldsNotRendered = new LinkedHashSet<>(); - private Set<String> fieldsRendered = new LinkedHashSet<>(); - - /** - * Tells to format a field as an attribute of the hit's tag. - * - * For instance, field 'query-latency' could be rendered as an attribute 'latency' by - * invoking {@code formatFieldAsAttribute("query-latency", "latency")}. - * - * Output would be: - * <pre> - * <hit latency="100"></hit> - * </pre> - * instead of: - * <pre> - * <hit><latency>100</latency></hit> - * </pre> - */ - public void formatFieldAsAttribute(String fieldName, String attributeName) { - fieldsAsAttributes.put(fieldName, attributeName); - } - - public Set<Map.Entry<String, String>> fieldsAsAttributes() { - return Collections.unmodifiableSet(this.fieldsAsAttributes.entrySet()); - } - - public String getAttributeName(String fieldName) { - return this.fieldsAsAttributes.get(fieldName); - } - - /** - * Tells to format a field using a subtype. A subtype is used when there is kind of a grouping - * for a set of fields. - * - * For instance, fields 'latency-connect', 'latency-finish' all belong to the same 'latency' logical group. - * So invoking {@code formatFieldWithSubtype("latency-connect", "latency", "type", "connect"}, - * {@code formatFieldWithSubtype("latency-finish", "latency", "type", "connect"} and so on, - * allows to have a common 'latency' tag name for all fields of the same kind. - * Note that it does no collapsing on tags. - * - * Output would be: - * <pre> - * <latency type="connect">50</latency> - * <latency type="finish">250</latency> - * </pre> - * Instead of: - * <pre> - * <hit> - * <latency-connect>50</latency-connect> - * <latency-finish>50</latency-finish> - * </pre> - */ - public void formatFieldWithSubtype(String fieldName, String tagName, String typeAttributeName, String typeAttributeValue) { - SubtypeField names = new SubtypeField(); - names.attributeName = typeAttributeName; - names.attributeValue = typeAttributeValue; - names.tagName = tagName; - fieldsWithSubtypes.put(fieldName, names); - } - - public SubtypeField getSubtype(String fieldName) { - return this.fieldsWithSubtypes.get(fieldName); - } - - /** - * Same as {@link #formatFieldWithSubtype(String, String, String, String)} except that fields - * are selected based on the beginning of their name and the type attribute value is deduced - * from the rest of their name. So this may select many fields instead of only one. - * Invoking {@code formatFieldWithSubtype("latency-", "latency", "type")} only once allows to have a common 'latency' - * tag name for all fields that start with 'latency-'. Type attribute value will be 'start' for field 'latency-start'. - * Note that it does no collapsing on tags. - * - * This is mostly used when you don't know all field names ahead. - * - * Output would be: - * <pre> - * <latency type="connect">50</latency> - * <latency type="finish">250</latency> - * </pre> - * Instead of: - * <pre> - * <hit> - * <latency-connect>50</latency-connect> - * <latency-finish>50</latency-finish> - * </pre> - * - * Note: don't use this with prefixes that start with a common substring (e.g. 'http', 'http_proxy'), I can tell you it just won't work. - */ - public void formatFieldWithSubtype(String fieldNamePrefix, String tagName, String typeAttributeName) { - SubtypeFieldWithPrefix names = new SubtypeFieldWithPrefix(); - names.attributeName = typeAttributeName; - names.tagName = tagName; - names.prefixLength = fieldNamePrefix.length(); - prefixedFieldsWithSubtypes.put(fieldNamePrefix, names); - } - - public SubtypeFieldWithPrefix getSubtypeWithPrefix(String fieldName) { - for(Map.Entry<String, SubtypeFieldWithPrefix> e : this.prefixedFieldsWithSubtypes.entrySet()) { - if(fieldName.startsWith(e.getKey())) - return e.getValue(); - } - return null; - } - - /** - * Tells whether a field should be rendered. - * - * @see #setFieldNotToRender(String) - * @see #setFieldToRender(String) - */ - public boolean shouldRenderField(String fieldName) { - if(fieldName == null) - return false; - if (fieldName.startsWith("$")) { - return false; - } - if(!this.fieldsRendered.isEmpty()) - return this.fieldsRendered.contains(fieldName); - return !this.fieldsNotRendered.contains(fieldName); - } - - /** - * Tells a field should be rendered. - * - * <p> - * Note: if at least one field is set to render, then only - * these fields should be rendered. Use {@link #setFieldNotToRender(String)} - * to only exclude specific fields. - */ - public void setFieldToRender(String fieldName) { - this.fieldsRendered.add(fieldName); - } - - /** - * Tells a field should not be rendered. - * - * <p> - * Note: all other fields should be rendered. Use {@link #setFieldToRender(String)} - * to only include specific fields. - */ - public void setFieldNotToRender(String fieldName) { - this.fieldsNotRendered.add(fieldName); - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/GenericTemplateSet.java b/container-search/src/main/java/com/yahoo/prelude/templates/GenericTemplateSet.java deleted file mode 100644 index 95875d0dd1f..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/GenericTemplateSet.java +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.protect.Validator; -import com.yahoo.search.Query; - -import java.io.Writer; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Properties; - -/** - * Superclass of a set of templates for rendering (serializing) results - * - * @deprecated use a renderer instead - */ -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public class GenericTemplateSet { - - public static final String DEFAULT_MIMETYPE = "text/xml"; - public static final String DEFAULT_ENCODING = "utf-8"; - - /** Templates */ - private HashMap<String, Template<? extends Writer>> templates; - - /** The text MIME subtype this template returns, xml, plain or html */ - private String mimeType; - - /** The charset encoding this template should have */ - private String encoding; - - private String boldOpenTag = null; - private String boldCloseTag = null; - private String separatorTag = null; - - /** - * Document summary class for this template - */ - private String summaryClass = null; - - /** - * The unique name of this template set - */ - private final String name; - - /** - * Creates a template set containing no templates - */ - public GenericTemplateSet(String name, String mimeType, String encoding) { - this.mimeType = mimeType; - this.encoding = encoding; - this.name = name; - - templates = new LinkedHashMap<>(); - } - - - public String getName() { - return name; - } - - /** - * Returns the text MIME - */ - public String getMimeType() { return mimeType; } - - /** - * Returns the text encoding - */ - public String getEncoding() { return encoding; } - - /** Returns the encoding of the query, or the encoding given by the template if none is set */ - public final String getRequestedEncoding(Query query) { - String encoding = query.getModel().getEncoding(); - if (encoding != null) return encoding; - return getEncoding(); - } - - /** - * Returns the selected template - * - * @return the template to use, never null - */ - public Template<? extends Writer> getTemplate(String templateName) { - return templates.get(templateName); - } - - /** - * Sets the selected template - * - * @throws NullPointerException if the given template is null - */ - public void setTemplate(String templateName, Template<? extends Writer> template) { - templates.put(templateName,template); - } - - /** - * Sets the selected template - * - * @throws NullPointerException if the given template is null - */ - public void setTemplateNotNull(String templateName, Template<? extends Writer> template) { - Validator.ensureNotNull("Template "+templateName,template); - templates.put(templateName,template); - } - - - /** - * Sets the highligting marks for this template - * - * @param start the highlingting start mark - * @param end the highlingting end mark - * @param sep the highlingting separator mark - */ - public void setHighlightTags(String start, String end, String sep) { - boldOpenTag = start; - boldCloseTag = end; - separatorTag = sep; - } - - // may return null - public String getBoldOpenTag() { - return boldOpenTag; - } - - // may return null - public String getBoldCloseTag() { - return boldCloseTag; - } - - // may return null - public String getSeparatorTag() { - return separatorTag; - } - - - /** - * Set the default summary class to use with this template. - */ - public void setSummaryClass(String summaryClass) { - this.summaryClass = summaryClass; - } - - /** - * Type safe accessor to get the default document summary class for this - * template set. This is also here to insulate the rest of the code - * against changes in the naming of the properties in the property file. - */ - public String getSummaryClass() { - if (summaryClass != null && ! summaryClass.isEmpty()) { - return summaryClass; - } else { - return null; - } - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/HitContext.java b/container-search/src/main/java/com/yahoo/prelude/templates/HitContext.java deleted file mode 100644 index 5ef28d6f6c6..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/HitContext.java +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.prelude.hitfield.HitField; -import com.yahoo.prelude.hitfield.JSONString; -import com.yahoo.prelude.hitfield.XMLString; -import com.yahoo.search.result.Hit; -import com.yahoo.search.result.StructuredData; -import com.yahoo.text.XML; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -/** - * A context providing all the fields of a hit, and falls back to MapContext behavior for all other keys. - * - * @author Tony Vaagenes - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public class HitContext extends Context { - - private final Hit hit; - private final Context fallbackContext; - - public HitContext(Hit hit, Context fallbackContext) { - this.hit = hit; - this.fallbackContext = fallbackContext; - } - - @Override - public Object put(String key, Object value) { - return fallbackContext.put(key, value); - } - - @Override - public Object get(String key) { - Object value = normalizedHitProperty(key); - return value != null ? - value : - fallbackContext.get(key); - } - - @Override - public Object remove(Object key) { - return fallbackContext.remove(key); - } - - @Override - public Collection<? extends Object> getKeys() { - Set<Object> keys = new HashSet<>(fallbackContext.getKeys()); - keys.addAll(hit.fieldKeys()); - return keys; - } - - @Override - public void setBoldOpenTag(String boldOpenTag) { - fallbackContext.setBoldOpenTag(boldOpenTag); - } - - @Override - public void setBoldCloseTag(String boldCloseTag) { - fallbackContext.setBoldCloseTag(boldCloseTag); - } - - @Override - public void setSeparatorTag(String separatorTag) { - fallbackContext.setSeparatorTag(separatorTag); - } - - @Override - public String getBoldOpenTag() { - return fallbackContext.getBoldOpenTag(); - } - - @Override - public String getBoldCloseTag() { - return fallbackContext.getBoldCloseTag(); - } - - @Override - public String getSeparatorTag() { - return fallbackContext.getSeparatorTag(); - } - - @Override - //TVT: TODO: Make this package private again. - public boolean isUtf8Output() { - return fallbackContext.isUtf8Output(); - } - - @Override - //TODO: TVT: make this package private again - public void setUtf8Output(boolean utf8Output) { - fallbackContext.setUtf8Output(utf8Output); - } - - @Override - public void setXmlEscape(boolean xmlEscape) { - fallbackContext.setXmlEscape(xmlEscape); - } - - @Override - public boolean getXmlEscape() { - return fallbackContext.getXmlEscape(); - } - - @Override - protected Object normalizeValue(Object value) { - return fallbackContext.normalizeValue(value); - } - - private Object normalizedHitProperty(String key) { - Object value = hit.getField(key); - return value == null ? - null : - normalizeHitFieldValue(value); - } - - private Object normalizeHitFieldValue(Object value) { - if (value instanceof HitField) { - HitField hf = (HitField) value; - if (getXmlEscape()) { - return hf.quotedContent(getBoldOpenTag(), - getBoldCloseTag(), - getSeparatorTag(), - true); - } else { - return hf.getContent(getBoldOpenTag(), - getBoldCloseTag(), - getSeparatorTag()); - } - } else if (value instanceof StructuredData) { - return value.toString(); - } else if (value instanceof XMLString || value instanceof JSONString) { - return value.toString(); - } else if (getXmlEscape()) { - return XML.xmlEscape(value.toString(), true, null); - } else { - return value.toString(); - } - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/LogExceptionUserTemplateDelegator.java b/container-search/src/main/java/com/yahoo/prelude/templates/LogExceptionUserTemplateDelegator.java deleted file mode 100644 index 7696790897e..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/LogExceptionUserTemplateDelegator.java +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.log.LogLevel; -import com.yahoo.yolean.Exceptions; - -import java.io.IOException; -import java.io.Writer; -import java.util.Properties; -import java.util.logging.Logger; - -/** - * Delegates to another UserTemplate, but handles any exceptions(except IOException) by logging them. - * - * @author Tony Vaagenes - * @deprecated use a renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public class LogExceptionUserTemplateDelegator<T extends Writer> extends UserTemplate<T> { - - private static Logger log = Logger.getLogger(LogExceptionUserTemplateDelegator.class.getName()); - private final UserTemplate<T> delegate; - - public LogExceptionUserTemplateDelegator(UserTemplate<T> delegate) { - super(LogExceptionUserTemplateDelegator.class.getSimpleName()); - this.delegate = delegate; - } - - @Override - public Context createContext() { - return delegate.createContext(); - } - - @Override - public T wrapWriter(Writer writer) { - return delegate.wrapWriter(writer); - } - - @Override - public boolean isDefaultTemplateSet() { - return delegate.isDefaultTemplateSet(); - } - - @Override - public String getSummaryClass() { - return delegate.getSummaryClass(); - } - - @Override - public String getBoldOpenTag() { - return delegate.getBoldOpenTag(); - } - - @Override - public String getBoldCloseTag() { - return delegate.getBoldCloseTag(); - } - - @Override - public String getSeparatorTag() { - return delegate.getSeparatorTag(); - } - - @Override - public void setSummaryClass(String summaryClass) { - delegate.setSummaryClass(summaryClass); - } - - @Override - public void setHighlightTags(String start, String end, String sep) { - delegate.setHighlightTags(start, end, sep); - } - - @Override - public String getName() { - return delegate.getName(); - } - - @Override - public String getMimeType() { - return delegate.getMimeType(); - } - - @Override - public String getEncoding() { - return delegate.getEncoding(); - } - - @Override - public Template<T> getTemplate(String templateName) { - throw new UnsupportedOperationException(); - } - - @Override - public void setTemplate(String templateName, Template<? extends Writer> template) { - throw new UnsupportedOperationException(); - } - - @Override - public void setTemplateNotNull(String templateName, Template<? extends Writer> template) { - throw new UnsupportedOperationException(); - } - - /*** Template - - @Override - public void <methodName>(Context context, T writer) throws IOException { - try { - delegate.<methodName>(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - ***/ - - /*** Begin expanded template for - header, footer, hit, hitFooter, error, noHits, queryContext, - Thanks java, for giving me the opportunely to use copy-paste ***/ - - - @Override - public void header(Context context, T writer) throws IOException { - try { - delegate.header(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - @Override - public void footer(Context context, T writer) throws IOException { - try { - delegate.footer(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - @Override - public void hit(Context context, T writer) throws IOException { - try { - delegate.hit(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - @Override - public void hitFooter(Context context, T writer) throws IOException { - try { - delegate.hitFooter(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - @Override - public void error(Context context, T writer) throws IOException { - try { - delegate.error(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - @Override - public void noHits(Context context, T writer) throws IOException { - try { - delegate.noHits(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - @Override - public void queryContext(Context context, T writer) throws IOException { - try { - delegate.queryContext(context, writer); - } catch (Exception e) { - handleException(e); - } - } - - /*** End expanded template. ***/ - - private void handleException(Exception e) throws IOException { - if (e instanceof IOException) { - throw (IOException) e; - } else { - log.log(LogLevel.WARNING, "Exception thrown in " + getName() - + ": " + Exceptions.toMessageString(e), e); - } - } - - UserTemplate<T> getDelegate() { - return delegate; - } -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/MapContext.java b/container-search/src/main/java/com/yahoo/prelude/templates/MapContext.java deleted file mode 100644 index c08c9701741..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/MapContext.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * A context having a map as secondary storage - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -public class MapContext extends Context { - - private Map<String, Object> map = new LinkedHashMap<>(); - - @Override - public Object get(String key) { - return normalizeValue(map.get(key)); - } - - public Object put(String name, Object value) { - return map.put(name, value); - } - - public Object remove(Object name) { - return map.remove(name); - } - - @Override - public Collection<? extends Object> getKeys() { - return map.keySet(); - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/PageTemplateSet.java b/container-search/src/main/java/com/yahoo/prelude/templates/PageTemplateSet.java deleted file mode 100644 index cac06011679..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/PageTemplateSet.java +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.search.Result; -import com.yahoo.search.result.Hit; -import com.yahoo.search.result.HitGroup; -import com.yahoo.text.XMLWriter; - -import java.io.IOException; -import java.io.Writer; - -/** - * A template implementing the 'page' format. - * This is a variant of the tiled template set - see that class for details. - * - * @author bratseth - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK -public class PageTemplateSet extends TiledTemplateSet { - - public PageTemplateSet() { - super("page"); - } - - @Override - /** Uses an XML writer in this */ - public XMLWriter wrapWriter(Writer writer) { return new XMLWriter(super.wrapWriter(writer)); } - - @Override - public void header(Context context,XMLWriter writer) throws IOException { - Result result=(Result)context.get("result"); - writer.xmlHeader(getRequestedEncoding(result.getQuery())); - writer.openTag("page").attribute("version","1.0").attribute("layout",result.hits().getField("layout")); - renderCoverageAttributes(result.getCoverage(false), writer); - writer.closeStartTag(); - renderSectionContent(result.hits(),writer); - } - - @Override - public void footer(Context context,XMLWriter writer) throws IOException { - if (writer.isIn("content")) - writer.closeTag(); - super.footer(context,writer); - } - - @Override - protected void renderSection(HitGroup hit, XMLWriter writer) throws IOException { - writer.openTag("section"); - writer.attribute("id",hit.getDisplayId()); - writer.attribute("layout",hit.getField("layout")); - writer.attribute("region",hit.getField("region")); - writer.closeStartTag(); - renderSectionContent(hit,writer); - } - - @Override - public void hit(Context context, XMLWriter writer) throws IOException { - Hit hit = (Hit) context.get("hit"); - if (!hit.isMeta() && !writer.isIn("content")) - writer.openTag("content"); - super.hit(context,writer); - } - - @Override - public void hitFooter(Context context, XMLWriter writer) throws IOException { - if (writer.isIn("content")) - writer.closeTag(); - super.hitFooter(context, writer); - } - - public String toString() { return "page template"; } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/SearchRendererAdaptor.java b/container-search/src/main/java/com/yahoo/prelude/templates/SearchRendererAdaptor.java deleted file mode 100644 index 467cd615ebd..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/SearchRendererAdaptor.java +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.prelude.fastsearch.GroupingListHit; -import com.yahoo.search.Result; -import com.yahoo.search.query.context.QueryContext; -import com.yahoo.search.rendering.Renderer; -import com.yahoo.search.result.*; -import com.yahoo.search.result.ErrorHit; -import com.yahoo.processing.request.ErrorMessage; -import com.yahoo.search.result.Hit; -import com.yahoo.text.XMLWriter; - -import java.io.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -/** - * Renders a search result using the old templates API. - * - * @author Tony Vaagenes - * @deprecated do not use - */ -@SuppressWarnings({ "rawtypes", "deprecation", "unchecked" }) -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -// TODO: Remove on Vespa 7 -public final class SearchRendererAdaptor extends Renderer { - - private final LogExceptionUserTemplateDelegator templates; - - //Per instance members, must be created at rendering time, not construction time due to cloning. - private Context context; - - public SearchRendererAdaptor(UserTemplate userTemplate) { - templates = new LogExceptionUserTemplateDelegator(userTemplate); - } - - @Override - public void init() { - super.init(); - context = templates.createContext(); - } - - /** A legacy test utility - do not use. */ - public static void callRender(OutputStream stream, Result result) throws IOException { - Renderer rendererAdaptor = new SearchRendererAdaptor(result.getTemplating().getTemplates()); - rendererAdaptor.init(); - result.getTemplating().setRenderer(rendererAdaptor); - rendererAdaptor.render(stream, result, result.getQuery().getModel().getExecution(), result.getQuery()); - } - - @Override - public String getEncoding() { - return templates.getEncoding(); - } - - @Override - public String getMimeType() { - return templates.getMimeType(); - } - - @Override - public String getDefaultSummaryClass() { - return templates.getSummaryClass(); - } - - /** - * Renders this result - */ - public void render(Writer writer, Result result) throws java.io.IOException { - Writer wrappedWriter = wrapWriter(writer); - - beginResult(wrappedWriter, result); - - if (result.hits().getError() != null || result.hits().getQuery().errors().size() > 0) { - error(wrappedWriter, Collections.unmodifiableCollection( - all(result.hits().getQuery().errors(), result.hits().getError()))); - } - - if (result.getConcreteHitCount() == 0) { - emptyResult(wrappedWriter, result); - } - - if (result.getContext(false) != null) { - queryContext(wrappedWriter, result.getContext(false)); - } - - renderHitGroup(wrappedWriter, result.hits(), result.hits().getQuery().getOffset() + 1); - - endResult(wrappedWriter, result); - } - - - private <T> Collection<T> all(Collection<T> collection, T extra) { - Collection<T> result = new ArrayList<>(collection); - result.add(extra); - return result; - } - - - public Writer wrapWriter(Writer writer) { - return templates.wrapWriter(writer); - } - - - public void beginResult(Writer writer, Result result) throws IOException { - context.put("context", context); - context.put("result", result); - context.setBoldOpenTag(templates.getBoldOpenTag()); - context.setBoldCloseTag(templates.getBoldCloseTag()); - context.setSeparatorTag(templates.getSeparatorTag()); - - templates.header(context, writer); - } - - public void endResult(Writer writer, Result result) throws IOException { - templates.footer(context, writer); - } - - public void error(Writer writer, Collection<ErrorMessage> errorMessages) throws IOException { - templates.error(context, writer); - } - - - public void emptyResult(Writer writer, Result result) throws IOException { - templates.noHits(context, writer); - } - - public void queryContext(Writer writer, QueryContext queryContext) throws IOException { - templates.queryContext(context, writer); - } - - private void renderHitGroup(Writer writer, HitGroup hitGroup, int hitnumber) - throws IOException { - boolean defaultTemplate = templates.isDefaultTemplateSet(); - for (Hit hit : hitGroup.asList()) { - if (!defaultTemplate && hit instanceof ErrorHit) continue; // TODO: Stop doing this - - renderHit(writer, hit, hitnumber); - if (!hit.isAuxiliary()) - hitnumber++; - } - } - - - /** - * Renders this hit as xml. The default implementation will call the simpleRender() - * hook. If it returns true, nothing more is done, otherwise the - * given template set will be used for rendering. - * - * - * @param writer the writer to append this hit to - * @throws java.io.IOException if rendering fails - */ - public void renderHit(Writer writer, Hit hit, int hitno) throws IOException { - renderRegularHit(writer, hit, hitno); - } - - private void renderRegularHit(Writer writer, Hit hit, int hitno) throws IOException { - boolean renderedSimple = simpleRenderHit(writer, hit); - - if (renderedSimple) { - return; - } - - HitContext hitContext = new HitContext(hit, context); - hitContext.put("hit", hit); - hitContext.put("hitno", Integer.valueOf(hitno)); - hitContext.put("relevancy",hit.getRelevance()); - templates.hit(hitContext, writer); - - if (hit instanceof HitGroup) - renderHitGroup(writer, (HitGroup) hit, hitno); - - // Put these back - may have been changed by nested rendering - hitContext.put("hit", hit); - hitContext.put("hitno", Integer.valueOf(hitno)); - templates.hitFooter(hitContext, writer); - - - hitContext.remove("hit"); - hitContext.remove("hitno"); - } - - private boolean simpleRenderHit(Writer writer, Hit hit) throws IOException { - if (hit instanceof DefaultErrorHit) { - return simpleRenderDefaultErrorHit(writer, (DefaultErrorHit) hit); - } else if (hit instanceof GroupingListHit) { - return true; - } else { - return false; - } - } - - public static boolean simpleRenderDefaultErrorHit(Writer writer, ErrorHit defaultErrorHit) throws IOException { - XMLWriter xmlWriter=(writer instanceof XMLWriter) ? (XMLWriter)writer : new XMLWriter(writer,10,-1); - xmlWriter.openTag("errordetails"); - for (Iterator i = defaultErrorHit.errorIterator(); i.hasNext();) { - ErrorMessage error = (ErrorMessage) i.next(); - renderMessageDefaultErrorHit(xmlWriter, error); - } - xmlWriter.closeTag(); - return true; - } - - public static void renderMessageDefaultErrorHit(XMLWriter writer, ErrorMessage error) throws IOException { - writer.openTag("error"); - if (error instanceof com.yahoo.search.result.ErrorMessage) - writer.attribute("source",((com.yahoo.search.result.ErrorMessage)error).getSource()); - writer.attribute("error",error.getMessage()); - writer.attribute("code",Integer.toString(error.getCode())); - writer.content(error.getDetailedMessage(),false); - if (error.getCause()!=null) { - writer.openTag("cause"); - writer.content("\n",true); - StringWriter stackTrace=new StringWriter(); - error.getCause().printStackTrace(new PrintWriter(stackTrace)); - writer.content(stackTrace.toString(),true); - writer.closeTag(); - } - writer.closeTag(); - } - - /** - * Renders this hit as XML, disregarding the given template. - * The main error will be rendered first, the all the following errors. - */ - public boolean simpleRenderErrorHit(Writer writer, com.yahoo.search.result.ErrorHit errorHit) throws IOException { - XMLWriter xmlWriter=(writer instanceof XMLWriter) ? (XMLWriter)writer : new XMLWriter(writer,10,-1); - xmlWriter.openTag("errordetails"); - for (Iterator i = errorHit.errorIterator(); i.hasNext();) { - ErrorMessage error = (ErrorMessage) i.next(); - rendererErrorHitMessageMessage(xmlWriter, errorHit, error); - } - xmlWriter.closeTag(); - return true; - } - - public static void rendererErrorHitMessageMessage(XMLWriter writer, com.yahoo.search.result.ErrorHit errorHit, ErrorMessage error) throws IOException { - writer.openTag("error"); - if (errorHit instanceof Hit) { - writer.attribute("source", ((Hit) errorHit).getSource()); - } - writer.attribute("error",error.getMessage()); - writer.attribute("code",Integer.toString(error.getCode())); - writer.content(error.getDetailedMessage(),false); - writer.closeTag(); - } - - /** - * For internal use only - */ - public UserTemplate getAdaptee() { - return templates.getDelegate(); - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/Template.java b/container-search/src/main/java/com/yahoo/prelude/templates/Template.java deleted file mode 100644 index 761eb1db562..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/Template.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import java.io.Writer; - - -/** - * A template turns a template string and some state into - * an instantiated string. Add support for a particular - * template mechanism by subclassing this. - * - * @author bratseth - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -// TODO: Remove on Vespa 7 -public abstract class Template<T extends Writer> { - - /** - * Renders this template - * - * @param context the context to evaluate in - * @param writer the writer to render to - */ - public abstract void render(Context context,T writer) throws java.io.IOException; - - - /** - * Get template name - * - * @return template name - */ - public abstract String getName(); - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/TemplateSet.java b/container-search/src/main/java/com/yahoo/prelude/templates/TemplateSet.java deleted file mode 100644 index 65a5b4cacfd..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/TemplateSet.java +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.search.Result; -import com.yahoo.search.result.Hit; -import com.yahoo.text.GenericWriter; -import com.yahoo.text.XMLWriter; - -import java.io.IOException; -import java.io.Writer; - -/** - * <p>A template set contains instances of the various templates - * required to render a result.</p> - * - * <p>Normal usage is to create an instance and populate it with templates, - * but this class also supports subclassing to refine the behaviour, - * like returning different templates for different hit types.</p> - * - * @author bratseth - * @deprecated use a renderer instead - */ -@SuppressWarnings("deprecation") -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -// TODO: Remove on Vespa 7 -public class TemplateSet<T extends Writer> extends UserTemplate<T> { - - private static final String queryContextTemplateName = "queryContext"; - - private static final DefaultTemplateSet defaultTemplateSet=new DefaultTemplateSet(); - - /** - * Creates a template set containing no templates - * - * @param name the unique name of this template set, used for - * refering to it by clients - */ - public TemplateSet(String name, - String mimeType, - String encoding) { - super(name, mimeType,encoding); - } - - /** - * Returns the default template set. This is a template set which renders in - * the default xml format - */ - public static UserTemplate<XMLWriter> getDefault() { - return defaultTemplateSet; - } - - /** - * Returns the result header template - * - * @param result the result which will use the template - * @return the template to use, never null - */ - @SuppressWarnings("unchecked") - public Template<T> getHeader(Result result) { return (Template<T>) getTemplate("header"); } - - /** - * Sets the header template - * - * @param header the template to use for rendering getHeaders - * @throws NullPointerException if the given template is null - */ - public void setHeader(Template<T> header) { - setTemplateNotNull("header",header); - } - - /** - * Returns the result footer template - * - * @param result the result which will use the template - * @return the template to use, never null - */ - @SuppressWarnings("unchecked") - public Template<T> getFooter(Result result) { return (Template<T>) getTemplate("footer"); } - - /** - * Sets the footer template - * - * @param footer the template to use for rendering footers - * @throws NullPointerException if the given template is null - */ - public void setFooter(Template<T> footer) { - setTemplateNotNull("footer",footer); - } - - /** - * Returns the empty body template - * - * @param result the result which will use the template - * @return the template to use, never null - */ - @SuppressWarnings("unchecked") - public Template<T> getNohits(Result result) { return (Template<T>) getTemplate("nohits"); } - - - /** - * @return the template for rendering the query context, never null - */ - @SuppressWarnings("unchecked") - public Template<T> getQueryContext(Result result) { - return (Template<T>) getTemplate(queryContextTemplateName); - } - - /** - * @param template The template to be used for rendering query contexts, never null. - */ - public void setQueryContext(Template<T> template) { - setTemplateNotNull(queryContextTemplateName, template); - } - - /** - * Sets the nohits template - * - * @param nohits the template to use for rendering empty results - * @throws NullPointerException if the given template is null - */ - public void setNohits(Template<T> nohits) { - setTemplateNotNull("nohits",nohits); - } - - /** - * Returns the error body template - * - * @param result the result which will use the template - * @return the template to use, never null - */ - @SuppressWarnings("unchecked") - public Template<T> getError(Result result) { return (Template<T>) getTemplate("error"); } - - /** - * Sets the error template - * - * @param error the template to use for rendering errors - * @throws NullPointerException if the given template is null - */ - public void setError(Template<T> error) { - setTemplateNotNull("error",error); - } - - /** - * Returns the hit template - * - * @param resultHit the hit which will use the template - * @return the template to use, never null - */ - @SuppressWarnings("unchecked") - public Template<T> getHit(Hit resultHit) { return (Template<T>) getTemplate("hit"); } - - /** - * Sets the hit template - * - * @param hit the template to use for rendering hits - * @throws NullPointerException if the given template is null - */ - public void setHit(Template<T> hit) { - setTemplateNotNull("hit",hit); - } - - /** - * Returns the hit footer template - * - * @param hit the hit which will use the template - * @return the template to use, or null if no hit footer is used - */ - @SuppressWarnings("unchecked") - public Template<T> getHitFooter(Hit hit) { return (Template<T>) getTemplate("hitfooter"); } - - public String toString() { - return "template set " + getName() + " of type " + getMimeType() + - " [header=" + getTemplate("header") + - ",footer=" + getTemplate("footer") + - ",nohits=" + getTemplate("nohits") + - ",error=" + getTemplate("error") + - ",hit=" + getTemplate("hit") + "]"; - } - - @Override - public void header(Context context, T writer) throws IOException { - getHeader(null).render(context, writer); - } - - @Override - public void footer(Context context, T writer) throws IOException { - getFooter(null).render(context, writer); - } - - @Override - public void hit(Context context, T writer) throws IOException { - getHit(null).render(context, writer); - } - - @Override - public void error(Context context, T writer) throws IOException { - getError(null).render(context, writer); - } - - @Override - public void hitFooter(Context context, T writer) throws IOException { - Template<T> hitFooter = getHitFooter(null); - if (hitFooter != null) - hitFooter.render(context, writer); - } - - @Override - public void noHits(Context context, T writer) throws IOException { - getNohits(null).render(context, writer); - } - - @Override - public void queryContext(Context context, T writer) throws IOException { - getQueryContext(null).render(context, 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 deleted file mode 100644 index 2fa6e14019e..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/TiledTemplateSet.java +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -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; -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. - * - * This template implementation requires a few rules to be observed for it to work properly: - * <ul> - * <li>As hit fields are rendered as XML tag names, their name must be compatible with XML tag names.</li> - * <li>Results sections, meta section, provider tags are rendered based on hits having specific types (as in {@link Hit#types()}, - * see table below for a list of hit types that are needed in order for hits to render properly.</li> - * <li>Some fields inside hits corresponding to provider tags (/result/meta/provider) are formatted in a specific way, see provider fields formatting options - * below. Other fields are rendered the usual way.</li> - * </ul> - * - * <p>Hit types required for proper rendering</p> - * <table summary="Hit types required for proper rendering"> - * <tr><td>XML tag path</td><td>Required hit type</td></tr> - * <tr><td>/result/section</td><td>A hit group and have a "section" type</td></tr> - * <tr><td>/result/meta</td><td>A hit group and have a "meta" type</td></tr> - * <tr><td>/result/meta/provider</td><td>A hit that has a "logging" type</td></tr> - * </table> - * - * <p>Provider fields formatting options</p> - * <table summary="Provider fields formatting options"> - * <tr><td>Field</td><td>Formatting</td><td>Field type</td></tr> - * <tr><td>provider</td><td>name attribute of <provider> tag</td><td>Provided by container</td></tr> - * <tr><td>scheme</td><td>scheme attribute of <provider> tag</td><td>Provided by container</td></tr> - * <tr><td>host</td><td>host attribute of <provider> tag</td><td>Provided by container</td></tr> - * <tr><td>port</td><td>port attribute of <provider> tag</td><td>Provided by container</td></tr> - * <tr><td>path</td><td>path attribute of <provider> tag</td><td>Provided by container</td></tr> - * <tr><td>status</td><td>result attribute of <provider> tag</td><td>Provided by container</td></tr> - * <tr><td>latency_connect</td><td><latency type="connect"> tag</td><td>Provided by container</td></tr> - * <tr><td>latency_start</td><td><latency type="start"> tag</td><td>Provided by container</td></tr> - * <tr><td>latency_finish</td><td><latency type="finish"> tag</td><td>Provided by container</td></tr> - * <tr><td>query_param_*</td><td><parameter name="..."> tag</td><td>Provided by container</td></tr> - * <tr><td>header_*</td><td><header name="..."> tag</td><td>Provided by container</td></tr> - * <tr><td>response_header_*</td><td><response-header name="..."> tag</td><td>Provided by container</td></tr> - * <tr><td>count_first</td><td><count type="first"> tag</td><td>Provided by container</td></tr> - * <tr><td>count_last</td><td><count type="last"> tag</td><td>Provided by container</td></tr> - * <tr><td>count_total</td><td><count type="total"> tag</td><td>Provided by container</td></tr> - * <tr><td>count_deep</td><td><count type="deep"> tag</td><td>Provided by container</td></tr> - * <tr><td>queryattrs_xorronum</td><td><queryattrs name="xorronum"> tag</td><td>Provided by YST searcher</td></tr> - * <tr><td>queryattrs_RankFeaturesRewriterAttr</td><td><queryattrs name="RankFeaturesRewriterAttr"> tag</td><td>Provided by YST searcher</td></tr> - * <tr><td>queryattrs_intlannotator</td><td><queryattrs name="intlannotator"> tag</td><td>Provided by YST searcher</td></tr> - * <tr><td>queryattrs_category</td><td><queryattrs name="category"> tag</td><td>Provided by YST searcher</td></tr> - * <tr><td>wordcounts_*</td><td><wordcounts word="..."> tag</td><td>Provided by YST searcher</td></tr> - * </table> - * - * @author bratseth - * @author laboisse - * @deprecated use a Renderer instead - */ -@SuppressWarnings("deprecation") -// TODO: Remove on Vespa 7 -@Deprecated // OK -public class TiledTemplateSet extends DefaultTemplateSet { - - private FormattingOptions hitOptionsForProvider; - private FormattingOptions hitOptions; - - public TiledTemplateSet() { - this("tiled"); - } - - public TiledTemplateSet(String templateName) { - super(templateName); - - // Define formatting options that will be used by various rendering methods - hitOptions = new FormattingOptions(); - // Render provider field as an attribute, not as a regular field - hitOptions.formatFieldAsAttribute("provider", "provider"); - hitOptions.setFieldNotToRender("provider"); - - - // Define formatting options that will be used by various rendering methods, for /result/meta/provider tags - hitOptionsForProvider = new FormattingOptions(); - hitOptionsForProvider.formatFieldAsAttribute("provider", "name"); // Provider name is rendered a provider/@name - // hitOptionsForProvider.formatFieldAsAttribute("uri", "query"); // FIXME Issue with attribute formatting, keeping as regular field for now - hitOptionsForProvider.formatFieldAsAttribute("scheme", "scheme"); - hitOptionsForProvider.formatFieldAsAttribute("host", "host"); - hitOptionsForProvider.formatFieldAsAttribute("port", "port"); - hitOptionsForProvider.formatFieldAsAttribute("path", "path"); - hitOptionsForProvider.formatFieldAsAttribute("status", "result"); - // Latency fields are not defined using prefixes as we know all the field names and prefixes are expensive - hitOptionsForProvider.formatFieldWithSubtype("latency_connect", "latency", "type", "connect"); - hitOptionsForProvider.formatFieldWithSubtype("latency_start", "latency", "type", "start"); - hitOptionsForProvider.formatFieldWithSubtype("latency_finish", "latency", "type", "finish"); - // Must use prefix for query parameters - hitOptionsForProvider.formatFieldWithSubtype("query_param_", "parameter", "name"); - // Must use prefix for getHeaders - hitOptionsForProvider.formatFieldWithSubtype("header_", "header", "name"); - // Must use prefix for response getHeaders - hitOptionsForProvider.formatFieldWithSubtype("response_header_", "response-header", "name"); - // Count fields are not defined using prefixes as we know all the field names and prefixes are expensive - hitOptionsForProvider.formatFieldWithSubtype("count_first", "count", "type", "first"); - hitOptionsForProvider.formatFieldWithSubtype("count_last", "count", "type", "last"); - hitOptionsForProvider.formatFieldWithSubtype("count_total", "count", "type", "total"); - hitOptionsForProvider.formatFieldWithSubtype("count_deep", "count", "type", "deep"); - - hitOptionsForProvider.formatFieldWithSubtype("queryattrs_xorronum", "queryattrs", "name", "xorronum"); - hitOptionsForProvider.formatFieldWithSubtype("queryattrs_RankFeaturesRewriterAttr", "queryattrs", "name", "RankFeaturesRewriterAttr"); - hitOptionsForProvider.formatFieldWithSubtype("queryattrs_intlannotator", "queryattrs", "name", "intlannotator"); - hitOptionsForProvider.formatFieldWithSubtype("queryattrs_category", "queryattrs", "name", "category"); - - hitOptionsForProvider.formatFieldWithSubtype("wordcounts_", "wordcounts", "word"); - // Provider field should not be rendered in logging hits as we already have <provider name="..."> - hitOptionsForProvider.setFieldNotToRender("provider"); - } - - @Override - /** Uses an XML writer in this template */ - public XMLWriter wrapWriter(Writer writer) { return new XMLWriter(super.wrapWriter(writer)); } - - @Override - public void header(Context context,XMLWriter writer) throws IOException { - Result result=(Result)context.get("result"); - writer.xmlHeader(getRequestedEncoding(result.getQuery())); - writer.openTag("result").attribute("version","1.0"); - writer.attribute("layout", result.hits().getField("layout")); - renderCoverageAttributes(result.getCoverage(false), writer); - writer.closeStartTag(); - renderSectionContent(result.hits(),writer); - } - - /** - * Augments default hit attributes rendering with formatting options. - * There's also a hacky part: if hit is actually a hit group, tries to use - * the 'type' field in place of the hit's type, to avoid having the 'group' hit type. - */ - @Override - protected void renderHitAttributes(Hit hit, XMLWriter writer) throws IOException { - if (hit instanceof HitGroup) { - 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.types().stream().collect(Collectors.joining(" "))); - } - - if (hit.getRelevance() != null) - writer.attribute("relevance", hit.getRelevance()); - writer.attribute("source", hit.getSource()); - - for (Map.Entry<String, String> attr : hitOptions.fieldsAsAttributes()) { - Object val = hit.getField(attr.getKey()); - if (val != null) - writer.attribute(attr.getValue(), String.valueOf(val)); - } - } - - @Override - protected void renderField(Context context, Hit hit, Map.Entry<String, Object> entry, XMLWriter writer) throws IOException { - String fieldName = entry.getKey(); - - if ( !shouldRenderField(hit, fieldName)) return; - - writer.openTag(fieldName); - renderFieldContent(context, hit, fieldName, writer); - writer.closeTag(); - } - - /** Renders all fields of the hit */ - @Override - protected void renderHitFields(Context context, Hit hit, XMLWriter writer) throws IOException { - renderId(hit.getId(), writer); - for (Iterator<Map.Entry<String, Object>> it = hit.fieldIterator(); it.hasNext(); ) { - Map.Entry<String, Object> entry = it.next(); - // Exclude fields that should not be rendered - if (hitOptions.shouldRenderField(entry.getKey())) - renderField(context, hit, entry, writer); - } - } - - @Override - protected boolean shouldRenderField(Hit hit, String fieldName) { - if (fieldName.equals("relevancy")) return false; - if (fieldName.equals("collapseId")) return false; - return true; - } - - /** - * Overrides {@link DefaultTemplateSet#hit(Context, Writer)} - * to print 'logging' type meta hits as /result/meta/provider tags. - * Fails back to {@code super.hit(context, writer)} in other cases. - */ - @Override - public void hit(Context context, XMLWriter writer) throws IOException { - Hit hit = (Hit) context.get("hit"); - if (hit.isMeta() && hit.types().contains("logging")) - renderProvider(context, hit, writer); - else - super.hit(context, writer); - } - - /** - * Overrides {@link DefaultTemplateSet#renderHitGroup(HitGroup, Context, XMLWriter)} - * for /result/section and /result/meta hit groups. - * Fails back to {@code super.renderHitGroup(hit, context, writer)} otherwise. - */ - @Override - protected void renderHitGroup(HitGroup hit, Context context, XMLWriter writer) throws IOException { - if (hit.types().contains("section")) { - renderSection(hit, writer); // Renders /result/section - } - else if (hit.types().contains("meta")) { - writer.openTag("meta"); // renders /result/meta - writer.closeStartTag(); - } - else { - super.renderHitGroup(hit, context, writer); - } - } - - /** - * Renders /result/section. - * Doesn't use {@link #renderHitAttributes(Hit, XMLWriter)}. - */ - protected void renderSection(HitGroup hit, XMLWriter writer) throws IOException { - writer.openTag("section"); - writer.attribute("id",hit.getDisplayId()); - writer.attribute("layout",hit.getField("layout")); - writer.attribute("region",hit.getField("region")); - writer.attribute("placement",hit.getField("placement")); // deprecated in 5.0 - writer.closeStartTag(); - renderSectionContent(hit,writer); - } - - protected void renderSectionContent(HitGroup hit,XMLWriter writer) throws IOException { - if (hit instanceof SectionHitGroup) { // render additional information - SectionHitGroup sectionGroup=(SectionHitGroup)hit; - for (Source source : sectionGroup.sources()) { - writer.openTag("source").attribute("url",source.getUrl()); - renderParameters(source.parameters(),writer); - writer.closeTag(); - } - for (Renderer renderer : sectionGroup.renderers()) { - writer.openTag("renderer").attribute("for",renderer.getRendererFor()).attribute("name",renderer.getName()); - renderParameters(renderer.parameters(),writer); - writer.closeTag(); - } - } - } - - private void renderParameters(Map<String,String> parameters,XMLWriter writer) throws IOException { - // Render content - for (Map.Entry<String, String> parameter : parameters.entrySet()) - writer.openTag("parameter").attribute("name",parameter.getKey()).content(parameter.getValue(),false).closeTag(); - } - - /** - * Renders /result/meta/provider. - * Uses {@link #renderProviderHitAttributes(Hit, XMLWriter)} instead of the default {@link #renderHitAttributes(Hit, XMLWriter)}. - * @see #renderProviderHitAttributes(Hit, XMLWriter) - * @see #renderProviderHitFields(Context, Hit, XMLWriter) - */ - protected void renderProvider(Context context, Hit hit, XMLWriter writer) - throws IOException { - writer.openTag("provider"); - renderProviderHitAttributes(hit, writer); - writer.closeStartTag(); - renderProviderHitFields(context, hit, writer); - } - - /** - * Specific hit attributes rendering for 'provider' meta hits under /result/meta. - */ - protected void renderProviderHitAttributes(Hit hit, XMLWriter writer) throws IOException { - // Browse through fields that should be rendered as attributes - for (Map.Entry<String, String> attr : hitOptionsForProvider.fieldsAsAttributes()) - writer.attribute(attr.getValue(),hit.getField(attr.getKey())); - } - - - /** - * Renders fields under /result/meta/provider. - * - * @see #renderProviderField(Context, Hit, java.util.Map.Entry, XMLWriter) - */ - protected void renderProviderHitFields(Context context, Hit hit, XMLWriter writer) - throws IOException { - renderId(hit.getId(), writer); - for (Iterator<Map.Entry<String, Object>> it = hit.fieldIterator(); it.hasNext(); ) { - Map.Entry<String, Object> entry = it.next(); - // Exclude fields that have already been rendered as attributes and - // fields that should not be rendered - if (hitOptionsForProvider.getAttributeName(entry.getKey()) == null - && hitOptionsForProvider.shouldRenderField(entry.getKey())) - renderProviderField(context, hit, entry, writer); - } - } - - /** - * Renders one field under /result/meta/provider. - */ - protected void renderProviderField(Context context, Hit hit, - Map.Entry<String, Object> entry, XMLWriter writer) throws IOException { - - String name = entry.getKey(); - FormattingOptions.SubtypeField subtypeField = hitOptionsForProvider.getSubtype(name); - if (subtypeField == null) - subtypeField = hitOptionsForProvider.getSubtypeWithPrefix(name); - - if (subtypeField != null) { - writer.openTag(subtypeField.tagName); - if (subtypeField.attributeValue != null) { - writer.attribute(subtypeField.attributeName,subtypeField.attributeValue); - } - else if (subtypeField instanceof SubtypeFieldWithPrefix) { - // This is a subtype field that was defined using a prefix - // get the remaining part of the field name - writer.attribute(subtypeField.attributeName, - name.substring(((SubtypeFieldWithPrefix)subtypeField).prefixLength)); - } - } else { - writer.openTag(name); - } - 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/prelude/templates/UserTemplate.java b/container-search/src/main/java/com/yahoo/prelude/templates/UserTemplate.java deleted file mode 100644 index bcdf3311c1f..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/UserTemplate.java +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.templates; - -import com.yahoo.io.ByteWriter; -import com.yahoo.prelude.fastsearch.FastHit; -import com.yahoo.prelude.fastsearch.XMLField; -import com.yahoo.search.Result; -import com.yahoo.text.Utf8String; -import com.yahoo.text.XMLWriter; - -import java.io.IOException; -import java.io.Writer; -import java.util.logging.Logger; - - -/** - * A wrapper for a template set, suitable for subclassing. - * - * <p> - * A subclass of UserTemplate must implement header(), footer(), hit(), - * hitFooter(), error() and noHits(). - * - * @deprecated use a renderer instead - * @author Steinar Knutsen - */ -@SuppressWarnings("deprecation") -@Deprecated // OK (But wait for deprecated handlers in vespaclient-container-plugin to be removed) -// TODO: Remove on Vespa 7 -public abstract class UserTemplate<T extends Writer> extends GenericTemplateSet { - - // & - private static final byte[] ampersand = new byte[] { 38, 97, 109, 112, 59 }; - - // < - private static final byte[] lessThan = new byte[] { 38, 108, 116, 59 }; - // > - private static final byte[] greaterThan = new byte[] { 38, 103, 116, 59 }; - - // \\u00 - private static final byte[] quotePrefix = new byte[] { 92, 117, 48, 48 }; - - private static final Logger log = Logger.getLogger(UserTemplate.class.getName()); - - /** - * The signature of this constructor is the one which is invoked - * in a production setting. - */ - public UserTemplate(String name, String mimeType, - String encoding) { - super(name, mimeType, encoding); - } - - public UserTemplate(String name) { - this(name, - DEFAULT_MIMETYPE, - DEFAULT_ENCODING - ); - } - - /** - * This is called once before each result is rendered using this template. - * The returned writer is used in all subsequent calls. Use this if another (wrapper) - * writer of the raw incoming writer is desired in the implementation of this template. - * The class of the returned type must be given as a type argument to the template class, - * to be able to implement methods taking this wrapper writer as the argument type. - * This default implementation returns an XMLWriter. - */ - @SuppressWarnings("unchecked") - public T wrapWriter(Writer writer) { - //FIXME: Hack - return (T) XMLWriter.from(writer, 10, -1); - } - - /** - * Creates a new context suitable for this template. - * The context may be reused for several evaluations, but not multiple - * concurrent evaluations - */ - public Context createContext() { - return new MapContext(); - } - - - /** - * For internal use only - * TODO: get rid of this method * - */ - public boolean isDefaultTemplateSet() { - return getClass().equals(TemplateSet.getDefault().getClass()); - } - - /** - * Render the result set header. - * - * <p> - * The result set is available in the context object under the name - * "result". - * - * @param context - * wrapper which will contain, among other thing, the result - * set instance - * @param writer - * the destination for rendering the result - * @throws IOException - * may be propagated from the writer - */ - public abstract void header(Context context, T writer) - throws IOException; - - /** - * Render the result set footer. - * - * <p> - * The result set is available in the context object under the name - * "result". - * - * @param context - * wrapper which will contain, among other thing, the result - * set instance - * @param writer - * the destination for rendering the result - * @throws IOException - * may be propagated from the writer - */ - public abstract void footer(Context context, T writer) - throws IOException; - - /** - * Render a single top level hit. - * - * <p> - * The result set is available in the context object under the name - * "result". The hit itself as "hit", the index of the hit as "hitno", and - * all the fields under their normal names. - * - * @param context - * wrapper which will contain, among other thing, the hit - * instance - * @param writer - * the destination for rendering the hit - * @throws IOException - * may be propagated from the writer - */ - public abstract void hit(Context context, T writer) throws IOException; - - /** - * Render a footer for a single top level hit. A typical implementation may - * do nothing. - * - * <p> - * The result set is available in the context object under the name - * "result". The hit itself as "hit", the index of the hit as "hitno", and - * all the fields under their normal names. - * - * @param context - * wrapper which will contain, among other thing, the hit - * instance - * @param writer - * the destination for rendering the hit - * @throws IOException - * may be propagated from the writer - */ - public abstract void hitFooter(Context context, T writer) - throws IOException; - - /** - * Render the error message for a result set. - * - * <p> - * The result set is available in the context object under the name - * "result". - * - * @param context - * wrapper which will contain, among other thing, main error - * and result set instances. - * @param writer - * the destination for rendering the hit - * @throws IOException - * may be propagated from the writer - */ - public abstract void error(Context context, T writer) - throws IOException; - - /** - * Invoked when the result set has no hits. - * - * <p> - * The result set is available in the context object under the name - * "result". - * - * @param context - * wrapper which will contain, among other thing, the result - * set instance - * @param writer - * the destination for rendering the hit - * @throws IOException - * may be propagated from the writer - */ - public abstract void noHits(Context context, T writer) - throws IOException; - - /** - * Override this to add custom rendering for the query context of the result. - * Only called when the query context is present. - * - * <p> - * The result set is available in the context object under the name - * "result". The query context is retrieved from the result by calling - * result.getQuery.getContext(false) - * - * @param context - * wrapper which will contain, among other things, the result - * set instance - * @param writer - * the destination for rendering the hit - * @throws IOException - * may be propagated from the writer - */ - public void queryContext(Context context, T writer) throws IOException { - Result result = (Result) context.get("result"); - result.getContext(false).render(writer); - } - - /** - * Dump UTF-8 byte array to writer, but escape low ASCII codes except - * TAB, NL and CR, and escape ampersand, less than and greater than. - * - * <p> - * It is presumed the writer is buffered (which is the case in normal - * result rendering), as the method may perform a large number of write - * operations. - * - * <p> - * public only for testing. - */ - public static void dumpAndXMLQuoteUTF8(ByteWriter writer, byte[] utf) throws java.io.IOException { - int startDump = 0; - - for (int i = 0; i < utf.length; ++i) { - byte b = utf[i]; - if (b < 0) { - // Not ASCII, above character 127 - // Don't try to do something smart with UNICODE characters, - // just pass them through. - } else if (b < 32) { - switch (b) { - case 9: - case 10: - case 13: - break; - default: - writer.append(utf, startDump, i - startDump); - startDump = i + 1; - quoteByte(writer, b); - break; - } - } else { - // printable ASCII - // quote special characters, otherwise do nothing - switch (b) { - // case 34: // double quote - // writer.append(utf, startDump, i - startDump); - // startDump = i + 1; - // writer.append(doubleQuote); - // break; - case 38: // ampersand - writer.append(utf, startDump, i - startDump); - startDump = i + 1; - writer.append(ampersand); - break; - case 60: // less than - writer.append(utf, startDump, i - startDump); - startDump = i + 1; - writer.append(lessThan); - break; - case 62: // greater than - writer.append(utf, startDump, i - startDump); - startDump = i + 1; - writer.append(greaterThan); - break; - } - } - } - if (startDump < utf.length) { - writer.append(utf, startDump, utf.length - startDump); - } - } - - /** - * If the field is available as a UTF-8 byte array, - * dump it to the writer. - */ - public static boolean dumpBytes(ByteWriter writer, - FastHit hit, - String fieldName) throws java.io.IOException { - return false; - } - - private static void quoteByte(ByteWriter writer, byte b) throws java.io.IOException { - byte[] quoted = new byte[2]; - writer.append(quotePrefix); - quoted[0] = (byte) ((b >>> 4) + 0x30); - if (quoted[0] > 0x39) { - quoted[0] = (byte) (quoted[0] + 7); - } - quoted[1] = (byte) ((b & 0x0f) + 0x30); - if (quoted[1] > 0x39) { - quoted[1] = (byte) (quoted[1] + 7); - } - writer.append(quoted); - } -} diff --git a/container-search/src/main/java/com/yahoo/prelude/templates/package-info.java b/container-search/src/main/java/com/yahoo/prelude/templates/package-info.java deleted file mode 100644 index 2363a12c78d..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/templates/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -@PublicApi -package com.yahoo.prelude.templates; - -import com.yahoo.api.annotations.PublicApi; -import com.yahoo.osgi.annotation.ExportPackage; |