summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/main/java')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java18
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinition.java92
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumDefinitionSet.java34
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/DocsumField.java5
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/DocumentDatabase.java44
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java10
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java13
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java16
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/schema/DocumentSummary.java160
-rw-r--r--container-search/src/main/java/com/yahoo/search/schema/RankProfile.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/schema/Schema.java20
-rw-r--r--container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java33
-rw-r--r--container-search/src/main/java/com/yahoo/search/schema/SchemaInfoConfigurer.java18
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java31
15 files changed, 325 insertions, 177 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
index 3953190eac4..23ba3b0619c 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
@@ -18,9 +18,11 @@ import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.config.ClusterConfig;
+import com.yahoo.search.config.SchemaInfoConfig;
import com.yahoo.search.dispatch.Dispatcher;
import com.yahoo.search.query.ParameterParser;
import com.yahoo.search.result.ErrorMessage;
+import com.yahoo.search.schema.SchemaInfo;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.vespa.streamingvisitors.VdsStreamingSearcher;
import com.yahoo.yolean.Exceptions;
@@ -76,6 +78,7 @@ public class ClusterSearcher extends Searcher {
QrSearchersConfig qrsConfig,
ClusterConfig clusterConfig,
DocumentdbInfoConfig documentDbConfig,
+ SchemaInfo schemaInfo,
ComponentRegistry<Dispatcher> dispatchers,
VipStatus vipStatus,
VespaDocumentAccess access) {
@@ -99,11 +102,11 @@ public class ClusterSearcher extends Searcher {
String uniqueServerId = UUID.randomUUID().toString();
if (searchClusterConfig.indexingmode() == STREAMING) {
server = vdsCluster(uniqueServerId, searchClusterIndex,
- searchClusterConfig, docSumParams, documentDbConfig, access);
+ searchClusterConfig, docSumParams, documentDbConfig, schemaInfo, access);
vipStatus.addToRotation(server.getName());
} else {
server = searchDispatch(searchClusterIndex, searchClusterName, uniqueServerId,
- docSumParams, documentDbConfig, dispatchers);
+ docSumParams, documentDbConfig, schemaInfo, dispatchers);
}
}
@@ -125,6 +128,7 @@ public class ClusterSearcher extends Searcher {
String serverId,
SummaryParameters docSumParams,
DocumentdbInfoConfig documentdbInfoConfig,
+ SchemaInfo schemaInfo,
ComponentRegistry<Dispatcher> dispatchers) {
ClusterParams clusterParams = makeClusterParams(searchclusterIndex);
ComponentId dispatcherComponentId = new ComponentId("dispatcher." + searchClusterName);
@@ -132,7 +136,7 @@ public class ClusterSearcher extends Searcher {
if (dispatcher == null)
throw new IllegalArgumentException("Configuration error: No dispatcher " + dispatcherComponentId +
" is configured");
- return new FastSearcher(serverId, dispatcher, docSumParams, clusterParams, documentdbInfoConfig);
+ return new FastSearcher(serverId, dispatcher, docSumParams, clusterParams, documentdbInfoConfig, schemaInfo);
}
private static VdsStreamingSearcher vdsCluster(String serverId,
@@ -140,6 +144,7 @@ public class ClusterSearcher extends Searcher {
QrSearchersConfig.Searchcluster searchClusterConfig,
SummaryParameters docSumParams,
DocumentdbInfoConfig documentdbInfoConfig,
+ SchemaInfo schemaInfo,
VespaDocumentAccess access) {
if (searchClusterConfig.searchdef().size() != 1) {
throw new IllegalArgumentException("Search clusters in streaming search shall only contain a single searchdefinition : " + searchClusterConfig.searchdef());
@@ -149,7 +154,7 @@ public class ClusterSearcher extends Searcher {
searcher.setSearchClusterName(searchClusterConfig.rankprofiles().configid());
searcher.setDocumentType(searchClusterConfig.searchdef(0));
searcher.setStorageClusterRouteSpec(searchClusterConfig.storagecluster().routespec());
- searcher.init(serverId, docSumParams, clusterParams, documentdbInfoConfig);
+ searcher.init(serverId, docSumParams, clusterParams, documentdbInfoConfig, schemaInfo);
return searcher;
}
@@ -218,7 +223,7 @@ public class ClusterSearcher extends Searcher {
}
private Set<String> schemasHavingProfile(String profile, Execution.Context context) {
- return context.schemaInfo().schemas().stream()
+ return context.schemaInfo().schemas().values().stream()
.filter(schema -> schema.rankProfiles().containsKey(profile))
.map(schema -> schema.name())
.collect(Collectors.toSet());
@@ -234,7 +239,8 @@ public class ClusterSearcher extends Searcher {
searcher.fill(result, summaryClass, execution);
} else {
if (result.hits().getErrorHit() == null) {
- result.hits().addError(ErrorMessage.createTimeout("No time left to get summaries, query timeout was " + query.getTimeout() + " ms"));
+ result.hits().addError(ErrorMessage.createTimeout("No time left to get summaries, query timeout was " +
+ query.getTimeout() + " ms"));
}
}
} else {
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 8a7d14d5f49..33b912da42f 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
@@ -1,15 +1,11 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.prelude.fastsearch;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.yahoo.data.access.Inspector;
+import com.yahoo.search.schema.DocumentSummary;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
+import java.util.stream.Collectors;
/**
* A docsum definition which knows how to decode a certain class of document
@@ -21,55 +17,26 @@ import java.util.Set;
public class DocsumDefinition {
private final String name;
- private final ImmutableList<DocsumField> fields;
+ private final Map<String, DocsumField> fields;
/** True if this contains dynamic fields */
private final boolean dynamic;
- // Mapping between field names and their index in this.fields
- private final ImmutableMap<String, Integer> fieldNameToIndex;
-
- public DocsumDefinition(String name, List<DocsumField> fields) {
- this.name = name;
- this.dynamic = false;
- this.fields = ImmutableList.copyOf(fields);
- ImmutableMap.Builder<String, Integer> fieldNameToIndexBuilder = new ImmutableMap.Builder<>();
- int i = 0;
- for (DocsumField field : fields)
- fieldNameToIndexBuilder.put(field.name, i++);
- this.fieldNameToIndex = fieldNameToIndexBuilder.build();
+ public DocsumDefinition(DocumentSummary documentSummary) {
+ this.name = documentSummary.name();
+ this.dynamic = documentSummary.isDynamic();
+ this.fields = documentSummary.fields()
+ .stream()
+ .map(field -> DocsumField.create(field.name(), field.type().asString()))
+ .collect(Collectors.toUnmodifiableMap(field -> field.getName(),
+ field -> field));
}
- DocsumDefinition(DocumentdbInfoConfig.Documentdb.Summaryclass config) {
- this.name = config.name();
-
- List<DocsumField> fieldsBuilder = new ArrayList<>();
- Map<String, Integer> fieldNameToIndexBuilder = new HashMap<>();
- boolean dynamic = false;
- 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()));
- if (field.dynamic())
- dynamic = true;
- }
- this.dynamic = dynamic;
- fields = ImmutableList.copyOf(fieldsBuilder);
- fieldNameToIndex = ImmutableMap.copyOf(fieldNameToIndexBuilder);
- }
-
- /** Returns the field at this index, or null if none */
- public DocsumField getField(int fieldIndex) {
- if (fieldIndex >= fields.size()) return null;
- return fields.get(fieldIndex);
- }
+ public String name() { return name; }
+ public Map<String, DocsumField> fields() { return fields; }
- /** Returns the field with this name, or null if none */
- public DocsumField getField(String fieldName) {
- Integer index = fieldNameToIndex.get(fieldName);
- if (index == null) return null;
- return getField(index);
- }
+ /** Returns whether this summary contains one or more dynamic fields */
+ public boolean isDynamic() { return dynamic; }
/**
* Returns the given slime value as the type specified in this, or null if the type is not known.
@@ -78,35 +45,14 @@ public class DocsumDefinition {
* another has not.
*/
public Object convert(String fieldName, Inspector value) {
- DocsumField fieldType = getField(fieldName);
- if (fieldType == null || ! value.valid()) return null;
- return fieldType.convert(value);
- }
-
- public Set<String> fieldNames() {
- return fieldNameToIndex.keySet();
+ DocsumField field = fields.get(fieldName);
+ if (field == null || ! value.valid()) return null;
+ return field.convert(value);
}
@Override
public String toString() {
- return "docsum definition '" + getName() + "'";
- }
-
- public String getName() {
- return name;
- }
-
- public int getFieldCount() {
- return fields.size();
- }
-
- public List<DocsumField> getFields() {
- return fields;
- }
-
- /** Returns whether this summary contains one or more dynamic fields */
- public boolean isDynamic() {
- return dynamic;
+ return "docsum definition '" + name() + "'";
}
}
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 1e0cfa3be9e..2b26cd29b78 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
@@ -1,7 +1,8 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.prelude.fastsearch;
-import com.google.common.collect.ImmutableMap;
+import com.yahoo.search.schema.DocumentSummary;
+import com.yahoo.search.schema.Schema;
import com.yahoo.slime.BinaryFormat;
import com.yahoo.data.access.Inspector;
import com.yahoo.slime.Slime;
@@ -10,7 +11,6 @@ import com.yahoo.prelude.ConfigurationException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Logger;
@@ -31,12 +31,15 @@ public final class DocsumDefinitionSet {
private final Map<String, DocsumDefinition> definitionsByName;
- public DocsumDefinitionSet(DocumentdbInfoConfig.Documentdb config) {
- this(toDocsums(config));
+ public DocsumDefinitionSet(Schema schema) {
+ this(schema.documentSummaries().values());
}
- public DocsumDefinitionSet(Collection<DocsumDefinition> docsumDefinitions) {
- this.definitionsByName = ImmutableMap.copyOf(docsumDefinitions.stream().collect(Collectors.toMap(DocsumDefinition::getName, p -> p)));
+ public DocsumDefinitionSet(Collection<DocumentSummary> docsumDefinitions) {
+ this.definitionsByName = docsumDefinitions.stream()
+ .map(summary -> new DocsumDefinition(summary))
+ .collect(Collectors.toUnmodifiableMap(summary -> summary.name(),
+ summary -> summary));
}
/**
@@ -45,15 +48,15 @@ public final class DocsumDefinitionSet {
* @throws ConfigurationException if the requested summary class is not found and there is none called "default"
*/
public DocsumDefinition getDocsum(String summaryClass) {
+ if (summaryClass == null)
+ summaryClass = "default";
DocsumDefinition ds = definitionsByName.get(summaryClass);
- if (ds == null) {
+ if (ds == null)
ds = definitionsByName.get("default");
- }
- if (ds == null) {
+ if (ds == null)
throw new ConfigurationException("Fetched hit with summary class " + summaryClass +
", but this summary class is not in current summary config (" + this + ")" +
" (that is, you asked for something unknown, and no default was found)");
- }
return ds;
}
@@ -95,7 +98,7 @@ public final class DocsumDefinitionSet {
if (sb.length() != 0) {
sb.append(",");
}
- sb.append("[").append(e.getKey()).append(",").append(e.getValue().getName()).append("]");
+ sb.append("[").append(e.getKey()).append(",").append(e.getValue().name()).append("]");
}
return sb.toString();
}
@@ -104,13 +107,4 @@ public final class DocsumDefinitionSet {
return definitionsByName.size();
}
- 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)));
- 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 e412258ff15..e6201a694cb 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
@@ -17,7 +17,7 @@ import java.util.logging.Logger;
public abstract class DocsumField {
private static final Logger log = Logger.getLogger(DocsumField.class.getName());
- private static FieldFactory fieldFactory;
+ private static final FieldFactory fieldFactory;
private static class FieldFactory {
@@ -32,8 +32,7 @@ public abstract class DocsumField {
DocsumField create(String typename, String name)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
- DocsumField f = constructors.get(typename).newInstance(name);
- return f;
+ return constructors.get(typename).newInstance(name);
}
}
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 67038e0e771..72ccf4aa1dd 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,6 +2,8 @@
package com.yahoo.prelude.fastsearch;
import com.yahoo.search.schema.RankProfile;
+import com.yahoo.search.schema.Schema;
+import com.yahoo.search.schema.SchemaInfo;
import com.yahoo.tensor.TensorType;
import java.util.ArrayList;
@@ -17,48 +19,20 @@ import java.util.stream.Collectors;
*/
public class DocumentDatabase {
- // TODO: What about name conflicts when different search defs have the same rank profile/docsum?
-
public static final String MATCH_PROPERTY = "match";
public static final String SEARCH_DOC_TYPE_KEY = "documentdb.searchdoctype";
- private final String name;
+ private final Schema schema;
private final DocsumDefinitionSet docsumDefSet;
- private final Map<String, RankProfile> rankProfiles;
-
- public DocumentDatabase(DocumentdbInfoConfig.Documentdb documentDb) {
- this(documentDb.name(), new DocsumDefinitionSet(documentDb), toRankProfiles(documentDb.rankprofile()));
+ public DocumentDatabase(Schema schema) {
+ this.schema = schema;
+ this.docsumDefSet = new DocsumDefinitionSet(schema);
}
- public DocumentDatabase(String name, DocsumDefinitionSet docsumDefinitionSet, Collection<RankProfile> rankProfiles) {
- this.name = name;
- this.docsumDefSet = docsumDefinitionSet;
- this.rankProfiles = Map.copyOf(rankProfiles.stream().collect(Collectors.toMap(RankProfile::name, p -> p)));
- }
-
- public String getName() {
- return name;
- }
+ public Schema schema() { return schema; }
- public DocsumDefinitionSet getDocsumDefinitionSet() {
- return docsumDefSet;
- }
-
- /** Returns an unmodifiable map of all the rank profiles in this indexed by rank profile name */
- public Map<String, RankProfile> rankProfiles() { return rankProfiles; }
-
- private static Collection<RankProfile> toRankProfiles(Collection<DocumentdbInfoConfig.Documentdb.Rankprofile> rankProfileConfigList) {
- List<RankProfile> rankProfiles = new ArrayList<>();
- for (var profileConfig : rankProfileConfigList) {
- var builder = new RankProfile.Builder(profileConfig.name());
- builder.setHasSummaryFeatures(profileConfig.hasSummaryFeatures());
- builder.setHasRankFeatures(profileConfig.hasRankFeatures());
- for (var inputConfig : profileConfig.input())
- builder.addInput(inputConfig.name(), TensorType.fromSpec(inputConfig.type()));
- rankProfiles.add(builder.build());
- }
- return rankProfiles;
- }
+ /** Returns the document summary model in this which knows how to convert serialized data to hit fields. */
+ public DocsumDefinitionSet getDocsumDefinitionSet() { return docsumDefSet; }
}
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 094367dc140..a094be943a2 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
@@ -183,7 +183,7 @@ public class FastHit extends Hit {
/** For internal use */
public void addSummary(DocsumDefinition docsumDef, Inspector value) {
if (removedFields != null)
- removedFields.removeAll(docsumDef.fieldNames());
+ removedFields.removeAll(docsumDef.fields().keySet());
if ( ! (summaries instanceof ArrayList) ) summaries = new ArrayList<>(8);
summaries.add(0, new SummaryData(this, docsumDef, value, 1 + summaries.size()));
}
@@ -363,8 +363,8 @@ public class FastHit extends Hit {
@Override
public String toString() {
- return super.toString() + " [fasthit, globalid: " + new GlobalId(globalId).toString() + ", partId: "
- + partId + ", distributionkey: " + distributionKey + "]";
+ return super.toString() + " [fasthit, globalid: " + new GlobalId(globalId).toString() + ", partId: " +
+ partId + ", distributionkey: " + distributionKey + "]";
}
@Override
@@ -562,7 +562,7 @@ public class FastHit extends Hit {
void forEachFieldAsRaw(RawUtf8Consumer consumer) {
data.traverse((ObjectTraverser)(name, value) -> {
if (!shadowed(name) && !removed(name)) {
- DocsumField fieldType = type.getField(name);
+ DocsumField fieldType = type.fields().get(name);
if (fieldType != null) {
if (fieldType.isString()) {
byte[] utf8Value = value.asUtf8();
@@ -592,7 +592,7 @@ public class FastHit extends Hit {
private boolean shadowed(String name) {
if (hit.hasField(name)) return true;
for (int i = 0; i < hit.summaries.size() - index; i++) {
- if (hit.summaries.get(i).type.fieldNames().contains(name))
+ if (hit.summaries.get(i).type.fields().containsKey(name))
return true;
}
return false;
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
index 27a45753bb5..33ad8d8c9a8 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
@@ -6,6 +6,7 @@ import com.yahoo.prelude.Pong;
import com.yahoo.prelude.querytransform.QueryRewrite;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
+import com.yahoo.search.config.SchemaInfoConfig;
import com.yahoo.search.dispatch.Dispatcher;
import com.yahoo.search.dispatch.FillInvoker;
import com.yahoo.search.dispatch.SearchInvoker;
@@ -15,6 +16,7 @@ import com.yahoo.search.query.Ranking;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.result.Hit;
import com.yahoo.search.result.HitGroup;
+import com.yahoo.search.schema.SchemaInfo;
import com.yahoo.search.searchchain.Execution;
import java.io.IOException;
@@ -51,10 +53,13 @@ public class FastSearcher extends VespaBackEndSearcher {
* @param clusterParams the cluster number, and other cluster backend parameters
* @param documentdbInfoConfig document database parameters
*/
- public FastSearcher(String serverId, Dispatcher dispatcher,
- SummaryParameters docSumParams, ClusterParams clusterParams,
- DocumentdbInfoConfig documentdbInfoConfig) {
- init(serverId, docSumParams, clusterParams, documentdbInfoConfig);
+ public FastSearcher(String serverId,
+ Dispatcher dispatcher,
+ SummaryParameters docSumParams,
+ ClusterParams clusterParams,
+ DocumentdbInfoConfig documentdbInfoConfig,
+ SchemaInfo schemaInfo) {
+ init(serverId, docSumParams, clusterParams, documentdbInfoConfig, schemaInfo);
this.dispatcher = dispatcher;
}
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 3847e80d3c7..21037be1a8b 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
@@ -14,10 +14,12 @@ import com.yahoo.protect.Validator;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.cluster.PingableSearcher;
+import com.yahoo.search.config.SchemaInfoConfig;
import com.yahoo.search.schema.RankProfile;
import com.yahoo.search.grouping.vespa.GroupingExecutor;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.result.Hit;
+import com.yahoo.search.schema.SchemaInfo;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.searchlib.aggregation.Grouping;
@@ -107,7 +109,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
if (hasLocation(query.getModel().getQueryTree())) return true;
// Needed to generate ranking features?
- RankProfile rankProfile = documentDb.rankProfiles().get(query.getRanking().getProfile());
+ RankProfile rankProfile = documentDb.schema().rankProfiles().get(query.getRanking().getProfile());
if (rankProfile == null) return true; // stay safe
if (rankProfile.hasSummaryFeatures()) return true;
if (query.getRanking().getListFeatures()) return true;
@@ -133,12 +135,12 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
private void resolveDocumentDatabase(Query query) {
DocumentDatabase docDb = getDocumentDatabase(query);
if (docDb != null) {
- query.getModel().setDocumentDb(docDb.getName());
+ query.getModel().setDocumentDb(docDb.schema().name());
}
}
public final void init(String serverId, SummaryParameters docSumParams, ClusterParams clusterParams,
- DocumentdbInfoConfig documentdbInfoConfig) {
+ DocumentdbInfoConfig documentdbInfoConfig, SchemaInfo schemaInfo) {
this.serverId = serverId;
this.name = clusterParams.searcherName;
@@ -148,10 +150,9 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
if (documentdbInfoConfig != null) {
for (DocumentdbInfoConfig.Documentdb docDb : documentdbInfoConfig.documentdb()) {
- DocumentDatabase db = new DocumentDatabase(docDb);
- if (documentDbs.isEmpty()) {
+ DocumentDatabase db = new DocumentDatabase(schemaInfo.schemas().get(docDb.name()));
+ if (documentDbs.isEmpty())
defaultDocumentDb = db;
- }
documentDbs.put(docDb.name(), db);
}
}
@@ -159,6 +160,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
protected void transformQuery(Query query) { }
+ @Override
public Result search(Query query, Execution execution) {
// query root should not be null here
Item root = query.getModel().getQueryTree().getRoot();
@@ -391,7 +393,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
private String decodeSummary(String summaryClass, FastHit hit, byte[] docsumdata) {
DocumentDatabase db = getDocumentDatabase(hit.getQuery());
- hit.setField(Hit.SDDOCNAME_FIELD, db.getName());
+ hit.setField(Hit.SDDOCNAME_FIELD, db.schema().name());
return decodeSummary(summaryClass, hit, docsumdata, db.getDocsumDefinitionSet());
}
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java
index 7a5ef94069d..57f7ea34a97 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java
@@ -215,7 +215,7 @@ public class RpcProtobufFillInvoker extends FillInvoker {
for (int i = 0; i < hits.size(); i++) {
Inspector summary = summaries.entry(i).field("docsum");
if (summary.valid()) {
- hits.get(i).setField(Hit.SDDOCNAME_FIELD, documentDb.getName());
+ hits.get(i).setField(Hit.SDDOCNAME_FIELD, documentDb.schema().name());
hits.get(i).addSummary(documentDb.getDocsumDefinitionSet().getDocsum(summaryClass), summary);
hits.get(i).setFilled(summaryClass);
} else {
diff --git a/container-search/src/main/java/com/yahoo/search/schema/DocumentSummary.java b/container-search/src/main/java/com/yahoo/search/schema/DocumentSummary.java
new file mode 100644
index 00000000000..12037ee6633
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/schema/DocumentSummary.java
@@ -0,0 +1,160 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.schema;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A document summary definition: Defines the schema on which a document hit may be
+ * represented in a Result.
+ *
+ * @author bratseth
+ */
+public class DocumentSummary {
+
+ private final String name;
+ private final List<Field> fields;
+ private final boolean dynamic;
+
+ private DocumentSummary(Builder builder) {
+ this.name = builder.name;
+ this.fields = List.copyOf(builder.fields);
+ this.dynamic = builder.dynamic;
+ }
+
+ public String name() { return name; }
+ public List<Field> fields() { return fields; }
+
+ /** Returns whether this contains fields which are generated dynamically from the query and field data. */
+ public boolean isDynamic() { return dynamic; }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if ( ! (o instanceof DocumentSummary)) return false;
+ var other = (DocumentSummary)o;
+ if ( ! other.name.equals(this.name)) return false;
+ if ( other.dynamic != this.dynamic) return false;
+ if ( ! other.fields.equals(this.fields)) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, dynamic, fields);
+ }
+
+ @Override
+ public String toString() {
+ return "document summary '" + name + "'";
+ }
+
+ public static class Builder {
+
+ private final String name;
+ private final List<Field> fields = new ArrayList<>();
+ private boolean dynamic;
+
+ public Builder(String name) {
+ this.name = name;
+ }
+
+ public Builder add(Field field) {
+ fields.add(field);
+ return this;
+ }
+
+ public Builder setDynamic(boolean dynamic) {
+ this.dynamic = dynamic;
+ return this;
+ }
+
+ public DocumentSummary build() { return new DocumentSummary(this); }
+
+ }
+
+ public static class Field {
+
+ public enum Type {
+ bool,
+ byteType("byte"),
+ shortType("short"),
+ integer,
+ int64,
+ float16,
+ floatType("float"),
+ doubleType("double"),
+ string,
+ data,
+ raw,
+ longstring,
+ longdata,
+ jsonstring,
+ featuredata,
+ xmlstring,
+ tensor;
+
+ private final String name;
+
+ Type() {
+ this(null);
+ }
+
+ Type(String name) {
+ this.name = name;
+ }
+
+ /** Use this, not name() to retrieve the string value of this. */
+ public String asString() {
+ return name != null ? name : name();
+ }
+
+ @Override
+ public String toString() { return asString(); }
+
+ public static Type fromString(String name) {
+ return Arrays.stream(Type.values()).filter(t -> name.equals(t.asString())).findAny().orElseThrow();
+ }
+
+ }
+
+ private final String name;
+ private final Type type;
+
+ public Field(String name, String type) {
+ this(name, Type.fromString(type));
+ }
+
+ public Field(String name, Type type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String name() { return name; }
+ public Type type() { return type; }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if ( ! (o instanceof Field)) return false;
+ var other = (Field)o;
+ if ( ! other.name.equals(this.name)) return false;
+ if ( other.type != this.type) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, type);
+ }
+
+ @Override
+ public String toString() {
+ return "summary field '" + name + "' " + type;
+ }
+
+ }
+
+}
diff --git a/container-search/src/main/java/com/yahoo/search/schema/RankProfile.java b/container-search/src/main/java/com/yahoo/search/schema/RankProfile.java
index 8267e5c937b..39d4a389e6f 100644
--- a/container-search/src/main/java/com/yahoo/search/schema/RankProfile.java
+++ b/container-search/src/main/java/com/yahoo/search/schema/RankProfile.java
@@ -3,7 +3,9 @@ package com.yahoo.search.schema;
import com.yahoo.tensor.TensorType;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@@ -23,7 +25,7 @@ public class RankProfile {
this.name = builder.name;
this.hasSummaryFeatures = builder.hasSummaryFeatures;
this.hasRankFeatures = builder.hasRankFeatures;
- this.inputs = Map.copyOf(builder.inputs);
+ this.inputs = Collections.unmodifiableMap(builder.inputs);
}
public String name() { return name; }
@@ -64,7 +66,7 @@ public class RankProfile {
private final String name;
private boolean hasSummaryFeatures = true;
private boolean hasRankFeatures = true;
- private final Map<String, TensorType> inputs = new HashMap<>();
+ private final Map<String, TensorType> inputs = new LinkedHashMap<>();
public Builder(String name) {
this.name = Objects.requireNonNull(name);
diff --git a/container-search/src/main/java/com/yahoo/search/schema/Schema.java b/container-search/src/main/java/com/yahoo/search/schema/Schema.java
index b66e6ce957a..2ab5a30fbd7 100644
--- a/container-search/src/main/java/com/yahoo/search/schema/Schema.java
+++ b/container-search/src/main/java/com/yahoo/search/schema/Schema.java
@@ -3,7 +3,9 @@ package com.yahoo.search.schema;
import com.yahoo.api.annotations.Beta;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@@ -19,14 +21,17 @@ public class Schema {
private final String name;
private final Map<String, RankProfile> rankProfiles;
+ private final Map<String, DocumentSummary> documentSummaries;
private Schema(Builder builder) {
this.name = builder.name;
- this.rankProfiles = Map.copyOf(builder.rankProfiles);
+ this.rankProfiles = Collections.unmodifiableMap(builder.rankProfiles);
+ this.documentSummaries = Collections.unmodifiableMap(builder.documentSummaries);
}
public String name() { return name; }
public Map<String, RankProfile> rankProfiles() { return rankProfiles; }
+ public Map<String, DocumentSummary> documentSummaries() { return documentSummaries; }
@Override
public boolean equals(Object o) {
@@ -35,12 +40,13 @@ public class Schema {
Schema other = (Schema)o;
if ( ! other.name.equals(this.name)) return false;
if ( ! other.rankProfiles.equals(this.rankProfiles)) return false;
+ if ( ! other.documentSummaries.equals(this.documentSummaries)) return false;
return true;
}
@Override
public int hashCode() {
- return Objects.hash(name, rankProfiles);
+ return Objects.hash(name, rankProfiles, documentSummaries);
}
@Override
@@ -51,14 +57,20 @@ public class Schema {
public static class Builder {
private final String name;
- private final Map<String, RankProfile> rankProfiles = new HashMap<>();
+ private final Map<String, RankProfile> rankProfiles = new LinkedHashMap<>();
+ private final Map<String, DocumentSummary> documentSummaries = new LinkedHashMap<>();
public Builder(String name) {
this.name = Objects.requireNonNull(name);
}
public Builder add(RankProfile profile) {
- rankProfiles.put(profile.name(), Objects.requireNonNull(profile));
+ rankProfiles.put(profile.name(), profile);
+ return this;
+ }
+
+ public Builder add(DocumentSummary documentSummary) {
+ documentSummaries.put(documentSummary.name(), documentSummary);
return this;
}
diff --git a/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java b/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java
index 4daf110fc54..7bd66445512 100644
--- a/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java
+++ b/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java
@@ -2,13 +2,17 @@
package com.yahoo.search.schema;
import com.yahoo.api.annotations.Beta;
+import com.yahoo.component.annotation.Inject;
import com.yahoo.container.QrSearchersConfig;
import com.yahoo.search.Query;
import com.yahoo.search.config.IndexInfoConfig;
import com.yahoo.search.config.SchemaInfoConfig;
import com.yahoo.tensor.TensorType;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -39,11 +43,12 @@ public class SchemaInfo {
private static final SchemaInfo empty = new SchemaInfo(List.of(), Map.of());
- private final List<Schema> schemas;
+ private final Map<String, Schema> schemas;
/** The schemas contained in each content cluster indexed by cluster name */
private final Map<String, List<String>> clusters;
+ @Inject
public SchemaInfo(IndexInfoConfig indexInfo, // will be used in the future
SchemaInfoConfig schemaInfoConfig,
QrSearchersConfig qrSearchersConfig) {
@@ -51,12 +56,14 @@ public class SchemaInfo {
}
public SchemaInfo(List<Schema> schemas, Map<String, List<String>> clusters) {
- this.schemas = List.copyOf(schemas);
- this.clusters = Map.copyOf(clusters);
+ Map<String, Schema> schemaMap = new LinkedHashMap<>();
+ schemas.forEach(schema -> schemaMap.put(schema.name(), schema));
+ this.schemas = Collections.unmodifiableMap(schemaMap);
+ this.clusters = Collections.unmodifiableMap(clusters);
}
- /** Returns all schemas configured in this application. */
- public List<Schema> schemas() { return schemas; }
+ /** Returns all schemas configured in this application, indexed by schema name. */
+ public Map<String, Schema> schemas() { return schemas; }
public Session newSession(Query query) {
return new Session(query.getModel().getSources(), query.getModel().getRestrict(), clusters, schemas);
@@ -80,13 +87,13 @@ public class SchemaInfo {
/** The schema information resolved to be relevant to this session. */
public static class Session {
- private final List<Schema> schemas;
+ private final Collection<Schema> schemas;
private Session(Set<String> sources,
Set<String> restrict,
Map<String, List<String>> clusters,
- List<Schema> candidates) {
- this.schemas = resolveSchemas(sources, restrict, clusters, candidates);
+ Map<String, Schema> candidates) {
+ this.schemas = resolveSchemas(sources, restrict, clusters, candidates.values());
}
/**
@@ -96,10 +103,10 @@ public class SchemaInfo {
*
* @return the possibly empty list of schemas matching the arguments
*/
- private static List<Schema> resolveSchemas(Set<String> sources,
- Set<String> restrict,
- Map<String, List<String>> clusters,
- List<Schema> candidates) {
+ private static Collection<Schema> resolveSchemas(Set<String> sources,
+ Set<String> restrict,
+ Map<String, List<String>> clusters,
+ Collection<Schema> candidates) {
if (sources.isEmpty())
return restrict.isEmpty() ? candidates : keep(restrict, candidates);
@@ -114,7 +121,7 @@ public class SchemaInfo {
return restrict.isEmpty() ? candidates : keep(restrict, candidates);
}
- private static List<Schema> keep(Set<String> names, List<Schema> schemas) {
+ private static List<Schema> keep(Set<String> names, Collection<Schema> schemas) {
return schemas.stream().filter(schema -> names.contains(schema.name())).collect(Collectors.toList());
}
diff --git a/container-search/src/main/java/com/yahoo/search/schema/SchemaInfoConfigurer.java b/container-search/src/main/java/com/yahoo/search/schema/SchemaInfoConfigurer.java
index 84ed9ae8e3d..c5a74ece866 100644
--- a/container-search/src/main/java/com/yahoo/search/schema/SchemaInfoConfigurer.java
+++ b/container-search/src/main/java/com/yahoo/search/schema/SchemaInfoConfigurer.java
@@ -1,11 +1,17 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.schema;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.yahoo.container.QrSearchersConfig;
+import com.yahoo.prelude.fastsearch.DocsumDefinition;
+import com.yahoo.prelude.fastsearch.DocsumField;
+import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig;
import com.yahoo.search.config.SchemaInfoConfig;
import com.yahoo.tensor.TensorType;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -24,6 +30,7 @@ class SchemaInfoConfigurer {
static Schema toSchema(SchemaInfoConfig.Schema schemaInfoConfig) {
Schema.Builder builder = new Schema.Builder(schemaInfoConfig.name());
+
for (var profileConfig : schemaInfoConfig.rankprofile()) {
RankProfile.Builder profileBuilder = new RankProfile.Builder(profileConfig.name());
profileBuilder.setHasSummaryFeatures(profileConfig.hasSummaryFeatures());
@@ -32,6 +39,17 @@ class SchemaInfoConfigurer {
profileBuilder.addInput(inputConfig.name(), TensorType.fromSpec(inputConfig.type()));
builder.add(profileBuilder.build());
}
+
+ for (var summaryConfig : schemaInfoConfig.summaryclass()) {
+ DocumentSummary.Builder summaryBuilder = new DocumentSummary.Builder(summaryConfig.name());
+ for (var field : summaryConfig.fields()) {
+ if (field.dynamic())
+ summaryBuilder.setDynamic(true);
+ summaryBuilder.add(new DocumentSummary.Field(field.name(), field.type()));
+ }
+ builder.add(summaryBuilder.build());
+ }
+
return builder.build();
}
diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java b/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java
index 3e44b02618e..bf8ef39001f 100644
--- a/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java
+++ b/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java
@@ -2,6 +2,7 @@
package com.yahoo.search.searchchain;
import com.google.inject.Inject;
+import com.yahoo.api.annotations.Beta;
import com.yahoo.component.AbstractComponent;
import com.yahoo.component.chain.Chain;
import com.yahoo.component.chain.ChainsConfigurer;
@@ -48,6 +49,8 @@ public class ExecutionFactory extends AbstractComponent {
private final RendererRegistry rendererRegistry;
private final Executor executor;
+ // TODO: Fix tests depending on HandlersConfigurerTestWrapper so that this constructor can be removed
+ @Beta
@Inject
public ExecutionFactory(ChainsConfig chainsConfig,
IndexInfoConfig indexInfo,
@@ -58,9 +61,29 @@ public class ExecutionFactory extends AbstractComponent {
Linguistics linguistics,
ComponentRegistry<Renderer> renderers,
Executor executor) {
+ this(chainsConfig,
+ indexInfo,
+ new SchemaInfo(indexInfo, schemaInfo, clusters),
+ clusters,
+ searchers,
+ specialTokens,
+ linguistics,
+ renderers,
+ executor);
+ }
+
+ public ExecutionFactory(ChainsConfig chainsConfig,
+ IndexInfoConfig indexInfo,
+ SchemaInfo schemaInfo,
+ QrSearchersConfig clusters,
+ ComponentRegistry<Searcher> searchers,
+ SpecialtokensConfig specialTokens,
+ Linguistics linguistics,
+ ComponentRegistry<Renderer> renderers,
+ Executor executor) {
this.searchChainRegistry = createSearchChainRegistry(searchers, chainsConfig);
this.indexFacts = new IndexFacts(new IndexModel(indexInfo, clusters)).freeze();
- this.schemaInfo = new SchemaInfo(indexInfo, schemaInfo, clusters);
+ this.schemaInfo = schemaInfo;
this.specialTokens = new SpecialTokenRegistry(specialTokens);
this.linguistics = linguistics;
this.renderingExecutor = createRenderingExecutor();
@@ -78,7 +101,7 @@ public class ExecutionFactory extends AbstractComponent {
Linguistics linguistics,
ComponentRegistry<Renderer> renderers,
Executor executor) {
- this(chainsConfig, indexInfo, new SchemaInfoConfig.Builder().build(), clusters, searchers, specialTokens, linguistics, renderers, executor);
+ this(chainsConfig, indexInfo, SchemaInfo.empty(), clusters, searchers, specialTokens, linguistics, renderers, executor);
}
/** @deprecated pass the container threadpool */
@@ -90,7 +113,7 @@ public class ExecutionFactory extends AbstractComponent {
SpecialtokensConfig specialTokens,
Linguistics linguistics,
ComponentRegistry<Renderer> renderers) {
- this(chainsConfig, indexInfo, new SchemaInfoConfig.Builder().build(), clusters, searchers, specialTokens, linguistics, renderers, null);
+ this(chainsConfig, indexInfo, SchemaInfo.empty(), clusters, searchers, specialTokens, linguistics, renderers, null);
}
private SearchChainRegistry createSearchChainRegistry(ComponentRegistry<Searcher> searchers,
@@ -144,7 +167,7 @@ public class ExecutionFactory extends AbstractComponent {
public static ExecutionFactory empty() {
return new ExecutionFactory(new ChainsConfig.Builder().build(),
new IndexInfoConfig.Builder().build(),
- new SchemaInfoConfig.Builder().build(),
+ SchemaInfo.empty(),
new QrSearchersConfig.Builder().build(),
new ComponentRegistry<>(),
new SpecialtokensConfig.Builder().build(),