summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-09-01 15:56:28 +0200
committerGitHub <noreply@github.com>2022-09-01 15:56:28 +0200
commit96d24924eed043c9d8df7694375828745889faa2 (patch)
tree5810bbe78d7beccdbe5751df1c88d6b8680d093e
parenta5a7789218d9fb5a569eb8f3feec6747f9ec2ca3 (diff)
parent38bfeeadafabeeef540157e440224b03ba80ed4d (diff)
Merge pull request #23878 from vespa-engine/bratseth/moodel-config
Bratseth/model config
-rw-r--r--abi-check-plugin/src/main/java/com/yahoo/abicheck/mojo/AbiCheck.java2
-rw-r--r--config-lib/abi-spec.json51
-rw-r--r--config-lib/src/main/java/com/yahoo/config/FileNode.java4
-rwxr-xr-xconfig-lib/src/main/java/com/yahoo/config/FileReference.java3
-rw-r--r--config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java8
-rw-r--r--config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java7
-rw-r--r--config-lib/src/main/java/com/yahoo/config/ModelNode.java64
-rw-r--r--config-lib/src/main/java/com/yahoo/config/ModelReference.java131
-rw-r--r--config-lib/src/main/java/com/yahoo/config/PathNode.java3
-rwxr-xr-xconfig-lib/src/main/java/com/yahoo/config/UrlReference.java1
-rw-r--r--config-lib/src/test/java/com/yahoo/config/BooleanNodeTest.java3
-rw-r--r--config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java9
-rw-r--r--config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java9
-rw-r--r--config-lib/src/test/java/com/yahoo/config/DoubleNodeTest.java3
-rw-r--r--config-lib/src/test/java/com/yahoo/config/EnumNodeTest.java2
-rw-r--r--config-lib/src/test/java/com/yahoo/config/FileNodeTest.java3
-rw-r--r--config-lib/src/test/java/com/yahoo/config/IntegerNodeTest.java3
-rw-r--r--config-lib/src/test/java/com/yahoo/config/LongNodeTest.java3
-rw-r--r--config-lib/src/test/java/com/yahoo/config/ModelNodeTest.java29
-rw-r--r--config-lib/src/test/java/com/yahoo/config/NodeVectorTest.java1
-rw-r--r--config-lib/src/test/java/com/yahoo/config/PathNodeTest.java3
-rw-r--r--config-lib/src/test/java/com/yahoo/config/StringNodeTest.java1
-rw-r--r--config-lib/src/test/resources/configdefinitions/test.function-test.def3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilder.java41
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelConfigTransformer.java73
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelIdResolver.java51
-rw-r--r--config-model/src/test/cfg/application/embed/configdefinitions/embedding.bert-base-embedder.def30
-rw-r--r--config-model/src/test/cfg/application/embed/services.xml2
-rw-r--r--config-model/src/test/cfg/application/embed_generic/configdefinitions/sentence-embedder.def9
-rw-r--r--config-model/src/test/cfg/application/embed_generic/services.xml2
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilderTest.java4
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java105
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java23
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java15
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java219
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java69
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java3
-rw-r--r--config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java49
-rw-r--r--config/src/test/resources/configs/def-files/resolved-types.def6
-rw-r--r--configdefinitions/src/vespa/embedding.bert-base-embedder.def9
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java19
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/ClassBuilder.java2
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java11
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/DefLine.java2
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/DefParser.java2
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/DefaultValue.java18
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/InnerCNode.java6
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java11
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java18
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/MakeConfig.java4
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/NormalizedDefinition.java10
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/ReservedWords.java2
-rw-r--r--configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java7
-rw-r--r--configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java6
-rw-r--r--configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java1
-rw-r--r--configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java2
-rw-r--r--configgen/src/test/resources/allfeatures.reference99
-rw-r--r--configgen/src/test/resources/configgen.allfeatures.def3
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionContentListResponse.java1
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionHandler.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java3
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java3
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/IndexedSegmentItem.java2
-rw-r--r--model-integration/src/main/java/ai/vespa/embedding/BertBaseEmbedder.java17
-rw-r--r--model-integration/src/test/java/ai/vespa/embedding/BertBaseEmbedderTest.java7
-rw-r--r--vespajlib/src/main/java/com/yahoo/text/Utf8.java4
67 files changed, 849 insertions, 471 deletions
diff --git a/abi-check-plugin/src/main/java/com/yahoo/abicheck/mojo/AbiCheck.java b/abi-check-plugin/src/main/java/com/yahoo/abicheck/mojo/AbiCheck.java
index a0415e335f0..bbf5876b57c 100644
--- a/abi-check-plugin/src/main/java/com/yahoo/abicheck/mojo/AbiCheck.java
+++ b/abi-check-plugin/src/main/java/com/yahoo/abicheck/mojo/AbiCheck.java
@@ -193,7 +193,7 @@ public class AbiCheck extends AbstractMojo {
} else {
Map<String, JavaClassSignature> abiSpec = readSpec(specFile);
if (!compareSignatures(abiSpec, signatures, getLog())) {
- throw new MojoFailureException("ABI spec mismatch. To update run 'mvn package -Dabicheck.writeSpec'");
+ throw new MojoFailureException("ABI spec mismatch.\nTo update run 'mvn package -Dabicheck.writeSpec'");
}
}
} catch (IOException e) {
diff --git a/config-lib/abi-spec.json b/config-lib/abi-spec.json
index 45290714777..b219e58d99f 100644
--- a/config-lib/abi-spec.json
+++ b/config-lib/abi-spec.json
@@ -272,7 +272,8 @@
"public static java.util.Map asNodeMap(java.util.Map, com.yahoo.config.LeafNode)",
"public static java.util.Map asFileNodeMap(java.util.Map)",
"public static java.util.Map asPathNodeMap(java.util.Map)",
- "public static java.util.Map asUrlNodeMap(java.util.Map)"
+ "public static java.util.Map asUrlNodeMap(java.util.Map)",
+ "public static java.util.Map asModelNodeMap(java.util.Map)"
],
"fields": []
},
@@ -287,7 +288,8 @@
"public java.util.List asList()",
"public static com.yahoo.config.LeafNodeVector createFileNodeVector(java.util.Collection)",
"public static com.yahoo.config.LeafNodeVector createPathNodeVector(java.util.Collection)",
- "public static com.yahoo.config.LeafNodeVector createUrlNodeVector(java.util.Collection)"
+ "public static com.yahoo.config.LeafNodeVector createUrlNodeVector(java.util.Collection)",
+ "public static com.yahoo.config.LeafNodeVector createModelNodeVector(java.util.Collection)"
],
"fields": []
},
@@ -308,6 +310,51 @@
],
"fields": []
},
+ "com.yahoo.config.ModelNode": {
+ "superClass": "com.yahoo.config.LeafNode",
+ "interfaces": [],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>()",
+ "public void <init>(com.yahoo.config.ModelReference)",
+ "public java.lang.String getValue()",
+ "public java.lang.String toString()",
+ "protected boolean doSetValue(java.lang.String)",
+ "public com.yahoo.config.ModelReference getModelReference()",
+ "public static java.util.List toModelReferences(java.util.List)",
+ "public static java.util.Map toModelReferenceMap(java.util.Map)"
+ ],
+ "fields": []
+ },
+ "com.yahoo.config.ModelReference": {
+ "superClass": "java.lang.Object",
+ "interfaces": [],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>(java.nio.file.Path)",
+ "public void <init>(java.util.Optional, java.util.Optional, java.util.Optional)",
+ "public java.util.Optional modelId()",
+ "public java.util.Optional url()",
+ "public java.util.Optional path()",
+ "public com.yahoo.config.ModelReference withModelId(java.util.Optional)",
+ "public com.yahoo.config.ModelReference withUrl(java.util.Optional)",
+ "public com.yahoo.config.ModelReference withPath(java.util.Optional)",
+ "public java.nio.file.Path value()",
+ "public boolean equals(java.lang.Object)",
+ "public int hashCode()",
+ "public java.lang.String toString()",
+ "public static com.yahoo.config.ModelReference fromModelId(java.lang.String)",
+ "public static com.yahoo.config.ModelReference fromUrl(java.lang.String)",
+ "public static com.yahoo.config.ModelReference fromPath(java.lang.String)",
+ "public static com.yahoo.config.ModelReference valueOf(java.nio.file.Path)",
+ "public static com.yahoo.config.ModelReference valueOf(java.lang.String)"
+ ],
+ "fields": []
+ },
"com.yahoo.config.Node": {
"superClass": "java.lang.Object",
"interfaces": [],
diff --git a/config-lib/src/main/java/com/yahoo/config/FileNode.java b/config-lib/src/main/java/com/yahoo/config/FileNode.java
index e6a4af6f439..a7c1ebb1488 100644
--- a/config-lib/src/main/java/com/yahoo/config/FileNode.java
+++ b/config-lib/src/main/java/com/yahoo/config/FileNode.java
@@ -1,8 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config;
-import java.nio.file.Path;
-
/**
* Represents a 'file' in a {@link ConfigInstance}, usually a filename.
*
@@ -16,8 +14,6 @@ public class FileNode extends LeafNode<FileReference> {
public FileNode(String stringVal) {
super(true);
this.value = new FileReference(ReferenceNode.stripQuotes(stringVal));
- if (Path.of(value.value()).normalize().startsWith(".."))
- throw new IllegalArgumentException("path may not start with '..', but got: " + value.value());
}
public FileReference value() {
diff --git a/config-lib/src/main/java/com/yahoo/config/FileReference.java b/config-lib/src/main/java/com/yahoo/config/FileReference.java
index 686721e91ae..8b8434c8cc4 100755
--- a/config-lib/src/main/java/com/yahoo/config/FileReference.java
+++ b/config-lib/src/main/java/com/yahoo/config/FileReference.java
@@ -2,6 +2,7 @@
package com.yahoo.config;
import java.io.File;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -19,6 +20,8 @@ public final class FileReference {
private final String value;
public FileReference(String value) {
+ if (Path.of(value).normalize().startsWith(".."))
+ throw new IllegalArgumentException("Path may not start with '..' but got '" + value + "'");
this.value = Objects.requireNonNull(value);
}
diff --git a/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java b/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java
index 9435c09803f..82663fa8bfd 100644
--- a/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java
+++ b/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java
@@ -8,7 +8,6 @@ import java.util.stream.Collectors;
/**
* @author gjoranv
- * @since 5.1.17
*/
public class LeafNodeMaps {
@@ -68,4 +67,11 @@ public class LeafNodeMaps {
));
}
+ public static Map<String, ModelNode> asModelNodeMap(Map<String, ModelReference> modelReferenceMap) {
+ return Collections.unmodifiableMap(
+ modelReferenceMap.entrySet().stream().collect(
+ Collectors.toMap(Map.Entry::getKey, e -> new ModelNode(e.getValue()))
+ ));
+ }
+
}
diff --git a/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java b/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java
index 599385899e1..ddbed4258dc 100644
--- a/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java
+++ b/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java
@@ -13,7 +13,6 @@ import java.util.List;
* A vector of leaf nodes.
*
* @author gjoranv
- * @since 5.1.4
*/
public class LeafNodeVector<REAL, NODE extends LeafNode<REAL>> extends NodeVector<NODE> {
@@ -79,5 +78,11 @@ public class LeafNodeVector<REAL, NODE extends LeafNode<REAL>> extends NodeVecto
return new LeafNodeVector<>(files, new UrlNode());
}
+ public static LeafNodeVector<Path, ModelNode> createModelNodeVector(Collection<ModelReference> values) {
+ List<Path> modelPaths = new ArrayList<>();
+ for (ModelReference modelReference : values)
+ modelPaths.add(modelReference.value());
+ return new LeafNodeVector<>(modelPaths, new ModelNode());
+ }
}
diff --git a/config-lib/src/main/java/com/yahoo/config/ModelNode.java b/config-lib/src/main/java/com/yahoo/config/ModelNode.java
new file mode 100644
index 00000000000..2748ef8c7e9
--- /dev/null
+++ b/config-lib/src/main/java/com/yahoo/config/ModelNode.java
@@ -0,0 +1,64 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a 'model' in a {@link ConfigInstance}.
+ *
+ * @author bratseth
+ */
+public class ModelNode extends LeafNode<Path> {
+
+ private final ModelReference reference;
+
+ public ModelNode() {
+ this.value = null;
+ this.reference = null;
+ }
+
+ public ModelNode(ModelReference modelReference) {
+ super(true);
+ this.value = modelReference.value();
+ this.reference = modelReference;
+ }
+
+ @Override
+ public String getValue() {
+ return value.toString();
+ }
+
+ @Override
+ public String toString() {
+ return (value == null) ? "(null)" : '"' + getValue() + '"';
+ }
+
+ @Override
+ protected boolean doSetValue(String stringVal) {
+ throw new UnsupportedOperationException();
+ }
+
+ public ModelReference getModelReference() {
+ return reference;
+ }
+
+ public static List<ModelReference> toModelReferences(List<ModelNode> modelNodes) {
+ List<ModelReference> modelReferences = new ArrayList<>();
+ for (ModelNode modelNode : modelNodes)
+ modelReferences.add(modelNode.getModelReference());
+ return modelReferences;
+ }
+
+ public static Map<String, ModelReference> toModelReferenceMap(Map<String, ModelNode> nodeMap) {
+ Map<String, ModelReference> referenceMap = new LinkedHashMap<>();
+ for (var entry : nodeMap.entrySet()) {
+ referenceMap.put(entry.getKey(), entry.getValue().getModelReference());
+ }
+ return referenceMap;
+ }
+
+}
diff --git a/config-lib/src/main/java/com/yahoo/config/ModelReference.java b/config-lib/src/main/java/com/yahoo/config/ModelReference.java
new file mode 100644
index 00000000000..ba35812db4d
--- /dev/null
+++ b/config-lib/src/main/java/com/yahoo/config/ModelReference.java
@@ -0,0 +1,131 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * An immutable reference to a model.
+ * This is a file path when read by a client but is set in a config instance either as a
+ * path, url or id resolved to an url during deployment.
+ *
+ * @author bratseth
+ */
+public class ModelReference {
+
+ // Either: If unresolved, at least one of these are set
+ private final Optional<String> modelId;
+ private final Optional<UrlReference> url;
+ private final Optional<FileReference> path;
+
+ // Or: If resolved, this is set
+ private final Path resolved;
+
+ public ModelReference(Path resolved) {
+ this.modelId = Optional.empty();
+ this.url = Optional.empty();
+ this.path = Optional.empty();
+ this.resolved = resolved;
+ }
+
+ public ModelReference(Optional<String> modelId,
+ Optional<UrlReference> url,
+ Optional<FileReference> path) {
+ if (modelId.isEmpty() && url.isEmpty() && path.isEmpty())
+ throw new IllegalArgumentException("A model reference must have either a model id, url or path");
+ this.modelId = modelId;
+ this.url = url;
+ this.path = path;
+ this.resolved = null;
+ }
+
+ public Optional<String> modelId() { return modelId; }
+ public Optional<UrlReference> url() { return url; }
+ public Optional<FileReference> path() { return path; }
+
+ public ModelReference withModelId(Optional<String> modelId) {
+ return new ModelReference(modelId, url, path);
+ }
+
+ public ModelReference withUrl(Optional<UrlReference> url) {
+ return new ModelReference(modelId, url, path);
+ }
+
+ public ModelReference withPath(Optional<FileReference> path) {
+ return new ModelReference(modelId, url, path);
+ }
+
+ /** Returns the path to the file containing this model, or null if not available. */
+ public Path value() {
+ if (resolved != null)
+ return resolved;
+
+ if (url.isPresent() && new File(url.get().value()).exists())
+ return Path.of(url.get().value());
+ if (path.isPresent())
+ return Path.of(path.get().value());
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( ! (o instanceof ModelReference other)) return false;
+ if ( ! this.modelId.equals(other.modelId)) return false;
+ if ( ! this.url.equals(other.url)) return false;
+ if ( ! this.path.equals(other.path)) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(modelId, url, path);
+ }
+
+ /** Returns this on the format accepted by valueOf */
+ @Override
+ public String toString() {
+ return modelId.orElse("") + " " +
+ url.map(v -> v.value()).orElse("") + " " +
+ path.map(v -> v.value()).orElse("");
+ }
+
+ /** Creates a model reference having a model id only. */
+ public static ModelReference fromModelId(String modelId) {
+ return new ModelReference(Optional.of(modelId), Optional.empty(), Optional.empty());
+ }
+
+ /** Creates a model reference having a url only. */
+ public static ModelReference fromUrl(String url) {
+ return new ModelReference(Optional.empty(), Optional.of(new UrlReference(url)), Optional.empty());
+ }
+
+ /** Creates a model reference having a path only. */
+ public static ModelReference fromPath(String path) {
+ return new ModelReference(Optional.empty(), Optional.empty(), Optional.of(new FileReference(path)));
+ }
+
+ /** Creates a model reference resolved to a Path to the local file. */
+ public static ModelReference valueOf(Path path) {
+ return new ModelReference(path);
+ }
+
+ /**
+ * Creates a model reference from a three-part string on the form
+ * <code>modelId url path</code>
+ * Each of the elements are either a value not containing space, or empty represented by "".
+ */
+ public static ModelReference valueOf(String s) {
+ String[] parts = s.split(" ");
+ if (parts.length == 1)
+ return new ModelReference(Path.of(s));
+ else if (parts.length == 3)
+ return new ModelReference(parts[0].equals("") ? Optional.empty() : Optional.of(parts[0]),
+ parts[1].equals("") ? Optional.empty() : Optional.of(new UrlReference(parts[1])),
+ parts[2].equals("") ? Optional.empty() : Optional.of(new FileReference(parts[2])));
+ else
+ throw new IllegalArgumentException("Unexpected model string '" + s + "'");
+ }
+
+}
diff --git a/config-lib/src/main/java/com/yahoo/config/PathNode.java b/config-lib/src/main/java/com/yahoo/config/PathNode.java
index ea4c657af8c..10100d374d6 100644
--- a/config-lib/src/main/java/com/yahoo/config/PathNode.java
+++ b/config-lib/src/main/java/com/yahoo/config/PathNode.java
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config;
-import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -24,8 +23,6 @@ public class PathNode extends LeafNode<Path> {
public PathNode(FileReference fileReference) {
super(true);
this.value = Path.of(fileReference.value());
- if (value.normalize().toString().startsWith(".."))
- throw new IllegalArgumentException("path may not start with '..', but got: " + value);
this.fileReference = fileReference;
}
diff --git a/config-lib/src/main/java/com/yahoo/config/UrlReference.java b/config-lib/src/main/java/com/yahoo/config/UrlReference.java
index 1adab8aaa53..d7a74165896 100755
--- a/config-lib/src/main/java/com/yahoo/config/UrlReference.java
+++ b/config-lib/src/main/java/com/yahoo/config/UrlReference.java
@@ -11,6 +11,7 @@ import java.util.Objects;
*/
public final class UrlReference {
+ /** Either the url or, if downloaded, the absolute path to the downloaded file. */
private final String value;
public UrlReference(String value) {
diff --git a/config-lib/src/test/java/com/yahoo/config/BooleanNodeTest.java b/config-lib/src/test/java/com/yahoo/config/BooleanNodeTest.java
index 50d71ba50e9..4d6b39f3976 100644
--- a/config-lib/src/test/java/com/yahoo/config/BooleanNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/BooleanNodeTest.java
@@ -8,9 +8,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Ulf Lilleengen
- * @since 5.1
*/
public class BooleanNodeTest {
+
@Test
void testSetValue() {
BooleanNode n = new BooleanNode();
@@ -21,4 +21,5 @@ public class BooleanNodeTest {
assertFalse(n.doSetValue("FALSEa"));
assertFalse(n.doSetValue("aFALSE"));
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java
index f05baeff08c..d1cd7678911 100644
--- a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java
@@ -15,6 +15,7 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import static com.yahoo.foo.StructtypesConfig.Simple.Gender.Enum.FEMALE;
import static com.yahoo.test.FunctionTestConfig.BasicStruct;
@@ -34,10 +35,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author gjoranv
- * @since 5.1.11
*/
-public class ConfigInstanceBuilderTest
-{
+public class ConfigInstanceBuilderTest {
@Test
void struct_values_can_be_set_without_declaring_a_new_struct_builder() {
@@ -170,6 +169,9 @@ public class ConfigInstanceBuilderTest
fileVal("etc").
pathVal(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))).
urlVal(new UrlReference("http://docs.vespa.ai")).
+ modelVal(new ModelReference(Optional.empty(),
+ Optional.empty(),
+ Optional.of(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))))).
boolarr(false).
longarr(9223372036854775807L).
longarr(-9223372036854775808L).
@@ -408,4 +410,5 @@ public class ConfigInstanceBuilderTest
report.toString().contains("function-test.myStructMap{one} with value \n")
);
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java
index 1584293a137..1a05c08d8f2 100644
--- a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java
@@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.Arrays;
+import java.util.Optional;
import static com.yahoo.test.FunctionTestConfig.BasicStruct;
import static com.yahoo.test.FunctionTestConfig.Enum_val;
@@ -18,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class ConfigInstanceEqualsTest {
+
FunctionTestConfig config1;
FunctionTestConfig.Builder builder2;
FunctionTestConfig config2;
@@ -130,6 +132,9 @@ public class ConfigInstanceEqualsTest {
fileVal("etc").
pathVal(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))).
urlVal(new UrlReference("http://docs.vespa.ai")).
+ modelVal(new ModelReference(Optional.of("my-model-id"),
+ Optional.of(new UrlReference("http://docs.vespa.ai")),
+ Optional.empty())).
boolarr(false).
longarr(9223372036854775807L).
longarr(-9223372036854775808L).
@@ -140,6 +145,9 @@ public class ConfigInstanceEqualsTest {
refarr(Arrays.asList(":parent:", ":parent", "parent:")). // test collection based setter
fileArr("bin").
urlArr(new UrlReference("http://docs.vespa.ai")).
+ modelArr(new ModelReference(Optional.empty(),
+ Optional.of(new UrlReference("http://docs.vespa.ai")),
+ Optional.of(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))))).
basicStruct(new BasicStruct.Builder().
foo("basicFoo").
@@ -183,4 +191,5 @@ public class ConfigInstanceEqualsTest {
b(-2)));
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/DoubleNodeTest.java b/config-lib/src/test/java/com/yahoo/config/DoubleNodeTest.java
index 475a33104b0..ae9894041f9 100644
--- a/config-lib/src/test/java/com/yahoo/config/DoubleNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/DoubleNodeTest.java
@@ -10,9 +10,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Ulf Lilleengen
- * @since 5.1
*/
public class DoubleNodeTest {
+
@Test
void testSetValue() {
DoubleNode n = new DoubleNode();
@@ -20,4 +20,5 @@ public class DoubleNodeTest {
assertTrue(n.doSetValue("3.14"));
assertEquals(3.14, n.value(), 0.001);
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/EnumNodeTest.java b/config-lib/src/test/java/com/yahoo/config/EnumNodeTest.java
index e7723409736..d53db9fa9c7 100644
--- a/config-lib/src/test/java/com/yahoo/config/EnumNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/EnumNodeTest.java
@@ -12,6 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* @author Ulf Lilleengen
*/
public class EnumNodeTest {
+
private static class MyNode extends EnumNode<MyNode.Enum> {
public enum Enum { ONE, TWO }
public final static Enum ONE = Enum.ONE;
@@ -39,4 +40,5 @@ public class EnumNodeTest {
assertEquals("ONE", n.toString());
assertFalse(n.doSetValue("THREE"));
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/FileNodeTest.java b/config-lib/src/test/java/com/yahoo/config/FileNodeTest.java
index 8bec9378f8f..49796c795a9 100644
--- a/config-lib/src/test/java/com/yahoo/config/FileNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/FileNodeTest.java
@@ -9,7 +9,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Ulf Lilleengen
- * @since 5.1
*/
public class FileNodeTest {
@@ -23,7 +22,7 @@ public class FileNodeTest {
assertEquals("foo.txt", n.value().value());
assertEquals("\"foo.txt\"", n.toString());
- assertEquals("path may not start with '..', but got: foo/../../boo",
+ assertEquals("Path may not start with '..' but got 'foo/../../boo'",
assertThrows(IllegalArgumentException.class, () -> new FileNode("foo/../../boo")).getMessage());
}
diff --git a/config-lib/src/test/java/com/yahoo/config/IntegerNodeTest.java b/config-lib/src/test/java/com/yahoo/config/IntegerNodeTest.java
index a195a5f65fb..4081192d2e8 100644
--- a/config-lib/src/test/java/com/yahoo/config/IntegerNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/IntegerNodeTest.java
@@ -9,9 +9,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Ulf Lilleengen
- * @since 5.1
*/
public class IntegerNodeTest {
+
@Test
void testSetValue() {
IntegerNode n = new IntegerNode();
@@ -19,4 +19,5 @@ public class IntegerNodeTest {
assertTrue(n.setValue("10"));
assertEquals(10, n.value().intValue());
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/LongNodeTest.java b/config-lib/src/test/java/com/yahoo/config/LongNodeTest.java
index dc6d59bbc46..9e021edd3a8 100644
--- a/config-lib/src/test/java/com/yahoo/config/LongNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/LongNodeTest.java
@@ -9,9 +9,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Ulf Lilleengen
- * @since 5.1
*/
public class LongNodeTest {
+
@Test
void testSetValue() {
LongNode n = new LongNode();
@@ -19,4 +19,5 @@ public class LongNodeTest {
assertTrue(n.setValue("10"));
assertEquals(10L, n.value().longValue());
}
+
}
diff --git a/config-lib/src/test/java/com/yahoo/config/ModelNodeTest.java b/config-lib/src/test/java/com/yahoo/config/ModelNodeTest.java
new file mode 100644
index 00000000000..696e0722714
--- /dev/null
+++ b/config-lib/src/test/java/com/yahoo/config/ModelNodeTest.java
@@ -0,0 +1,29 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author bratseth
+ */
+public class ModelNodeTest {
+
+ @Test
+ void testEmpty() {
+ assertEquals("(null)", new ModelNode().toString());
+ }
+
+ @Test
+ void testReference() {
+ var reference = new ModelReference(Optional.of("myModelId"),
+ Optional.of(new UrlReference("https://host:my/path")),
+ Optional.of(new FileReference("foo.txt")));
+ assertEquals("myModelId https://host:my/path foo.txt", reference.toString());
+ assertEquals(reference, ModelReference.valueOf(reference.toString()));
+ }
+
+}
diff --git a/config-lib/src/test/java/com/yahoo/config/NodeVectorTest.java b/config-lib/src/test/java/com/yahoo/config/NodeVectorTest.java
index e6b3b4b6a71..fb751931062 100644
--- a/config-lib/src/test/java/com/yahoo/config/NodeVectorTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/NodeVectorTest.java
@@ -12,7 +12,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author Ulf Lilleengen
- * @since 5.1
*/
public class NodeVectorTest {
diff --git a/config-lib/src/test/java/com/yahoo/config/PathNodeTest.java b/config-lib/src/test/java/com/yahoo/config/PathNodeTest.java
index ad8f5e2e65f..622466d95a2 100644
--- a/config-lib/src/test/java/com/yahoo/config/PathNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/PathNodeTest.java
@@ -10,7 +10,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author gjoranv
- * @since 5.1.28
*/
public class PathNodeTest {
@@ -22,7 +21,7 @@ public class PathNodeTest {
n = new PathNode(new FileReference("foo.txt"));
assertEquals(new File("foo.txt").toPath(), n.value());
- assertEquals("path may not start with '..', but got: foo/../../boo",
+ assertEquals("Path may not start with '..' but got 'foo/../../boo'",
assertThrows(IllegalArgumentException.class, () -> new PathNode(new FileReference("foo/../../boo"))).getMessage());
}
diff --git a/config-lib/src/test/java/com/yahoo/config/StringNodeTest.java b/config-lib/src/test/java/com/yahoo/config/StringNodeTest.java
index d0baf8d1837..3470c96bbcc 100644
--- a/config-lib/src/test/java/com/yahoo/config/StringNodeTest.java
+++ b/config-lib/src/test/java/com/yahoo/config/StringNodeTest.java
@@ -8,7 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author hmusum
- * @since 5.1.7
*/
public class StringNodeTest {
diff --git a/config-lib/src/test/resources/configdefinitions/test.function-test.def b/config-lib/src/test/resources/configdefinitions/test.function-test.def
index f6a997daf77..cdd4bf012d2 100644
--- a/config-lib/src/test/resources/configdefinitions/test.function-test.def
+++ b/config-lib/src/test/resources/configdefinitions/test.function-test.def
@@ -45,6 +45,7 @@ refwithdef reference default=":parent:" restart
fileVal file restart
pathVal path restart
urlVal url
+modelVal model
boolarr[] bool restart
intarr[] int restart
@@ -56,6 +57,7 @@ refarr[] reference restart
fileArr[] file restart
pathArr[] path restart
urlArr[] url
+modelArr[] model
#This is a map of ints.
intMap{} int restart
@@ -63,6 +65,7 @@ stringMap{} string restart
filemap{} file restart
pathMap{} path restart
urlMap{} url
+modelMap{} model
# A basic struct
basicStruct.foo string default="basic" restart
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilder.java
index 7ff01cbf82e..9390986c0c4 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilder.java
@@ -52,19 +52,19 @@ public class DomConfigPayloadBuilder {
public static ConfigDefinitionKey parseConfigName(Element configE) {
if (!configE.getNodeName().equals("config")) {
- throw new ConfigurationRuntimeException("The root element must be 'config', but was '" + configE.getNodeName() + "'.");
+ throw new ConfigurationRuntimeException("The root element must be 'config', but was '" + configE.getNodeName() + "'");
}
if (!configE.hasAttribute("name")) {
throw new ConfigurationRuntimeException
- ("The 'config' element must have a 'name' attribute that matches the name of the config definition.");
+ ("The 'config' element must have a 'name' attribute that matches the name of the config definition");
}
String elementString = configE.getAttribute("name");
if (!elementString.contains(".")) {
throw new ConfigurationRuntimeException("The config name '" + elementString +
- "' contains illegal characters. Only names with the pattern " +
- namespacePattern.pattern() + "." + namePattern.pattern() + " are legal.");
+ "' contains illegal characters. Only names with the pattern " +
+ namespacePattern.pattern() + "." + namePattern.pattern() + " are legal.");
}
Tuple2<String, String> t = ConfigUtils.getNameAndNamespaceFromString(elementString);
@@ -73,28 +73,26 @@ public class DomConfigPayloadBuilder {
if (!validName(xmlName)) {
throw new ConfigurationRuntimeException("The config name '" + xmlName +
- "' contains illegal characters. Only names with the pattern " + namePattern.toString() + " are legal.");
+ "' contains illegal characters. Only names with the pattern " +
+ namePattern.toString() + " are legal.");
}
if (!validNamespace(xmlNamespace)) {
throw new ConfigurationRuntimeException("The config namespace '" + xmlNamespace +
- "' contains illegal characters. Only namespaces with the pattern " + namespacePattern.toString() + " are legal.");
+ "' contains illegal characters. Only namespaces with the pattern " +
+ namespacePattern.toString() + " are legal.");
}
return new ConfigDefinitionKey(xmlName, xmlNamespace);
}
private static boolean validName(String name) {
if (name == null) return false;
-
- Matcher m = namePattern.matcher(name);
- return m.matches();
+ return namePattern.matcher(name).matches();
}
private static boolean validNamespace(String namespace) {
if (namespace == null) return false;
-
- Matcher m = namespacePattern.matcher(namespace);
- return m.matches();
+ return namespacePattern.matcher(namespace).matches();
}
private String extractName(Element element) {
@@ -118,12 +116,11 @@ public class DomConfigPayloadBuilder {
return buf.toString();
}
- /**
- * Parse leaf value in an xml tree
- */
+ /** Parse leaf value in an xml tree. */
private void parseLeaf(Element element, ConfigPayloadBuilder payloadBuilder, String parentName) {
String name = extractName(element);
String value = XML.getValue(element);
+ var definition = payloadBuilder.getConfigDefinition();
if (value == null) {
throw new ConfigurationRuntimeException("Element '" + name + "' must have either children or a value");
}
@@ -136,8 +133,14 @@ public class DomConfigPayloadBuilder {
} else {
payloadBuilder.getArray(parentName).append(value);
}
- } else {
- // leaf scalar, e.g. <intVal>3</intVal>
+ }
+ else if (definition != null && definition.getModelDefs().containsKey(name)) { // model field special syntax
+ String modelString = XML.attribute("model-id", element).orElse("\"\"");
+ modelString += " " + XML.attribute("url", element).orElse("\"\"");
+ modelString += " " + XML.attribute("path", element).orElse("\"\"");
+ payloadBuilder.setField(name, modelString);
+ }
+ else { // leaf value: <myValueName>value</myValue>
payloadBuilder.setField(name, value);
}
}
@@ -196,8 +199,8 @@ public class DomConfigPayloadBuilder {
parseComplex(currElem, children, payloadBuilder, parentName);
}
} catch (Exception exception) {
- throw new ConfigurationRuntimeException("Error parsing element at " + XML.getNodePath(currElem, " > ") + ": " +
- Exceptions.toMessageString(exception));
+ throw new ConfigurationRuntimeException("Error parsing element at " + XML.getNodePath(currElem, " > ") +
+ ": " + Exceptions.toMessageString(exception));
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 1cf73c1ed03..0bf586a089f 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -957,7 +957,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private static void addConfiguredComponents(DeployState deployState, ContainerCluster<? extends Container> cluster,
Element parent, String componentName) {
for (Element component : XML.getChildren(parent, componentName)) {
- component = ModelConfigTransformer.transform(deployState, component);
+ ModelIdResolver.resolveModelIds(component, deployState.isHosted());
cluster.addComponent(new DomComponentBuilder().build(deployState, cluster, component));
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelConfigTransformer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelConfigTransformer.java
deleted file mode 100644
index 0065a582145..00000000000
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelConfigTransformer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.model.container.xml;
-
-import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.text.XML;
-import org.w3c.dom.Element;
-
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Translates model references in component configs.
- *
- * @author lesters
- * @author bratseth
- */
-public class ModelConfigTransformer {
-
- private static final Map<String, String> providedModels =
- Map.of("minilm-l6-v2", "https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx",
- "bert-base-uncased", "https://data.vespa.oath.cloud/onnx_models/bert-base-uncased-vocab.txt");
-
- // Until we have optional path parameters, use services.xml as it is guaranteed to exist
- private final static String dummyPath = "services.xml";
-
- /**
- * Transforms the &lt;embedder ...&gt; element to component configuration.
- *
- * @param deployState the deploy state - as config generation can depend on context
- * @param component the XML element containing the &lt;embedder ...&gt;
- * @return a new XML element containting the &lt;component ...&gt; configuration
- */
- public static Element transform(DeployState deployState, Element component) {
- for (Element config : XML.getChildren(component, "config")) {
- for (Element value : XML.getChildren(config))
- transformModelValue(value, config, deployState.isHosted());
- }
- return component;
- }
-
- /** Expans a model config value into regular config values. */
- private static void transformModelValue(Element value, Element config, boolean hosted) {
- if (value.hasAttribute("path")) {
- addChild(value.getTagName() + "Url", "", config);
- addChild(value.getTagName() + "Path", value.getAttribute("path"), config);
- config.removeChild(value);
- }
- else if (value.hasAttribute("id") && hosted) {
- addChild(value.getTagName() + "Url", modelIdToUrl(value.getAttribute("id")), config);
- addChild(value.getTagName() + "Path", dummyPath, config);
- config.removeChild(value);
- }
- else if (value.hasAttribute("url")) {
- addChild(value.getTagName() + "Url", value.getAttribute("url"), config);
- addChild(value.getTagName() + "Path", dummyPath, config);
- config.removeChild(value);
- }
- }
-
- private static void addChild(String name, String value, Element parent) {
- Element element = parent.getOwnerDocument().createElement(name);
- element.setTextContent(value);
- parent.appendChild(element);
- }
-
- private static String modelIdToUrl(String id) {
- if ( ! providedModels.containsKey(id))
- throw new IllegalArgumentException("Unknown embedder model '" + id + "'. Available models are [" +
- providedModels.keySet().stream().sorted().collect(Collectors.joining(", ")) + "]");
- return providedModels.get(id);
- }
-
-}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelIdResolver.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelIdResolver.java
new file mode 100644
index 00000000000..463832ea263
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ModelIdResolver.java
@@ -0,0 +1,51 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.xml;
+
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.text.XML;
+import org.w3c.dom.Element;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Replaces model id references in configs by their url.
+ *
+ * @author lesters
+ * @author bratseth
+ */
+public class ModelIdResolver {
+
+ private static final Map<String, String> providedModels =
+ Map.of("minilm-l6-v2", "https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx",
+ "bert-base-uncased", "https://data.vespa.oath.cloud/onnx_models/bert-base-uncased-vocab.txt");
+
+ /**
+ * Finds any config values of type 'model' below the given config element and
+ * supplies the url attribute of them if a model id is specified and hosted is true
+ * (regardless of whether an url is already specified).
+ *
+ * @param component the XML element of any component
+ */
+ public static void resolveModelIds(Element component, boolean hosted) {
+ if ( ! hosted) return;
+ for (Element config : XML.getChildren(component, "config")) {
+ for (Element value : XML.getChildren(config))
+ transformModelValue(value);
+ }
+ }
+
+ /** Expands a model config value into regular config values. */
+ private static void transformModelValue(Element value) {
+ if ( ! value.hasAttribute("model-id")) return;
+ value.setAttribute("url", modelIdToUrl(value.getTagName(), value.getAttribute("model-id")));
+ }
+
+ private static String modelIdToUrl(String valueName, String modelId) {
+ if ( ! providedModels.containsKey(modelId))
+ throw new IllegalArgumentException("Unknown model id '" + modelId + "' on '" + valueName + "'. Available models are [" +
+ providedModels.keySet().stream().sorted().collect(Collectors.joining(", ")) + "]");
+ return providedModels.get(modelId);
+ }
+
+}
diff --git a/config-model/src/test/cfg/application/embed/configdefinitions/embedding.bert-base-embedder.def b/config-model/src/test/cfg/application/embed/configdefinitions/embedding.bert-base-embedder.def
new file mode 100644
index 00000000000..144dfbd0001
--- /dev/null
+++ b/config-model/src/test/cfg/application/embed/configdefinitions/embedding.bert-base-embedder.def
@@ -0,0 +1,30 @@
+# Copy of this Vespa config stored here because Vespa config definitions are not
+# available in unit tests, and are needed (by DomConfigPayloadBuilder.parseLeaf)
+# Alternatively, we could make that not need it as it is not strictly necessaery.
+
+namespace=embedding
+
+# Wordpiece tokenizer
+tokenizerVocab model
+
+transformerModel model
+
+# Max length of token sequence model can handle
+transformerMaxTokens int default=384
+
+# Pooling strategy
+poolingStrategy enum { cls, mean } default=mean
+
+# Input names
+transformerInputIds string default=input_ids
+transformerAttentionMask string default=attention_mask
+transformerTokenTypeIds string default=token_type_ids
+
+# Output name
+transformerOutput string default=output_0
+
+# Settings for ONNX model evaluation
+onnxExecutionMode enum { parallel, sequential } default=sequential
+onnxInterOpThreads int default=1
+onnxIntraOpThreads int default=-4 # n=number of threads -> n<0: CPUs/(-n), n==0: CPUs, n>0: n
+
diff --git a/config-model/src/test/cfg/application/embed/services.xml b/config-model/src/test/cfg/application/embed/services.xml
index 88558ace4bf..cdbcfd67f02 100644
--- a/config-model/src/test/cfg/application/embed/services.xml
+++ b/config-model/src/test/cfg/application/embed/services.xml
@@ -7,7 +7,7 @@
<component id="transformer" class="ai.vespa.embedding.BertBaseEmbedder" bindle="model-integration">
<config name="embedding.bert-base-embedder">
<!-- model specifics -->
- <transformerModel id="minilm-l6-v2" url="application-url"/>
+ <transformerModel model-id="minilm-l6-v2" url="application-url"/>
<tokenizerVocab path="files/vocab.txt"/>
<!-- tunable parameters: number of threads etc -->
diff --git a/config-model/src/test/cfg/application/embed_generic/configdefinitions/sentence-embedder.def b/config-model/src/test/cfg/application/embed_generic/configdefinitions/sentence-embedder.def
index 81fc88dbf01..87b80f1051a 100644
--- a/config-model/src/test/cfg/application/embed_generic/configdefinitions/sentence-embedder.def
+++ b/config-model/src/test/cfg/application/embed_generic/configdefinitions/sentence-embedder.def
@@ -1,12 +1,9 @@
package=ai.vespa.example.paragraph
-# Settings for wordpiece tokenizer
-vocabPath path
-vocabUrl string
+# WordPiece tokenizer vocabulary
+vocab model
-# Transformer model settings
-modelPath path
-modelUrl string
+model model
myValue string
diff --git a/config-model/src/test/cfg/application/embed_generic/services.xml b/config-model/src/test/cfg/application/embed_generic/services.xml
index ea430f24e2f..d2c22c03343 100644
--- a/config-model/src/test/cfg/application/embed_generic/services.xml
+++ b/config-model/src/test/cfg/application/embed_generic/services.xml
@@ -8,7 +8,7 @@
class='ai.vespa.example.paragraph.ApplicationSpecificEmbedder'
bundle='exampleEmbedder'>
<config name='ai.vespa.example.paragraph.sentence-embedder'>
- <model id="minilm-l6-v2" url="application-url" />
+ <model model-id="minilm-l6-v2" url="application-url" />
<vocab path="files/vocab.txt"/>
<myValue>foo</myValue>
</config>
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilderTest.java
index 88af584de90..e788fe5fc54 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/builder/xml/dom/DomConfigPayloadBuilderTest.java
@@ -130,7 +130,7 @@ public class DomConfigPayloadBuilderTest {
new DomConfigPayloadBuilder(null).build(configRoot);
fail("Expected exception for wrong tag name.");
} catch (ConfigurationRuntimeException e) {
- assertEquals("The root element must be 'config', but was 'configs'.", e.getMessage());
+ assertEquals("The root element must be 'config', but was 'configs'", e.getMessage());
}
}
@@ -142,7 +142,7 @@ public class DomConfigPayloadBuilderTest {
new DomConfigPayloadBuilder(null).build(configRoot);
fail("Expected exception for mismatch between def-name and xml name attribute.");
} catch (ConfigurationRuntimeException e) {
- assertEquals("The 'config' element must have a 'name' attribute that matches the name of the config definition.", e.getMessage());
+ assertEquals("The 'config' element must have a 'name' attribute that matches the name of the config definition", e.getMessage());
}
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java
index ffa7e52136f..60386be17db 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java
@@ -28,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.fail;
public class EmbedderTestCase {
- private static final String emptyPathFileName = "services.xml";
private static final String BUNDLED_EMBEDDER_CLASS = "ai.vespa.embedding.BertBaseEmbedder";
private static final String BUNDLED_EMBEDDER_CONFIG = "embedding.bert-base-embedder";
@@ -42,29 +41,8 @@ public class EmbedderTestCase {
"</component>";
String component = "<component id='test' class='" + BUNDLED_EMBEDDER_CLASS + "' bundle='model-integration'>" +
" <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModelUrl>my-model-url</transformerModelUrl>" +
- " <transformerModelPath>services.xml</transformerModelPath>" +
- " <tokenizerVocabUrl>my-vocab-url</tokenizerVocabUrl>" +
- " <tokenizerVocabPath>services.xml</tokenizerVocabPath>" +
- " </config>" +
- "</component>";
- assertTransform(input, component, false);
- }
-
- @Test
- void testPathHasPriority_selfhosted() throws IOException, SAXException {
- String input = "<component id='test' class='" + BUNDLED_EMBEDDER_CLASS + "' bundle='model-integration'>" +
- " <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModel id='my_model_id' url='my-model-url' path='files/model.onnx' />" +
- " <tokenizerVocab id='my_vocab_id' url='my-vocab-url' path='files/vocab.txt' />" +
- " </config>" +
- "</component>";
- String component = "<component id='test' class='" + BUNDLED_EMBEDDER_CLASS + "' bundle='model-integration'>" +
- " <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModelUrl></transformerModelUrl>" +
- " <transformerModelPath>files/model.onnx</transformerModelPath>" +
- " <tokenizerVocabUrl></tokenizerVocabUrl>" +
- " <tokenizerVocabPath>files/vocab.txt</tokenizerVocabPath>" +
+ " <transformerModel id='my_model_id' url='my-model-url' />" +
+ " <tokenizerVocab id='my_vocab_id' url='my-vocab-url' />" +
" </config>" +
"</component>";
assertTransform(input, component, false);
@@ -74,35 +52,31 @@ public class EmbedderTestCase {
void testBundledEmbedder_hosted() throws IOException, SAXException {
String input = "<component id='test' class='" + BUNDLED_EMBEDDER_CLASS + "' bundle='model-integration'>" +
" <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModel id='minilm-l6-v2' />" +
- " <tokenizerVocab id='bert-base-uncased' />" +
+ " <transformerModel model-id='minilm-l6-v2' />" +
+ " <tokenizerVocab model-id='bert-base-uncased' />" +
" </config>" +
"</component>";
String component = "<component id='test' class='" + BUNDLED_EMBEDDER_CLASS + "' bundle='model-integration'>" +
" <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModelUrl>https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx</transformerModelUrl>" +
- " <transformerModelPath>services.xml</transformerModelPath>" +
- " <tokenizerVocabUrl>https://data.vespa.oath.cloud/onnx_models/bert-base-uncased-vocab.txt</tokenizerVocabUrl>" +
- " <tokenizerVocabPath>services.xml</tokenizerVocabPath>" +
+ " <transformerModel model-id='minilm-l6-v2' url='https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx' />" +
+ " <tokenizerVocab model-id='bert-base-uncased' url='https://data.vespa.oath.cloud/onnx_models/bert-base-uncased-vocab.txt' />" +
" </config>" +
"</component>";
assertTransform(input, component, true);
}
@Test
- void testApplicationEmbedderWithBundledConfig_hosted() throws IOException, SAXException {
+ void testApplicationComponentWithModelReference_hosted() throws IOException, SAXException {
String input = "<component id='test' class='ApplicationSpecificEmbedder' bundle='model-integration'>" +
" <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModel id='minilm-l6-v2' />" +
- " <tokenizerVocab id='bert-base-uncased' />" +
+ " <transformerModel model-id='minilm-l6-v2' />" +
+ " <tokenizerVocab model-id='bert-base-uncased' />" +
" </config>" +
"</component>";
String component = "<component id='test' class='ApplicationSpecificEmbedder' bundle='model-integration'>" +
" <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModelUrl>https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx</transformerModelUrl>" +
- " <transformerModelPath>services.xml</transformerModelPath>" +
- " <tokenizerVocabUrl>https://data.vespa.oath.cloud/onnx_models/bert-base-uncased-vocab.txt</tokenizerVocabUrl>" +
- " <tokenizerVocabPath>services.xml</tokenizerVocabPath>" +
+ " <transformerModel model-id='minilm-l6-v2' url='https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx' />" +
+ " <tokenizerVocab model-id='bert-base-uncased' url='https://data.vespa.oath.cloud/onnx_models/bert-base-uncased-vocab.txt' />" +
" </config>" +
"</component>";
assertTransform(input, component, true);
@@ -112,12 +86,12 @@ public class EmbedderTestCase {
void testUnknownModelId_hosted() throws IOException, SAXException {
String embedder = "<component id='test' class='" + BUNDLED_EMBEDDER_CLASS + "'>" +
" <config name='" + BUNDLED_EMBEDDER_CONFIG + "'>" +
- " <transformerModel id='my_model_id' />" +
- " <tokenizerVocab id='my_vocab_id' />" +
+ " <transformerModel model-id='my_model_id' />" +
+ " <tokenizerVocab model-id='my_vocab_id' />" +
" </config>" +
"</component>";
assertTransformThrows(embedder,
- "Unknown embedder model 'my_model_id'. " +
+ "Unknown model id 'my_model_id' on 'transformerModel'. " +
"Available models are [bert-base-uncased, minilm-l6-v2]",
true);
}
@@ -130,10 +104,8 @@ public class EmbedderTestCase {
Component<?, ?> transformer = containerCluster.getComponentsMap().get(new ComponentId("transformer"));
ConfigPayloadBuilder config = transformer.getUserConfigs().get(new ConfigDefinitionKey("bert-base-embedder", "embedding"));
- assertEquals("application-url", config.getObject("transformerModelUrl").getValue());
- assertEquals(emptyPathFileName, config.getObject("transformerModelPath").getValue());
- assertEquals("", config.getObject("tokenizerVocabUrl").getValue());
- assertEquals("files/vocab.txt", config.getObject("tokenizerVocabPath").getValue());
+ assertEquals("minilm-l6-v2 application-url \"\"", config.getObject("transformerModel").getValue());
+ assertEquals("\"\" \"\" files/vocab.txt", config.getObject("tokenizerVocab").getValue());
assertEquals("4", config.getObject("onnxIntraOpThreads").getValue());
}
@@ -145,11 +117,9 @@ public class EmbedderTestCase {
Component<?, ?> transformer = containerCluster.getComponentsMap().get(new ComponentId("transformer"));
ConfigPayloadBuilder config = transformer.getUserConfigs().get(new ConfigDefinitionKey("bert-base-embedder", "embedding"));
- assertEquals("https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx",
- config.getObject("transformerModelUrl").getValue());
- assertEquals(emptyPathFileName, config.getObject("transformerModelPath").getValue());
- assertEquals("", config.getObject("tokenizerVocabUrl").getValue());
- assertEquals("files/vocab.txt", config.getObject("tokenizerVocabPath").getValue());
+ assertEquals("minilm-l6-v2 https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx \"\"",
+ config.getObject("transformerModel").getValue());
+ assertEquals("\"\" \"\" files/vocab.txt", config.getObject("tokenizerVocab").getValue());
assertEquals("4", config.getObject("onnxIntraOpThreads").getValue());
}
@@ -161,10 +131,8 @@ public class EmbedderTestCase {
Component<?, ?> testComponent = containerCluster.getComponentsMap().get(new ComponentId("transformer"));
ConfigPayloadBuilder config = testComponent.getUserConfigs().get(new ConfigDefinitionKey("sentence-embedder", "ai.vespa.example.paragraph"));
- assertEquals("application-url", config.getObject("modelUrl").getValue());
- assertEquals(emptyPathFileName, config.getObject("modelPath").getValue());
- assertEquals("files/vocab.txt", config.getObject("vocabPath").getValue());
- assertEquals("foo", config.getObject("myValue").getValue());
+ assertEquals("minilm-l6-v2 application-url \"\"", config.getObject("model").getValue());
+ assertEquals("\"\" \"\" files/vocab.txt", config.getObject("vocab").getValue());
}
@Test
@@ -175,11 +143,9 @@ public class EmbedderTestCase {
Component<?, ?> testComponent = containerCluster.getComponentsMap().get(new ComponentId("transformer"));
ConfigPayloadBuilder config = testComponent.getUserConfigs().get(new ConfigDefinitionKey("sentence-embedder", "ai.vespa.example.paragraph"));
- assertEquals("https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx",
- config.getObject("modelUrl").getValue());
- assertEquals(emptyPathFileName, config.getObject("modelPath").getValue());
- assertEquals("files/vocab.txt", config.getObject("vocabPath").getValue());
- assertEquals("foo", config.getObject("myValue").getValue());
+ assertEquals("minilm-l6-v2 https://data.vespa.oath.cloud/onnx_models/sentence_all_MiniLM_L6_v2.onnx \"\"",
+ config.getObject("model").getValue());
+ assertEquals("\"\" \"\" files/vocab.txt", config.getObject("vocab").getValue());
}
private VespaModel loadModel(Path path, boolean hosted) throws Exception {
@@ -189,13 +155,10 @@ public class EmbedderTestCase {
return new VespaModel(state);
}
- private void assertTransform(String embedder, String component) throws IOException, SAXException {
- assertTransform(embedder, component, false);
- }
-
- private void assertTransform(String embedder, String expectedComponent, boolean hosted) throws IOException, SAXException {
- assertSpec(createElement(expectedComponent),
- ModelConfigTransformer.transform(createEmptyDeployState(hosted), createElement(embedder)));
+ private void assertTransform(String inputComponent, String expectedComponent, boolean hosted) throws IOException, SAXException {
+ Element component = createElement(inputComponent);
+ ModelIdResolver.resolveModelIds(component, hosted);
+ assertSpec(createElement(expectedComponent), component);
}
private void assertSpec(Element e1, Element e2) {
@@ -209,8 +172,9 @@ public class EmbedderTestCase {
private void assertAttributes(Element e1, Element e2) {
NamedNodeMap map = e1.getAttributes();
for (int i = 0; i < map.getLength(); ++i) {
- String attr = map.item(i).getNodeName();
- assertEquals(e1.getAttribute(attr), e2.getAttribute(attr));
+ String attribute = map.item(i).getNodeName();
+ assertEquals(e1.getAttribute(attribute), e2.getAttribute(attribute),
+ "Attribute '" + attribute + "' is equal");
}
}
@@ -227,7 +191,7 @@ public class EmbedderTestCase {
private void assertTransformThrows(String embedder, String expectedMessage, boolean hosted) throws IOException, SAXException {
try {
- ModelConfigTransformer.transform(createEmptyDeployState(hosted), createElement(embedder));
+ ModelIdResolver.resolveModelIds(createElement(embedder), hosted);
fail("Expected exception was not thrown: " + expectedMessage);
} catch (IllegalArgumentException e) {
assertEquals(expectedMessage, e.getMessage());
@@ -239,9 +203,4 @@ public class EmbedderTestCase {
return (Element) doc.getFirstChild();
}
- private DeployState createEmptyDeployState(boolean hosted) {
- TestProperties properties = new TestProperties().setHostedVespa(hosted);
- return new DeployState.Builder().properties(properties).build();
- }
-
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java
index 96046e64c1a..9d9e43de130 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java
@@ -28,7 +28,7 @@ public class ConfigDefinition {
private final String namespace;
ConfigDefinition parent = null;
- // TODO Strings without default are null, could be not OK.
+ // TODO: Strings without default are null, could be not OK.
private final Map<String, StringDef> stringDefs = new LinkedHashMap<>();
private final Map<String, BoolDef> boolDefs = new LinkedHashMap<>();
private final Map<String, IntDef> intDefs = new LinkedHashMap<>();
@@ -39,6 +39,7 @@ public class ConfigDefinition {
private final Map<String, FileDef> fileDefs = new LinkedHashMap<>();
private final Map<String, PathDef> pathDefs = new LinkedHashMap<>();
private final Map<String, UrlDef> urlDefs = new LinkedHashMap<>();
+ private final Map<String, ModelDef> modelDefs = new LinkedHashMap<>();
private final Map<String, StructDef> structDefs = new LinkedHashMap<>();
private final Map<String, InnerArrayDef> innerArrayDefs = new LinkedHashMap<>();
private final Map<String, ArrayDef> arrayDefs = new LinkedHashMap<>();
@@ -99,6 +100,8 @@ public class ConfigDefinition {
verifyPath(id);
} else if (urlDefs.containsKey(id)) {
verifyUrl(id);
+ } else if (modelDefs.containsKey(id)) {
+ verifyModel(id);
} else if (boolDefs.containsKey(id)) {
verifyBool(id, val);
} else if (intDefs.containsKey(id)) {
@@ -550,6 +553,11 @@ public class ConfigDefinition {
}
}
+ /** A value which may be either an url or a path. */
+ public static class ModelDef {
+
+ }
+
public void addEnumDef(String id, EnumDef def) {
enumDefs.put(id, def);
}
@@ -655,6 +663,10 @@ public class ConfigDefinition {
urlDefs.put(url, new UrlDef(defVal));
}
+ public void addModelDef(String modelName) {
+ modelDefs.put(modelName, new ModelDef());
+ }
+
public void addUrlDef(String url) {
urlDefs.put(url, new UrlDef(null));
}
@@ -689,6 +701,10 @@ public class ConfigDefinition {
public Map<String, PathDef> getPathDefs() { return pathDefs; }
+ public Map<String, UrlDef> getUrlDefs() { return urlDefs; }
+
+ public Map<String, ModelDef> getModelDefs() { return modelDefs; }
+
public Map<String, InnerArrayDef> getInnerArrayDefs() {
return innerArrayDefs;
}
@@ -857,6 +873,11 @@ public class ConfigDefinition {
throw new IllegalArgumentException("No such url in " + verifyWarning(id));
}
+ private void verifyModel(String field) {
+ if ( ! modelDefs.containsKey(field))
+ throw new IllegalArgumentException("No such model in " + verifyWarning(field));
+ }
+
private void verifyBool(String id) {
if ( ! boolDefs.containsKey(id))
throw new IllegalArgumentException("No such bool in " + verifyWarning(id));
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java
index f6493c3514e..da5048a99e8 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java
@@ -69,41 +69,37 @@ public class ConfigDefinitionBuilder {
addNode(def, (LeafCNode.PathLeaf) node);
} else if (node instanceof LeafCNode.UrlLeaf) {
addNode(def, (LeafCNode.UrlLeaf) node);
+ } else if (node instanceof LeafCNode.ModelLeaf) {
+ addNode(def, (LeafCNode.ModelLeaf) node);
} else if (node instanceof LeafCNode.StringLeaf) {
addNode(def, (LeafCNode.StringLeaf) node);
} else if (node instanceof LeafCNode.EnumLeaf) {
addNode(def, (LeafCNode.EnumLeaf) node);
} else {
- System.err.println("Unknown node type for node with name " + name);
+ System.err.println("Unknown node type for node with name '" + name + "'");
}
}
} else {
ConfigDefinition newDef;
if (node.isArray) {
if (node.getChildren() != null && node.getChildren().length > 0) {
- //System.out.println("\tAdding inner array node " + name);
newDef = def.innerArrayDef(name);
for (CNode childNode : node.getChildren()) {
- //System.out.println("\tChild node " + childNode.getName());
addNode(newDef, childNode);
}
}
} else if (node.isMap) {
- //System.out.println("Adding struct map node " + name);
newDef = def.structMapDef(name);
if (node.getChildren() != null && node.getChildren().length > 0) {
for (CNode childNode : node.getChildren()) {
- //System.out.println("\tChild node " + childNode.getName());
addNode(newDef, childNode);
}
}
} else {
- //System.out.println("Adding struct node " + name);
newDef = def.structDef(name);
if (node.getChildren() != null && node.getChildren().length > 0) {
for (CNode childNode : node.getChildren()) {
- //System.out.println("\tChild node " + childNode.getName());
addNode(newDef, childNode);
}
}
@@ -184,6 +180,10 @@ public class ConfigDefinitionBuilder {
}
}
+ private static void addNode(ConfigDefinition def, LeafCNode.ModelLeaf leaf) {
+ def.addModelDef(leaf.getName());
+ }
+
private static void addNode(ConfigDefinition def, LeafCNode.EnumLeaf leaf) {
if (leaf.getDefaultValue() != null) {
def.addEnumDef(leaf.getName(), Arrays.asList(leaf.getLegalValues()), leaf.getDefaultValue().getValue());
@@ -202,4 +202,5 @@ public class ConfigDefinitionBuilder {
sb.delete(length - 2, length);
return sb.toString();
}
+
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
index 5c0e9539f4f..259a5ef9e6b 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
@@ -4,13 +4,12 @@ package com.yahoo.vespa.config;
import com.yahoo.config.ConfigBuilder;
import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
+import com.yahoo.config.ModelReference;
import com.yahoo.config.UrlReference;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.Type;
-import com.yahoo.text.Utf8;
-import com.yahoo.yolean.Exceptions;
import java.io.File;
import java.lang.reflect.Constructor;
@@ -22,12 +21,11 @@ import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Logger;
-import static java.util.logging.Level.FINE;
-import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.INFO;
/**
@@ -35,7 +33,9 @@ import static java.util.logging.Level.INFO;
*
* TODO: This can be refactored a lot, since many of the reflection methods are duplicated
*
- * @author Ulf Lilleengen, hmusum, Tony Vaagenes
+ * @author Ulf Lilleengen
+ * @author hmusum
+ * @author Tony Vaagenes
*/
public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
@@ -54,7 +54,6 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
this.rootBuilder = builder;
this.pathAcquirer = pathAcquirer;
this.urlDownloader = urlDownloader;
- debug("rootBuilder=" + rootBuilder);
}
public void applyPayload(ConfigPayload payload) {
@@ -62,8 +61,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
try {
handleValue(payload.getSlime().get());
} catch (Exception e) {
- throw new RuntimeException("Not able to create config builder for payload:" + payload.toString() +
- ", " + Exceptions.toMessageString(e), e);
+ throw new RuntimeException("Not able to create config builder for payload '" + payload.toString() + "'", e);
}
}
@@ -89,27 +87,19 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
private void handleARRAY(Inspector inspector) {
- trace("Array");
- inspector.traverse(new ArrayTraverser() {
- @Override
- public void entry(int idx, Inspector inspector) {
- handleArrayEntry(idx, inspector);
- }
- });
+ inspector.traverse((ArrayTraverser)(int index, Inspector value) -> handleArrayEntry(index, value));
}
private void handleArrayEntry(int idx, Inspector inspector) {
try {
- trace("entry, idx=" + idx);
- trace("top of stack=" + stack.peek().toString());
String name = stack.peek().nameStack().peek();
- if (inspector.type().equals(Type.OBJECT)) {
+ if (inspector.type() == Type.OBJECT) {
NamedBuilder builder = createBuilder(stack.peek(), name);
if (builder == null) return; // Ignore non-existent struct array class
stack.push(builder);
}
handleValue(inspector);
- if (inspector.type().equals(Type.OBJECT)) {
+ if (inspector.type() == Type.OBJECT) {
stack.peek().nameStack().pop();
}
} catch (Exception e) {
@@ -118,37 +108,24 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
private void handleOBJECT(Inspector inspector) {
- trace("Object");
- printStack();
-
- inspector.traverse(new ObjectTraverser() {
- @Override
- public void field(String name, Inspector inspector) {
- handleObjectEntry(name, inspector);
- }
- });
-
- trace("Should pop a builder from stack");
+ inspector.traverse((String name, Inspector value) -> handleObjectEntry(name, value));
NamedBuilder builder = stack.pop();
- printStack();
// Need to set e.g struct(Struct.Builder) here
- if (!stack.empty()) {
- trace("builder= " + builder);
+ if ( ! stack.empty()) {
try {
invokeSetter(stack.peek().builder, builder.peekName(), builder.builder);
} catch (Exception e) {
throw new RuntimeException("Could not set '" + builder.peekName() +
- "' for value '" + builder.builder() + "'", e);
+ "' for value '" + builder.builder() + "'", e);
}
}
}
private void handleObjectEntry(String name, Inspector inspector) {
try {
- trace("field, name=" + name);
NamedBuilder parentBuilder = stack.peek();
- if (inspector.type().equals(Type.OBJECT)) {
+ if (inspector.type() == Type.OBJECT) {
if (isMapField(parentBuilder, name)) {
parentBuilder.nameStack().push(name);
handleMap(inspector);
@@ -159,9 +136,8 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
if (builder == null) return; // Ignore non-existent struct class
stack.push(builder);
}
- } else if (inspector.type().equals(Type.ARRAY)) {
+ } else if (inspector.type() == Type.ARRAY) {
for (int i = 0; i < inspector.children(); i++) {
- trace("Pushing " + name);
parentBuilder.nameStack().push(name);
}
} else { // leaf
@@ -174,19 +150,11 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
private void handleMap(Inspector inspector) {
- inspector.traverse(new ObjectTraverser() {
- @Override
- public void field(String name, Inspector inspector) {
- switch (inspector.type()) {
- case OBJECT:
- handleInnerMap(name, inspector);
- break;
- case ARRAY:
- throw new IllegalArgumentException("Never herd of array inside maps before");
- default:
- setMapLeafValue(name, getValueFromInspector(inspector));
- break;
- }
+ inspector.traverse((String name, Inspector value) -> {
+ switch (value.type()) {
+ case OBJECT -> handleInnerMap(name, value);
+ case ARRAY -> throw new IllegalArgumentException("Never heard of array inside maps before");
+ default -> setMapLeafValue(name, value);
}
});
}
@@ -197,12 +165,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
throw new RuntimeException("Missing map builder (this should never happen): " + stack.peek());
setMapLeafValue(name, builder.builder());
stack.push(builder);
- inspector.traverse(new ObjectTraverser() {
- @Override
- public void field(String name, Inspector inspector) {
- handleObjectEntry(name, inspector);
- }
- });
+ inspector.traverse((ObjectTraverser) (key, value) -> handleObjectEntry(key, value));
stack.pop();
}
@@ -210,21 +173,8 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
NamedBuilder parent = stack.peek();
ConfigBuilder builder = parent.builder();
String methodName = parent.peekName();
- //trace("class to obtain method from: " + builder.getClass().getName());
try {
- // Need to convert reference into actual path if 'path' type is used
- if (isPathField(builder, methodName)) {
- FileReference wrappedPath = resolvePath((String)value);
- invokeSetter(builder, methodName, key, wrappedPath);
-
- // Need to convert url into actual file if 'url' type is used
- } else if (isUrlField(builder, methodName)) {
- UrlReference url = resolveUrl((String)value);
- invokeSetter(builder, methodName, key, url);
-
- } else {
- invokeSetter(builder, methodName, key, value);
- }
+ invokeSetter(builder, methodName, key, resolveValue(builder, methodName, value));
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException("Name: " + methodName + ", value '" + value + "'", e);
} catch (NoSuchMethodException e) {
@@ -246,46 +196,20 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
Object builder = parentBuilder.builder();
Object newBuilder = getBuilderForStruct(name, builder.getClass().getDeclaringClass());
if (newBuilder == null) return null;
- trace("New builder for " + name + "=" + newBuilder);
- trace("Pushing builder for " + name + "=" + newBuilder + " onto stack");
return new NamedBuilder((ConfigBuilder) newBuilder, name);
}
private void handleLeafValue(Inspector value) {
- trace("String ");
- printStack();
NamedBuilder peek = stack.peek();
- trace("popping name stack");
String name = peek.nameStack().pop();
- printStack();
ConfigBuilder builder = peek.builder();
- trace("name=" + name + ",builder=" + builder + ",value=" + value.toString());
setValueForLeafNode(builder, name, value);
}
// Sets values for leaf nodes (uses private accessors that take string as argument)
private void setValueForLeafNode(Object builder, String methodName, Inspector value) {
try {
- // Need to convert reference into actual path if 'path' type is used
- if (isPathField(builder, methodName)) {
- FileReference wrappedPath = resolvePath(Utf8.toString(value.asUtf8()));
- invokeSetter(builder, methodName, wrappedPath);
-
- // Need to convert url into actual file if 'url' type is used
- } else if (isUrlField(builder, methodName)) {
- String url = Utf8.toString(value.asUtf8());
- if (url == null || url.length() == 0) {
- invokeSetter(builder, methodName, "");
- } else {
- UrlReference urlref = resolveUrl(Utf8.toString(value.asUtf8()));
- invokeSetter(builder, methodName, urlref);
- }
-
-
- } else {
- Object object = getValueFromInspector(value);
- invokeSetter(builder, methodName, object);
- }
+ invokeSetter(builder, methodName, resolveValue(builder, methodName, value));
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException("Name: " + methodName + ", value '" + value + "'", e);
} catch (NoSuchMethodException e) {
@@ -293,27 +217,44 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
}
+ private Object resolveValue(Object builder, String methodName, Object rawValue) {
+ if (rawValue instanceof ConfigBuilder) // Value in a map
+ return rawValue;
+ Inspector value = (Inspector)rawValue;
+ if (isPathField(builder, methodName))
+ return resolvePath(value.asString());
+ else if (isUrlField(builder, methodName))
+ return value.asString().isEmpty() ? "" : resolveUrl(value.asString());
+ else if (isModelField(builder, methodName))
+ return value.asString().isEmpty() ? "" : resolveModel(value.asString());
+ else
+ return getValueFromInspector(value);
+ }
+
private FileReference resolvePath(String value) {
- Path path = pathAcquirer.getPath(newFileReference(value));
- return newFileReference(path.toString());
+ Path path = pathAcquirer.getPath(new FileReference(value));
+ return new FileReference(path.toString());
}
private UrlReference resolveUrl(String url) {
- if (urlDownloader == null) {
- return new UrlReference(url); // assuming config server - just return the actual url.
- }
+ if (! canResolveUrls()) // assuming config server - keep the url
+ return new UrlReference(url);
File file = urlDownloader.waitFor(new UrlReference(url), 60 * 60);
return new UrlReference(file.getAbsolutePath());
}
- private FileReference newFileReference(String fileReference) {
- try {
- Constructor<FileReference> constructor = FileReference.class.getDeclaredConstructor(String.class);
- constructor.setAccessible(true);
- return constructor.newInstance(fileReference);
- } catch (Exception e) {
- throw new RuntimeException("Failed invoking FileReference constructor.", e);
- }
+ private boolean canResolveUrls() {
+ return urlDownloader != null && urlDownloader.isValid();
+ }
+
+ private ModelReference resolveModel(String modelStringValue) {
+ var model = ModelReference.valueOf(modelStringValue);
+ // Resolve any of url and path present, in priority order
+ if (model.url().isPresent() && canResolveUrls())
+ model = model.withUrl(Optional.of(resolveUrl(model.url().get().value())));
+ else if (model.path().isPresent())
+ model = model.withPath(Optional.of(resolvePath(model.path().get().value())));
+ return model;
}
private final Map<String, Method> methodCache = new HashMap<>();
@@ -335,7 +276,6 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
Method method = builder.getClass().getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
- trace("method=" + method + ",params=" + params);
return method;
}
@@ -353,7 +293,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
private Object getValueFromInspector(Inspector inspector) {
switch (inspector.type()) {
case STRING:
- return Utf8.toString(inspector.asUtf8());
+ return inspector.asString();
case LONG:
return String.valueOf(inspector.asLong());
case DOUBLE:
@@ -385,6 +325,12 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
return isFieldType(urlFieldSet, builder, methodName, UrlReference.class);
}
+ private final Set<String> modelFieldSet = new HashSet<>();
+ private boolean isModelField(Object builder, String methodName) {
+ // Models are stored as ModelReference in Builder.
+ return isFieldType(modelFieldSet, builder, methodName, ModelReference.class);
+ }
+
private boolean isFieldType(Set<String> fieldSet, Object builder, String methodName, java.lang.reflect.Type type) {
String key = fieldKey(builder, methodName);
if (fieldSet.contains(key)) {
@@ -419,14 +365,11 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
private String capitalize(String name) {
- StringBuilder sb = new StringBuilder();
- sb.append(name.substring(0, 1).toUpperCase()).append(name.substring(1));
- return sb.toString();
+ return name.substring(0, 1).toUpperCase() + name.substring(1);
}
private Constructor<?> lookupBuilderForStruct(String structName, String name, Class<?> currentClass) {
- final String currentClassName = currentClass.getName();
- trace("structName=" + structName + ", name=" + name + ",current class=" + currentClassName);
+ String currentClassName = currentClass.getName();
Class<?> structClass = getInnerClass(currentClass, currentClassName + "$" + structName);
if (structClass == null) {
log.info("Could not find nested class '" + currentClassName + "$" + structName +
@@ -449,17 +392,16 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
}
/**
- * Finds a nested class with the given <code>name</code>name in <code>clazz</code>
+ * Finds a nested class with the given <code>name</code>name in <code>clazz</code>.
+ *
* @param clazz a Class
* @param name a name
* @return class found, or null if no class is found
*/
private Class<?> getInnerClass(Class<?> clazz, String name) {
for (Class<?> cls : clazz.getDeclaredClasses()) {
- if (cls.getName().equals(name)) {
- trace("Found class " + cls.getName());
+ if (cls.getName().equals(name))
return cls;
- }
}
return null;
}
@@ -472,37 +414,24 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
private Object getBuilderForStruct(String name, Class<?> currentClass) {
String structName = capitalize(name);
String key = constructorCacheKey(structName, name, currentClass);
- Constructor<?> ctor = constructorCache.get(key);
- if (ctor == null) {
- ctor = lookupBuilderForStruct(structName, name, currentClass);
- if (ctor == null) return null;
- constructorCache.put(key, ctor);
+ Constructor<?> constructor = constructorCache.get(key);
+ if (constructor == null) {
+ constructor = lookupBuilderForStruct(structName, name, currentClass);
+ if (constructor == null) return null;
+ constructorCache.put(key, constructor);
}
- Object builder;
try {
- builder = ctor.newInstance();
+ return constructor.newInstance();
} catch (Exception e) {
- throw new RuntimeException("Could not create class '" + "'" + ctor.getDeclaringClass().getName() + "'");
+ throw new RuntimeException("Could not create class '" + "'" + constructor.getDeclaringClass().getName() + "'");
}
- return builder;
- }
-
- private void debug(String message) {
- log.log(FINE, () -> message);
- }
-
- private void trace(String message) {
- log.log(FINEST, () -> message);
- }
-
- private void printStack() {
- trace("stack=" + stack.toString());
}
/**
* A class that holds a builder and a stack of names
*/
private static class NamedBuilder {
+
private final ConfigBuilder builder;
private final Stack<String> names = new Stack<>(); // if empty, the builder is the root builder
@@ -529,9 +458,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(builder() == null ? "null" : builder.toString()).append(" names=").append(names);
- return sb.toString();
+ return builder() == null ? "null" : builder.toString() + " names=" + names;
}
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java
index 48cdbe36745..74ee29f08ed 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java
@@ -1,16 +1,21 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config;
-import com.yahoo.slime.*;
+import com.yahoo.slime.ArrayTraverser;
+import com.yahoo.slime.Cursor;
+import com.yahoo.slime.Inspector;
+import com.yahoo.slime.ObjectTraverser;
+import com.yahoo.slime.Slime;
-import java.util.*;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
/**
* Helper class for building Slime config payloads, while supporting referring to payloads with their indices. The
* builder does not care about config field types. This is resolved by the actual config type consumer created
* from the Slime tree.
*
- * TODO: Add toString
* @author Ulf Lilleengen
*/
public class ConfigPayloadBuilder {
@@ -33,9 +38,9 @@ public class ConfigPayloadBuilder {
}
/**
- * Construct a payload builder with a leaf value
+ * Construct a payload builder with a leaf value.
*
- * @param value The value of this leaf.
+ * @param value the value of this leaf
*/
private ConfigPayloadBuilder(String value) {
this(null, value);
@@ -172,11 +177,9 @@ public class ConfigPayloadBuilder {
/**
* Get the value of this field, if any.
*
- * @return value of field, null if this is not a leaf.
+ * @return value of field, null if this is not a leaf
*/
- public String getValue() {
- return value;
- }
+ public String getValue() { return value; }
public void setValue(String value) {
this.value = value;
@@ -209,6 +212,7 @@ public class ConfigPayloadBuilder {
}
public class MapBuilder {
+
private final Map<String, ConfigPayloadBuilder> elements = new LinkedHashMap<>();
private final ConfigDefinition configDefinition;
private final String name;
@@ -268,6 +272,11 @@ public class ConfigPayloadBuilder {
INDEX, APPEND
}
+ @Override
+ public String toString() {
+ return "config builder of " + getConfigDefinition();
+ }
+
/**
* Representation of a config array, which supports both INDEX and APPEND modes.
*/
@@ -450,26 +459,12 @@ public class ConfigPayloadBuilder {
private static void decode(Slime slime, String name, Inspector inspector, ConfigPayloadBuilder builder) {
switch (inspector.type()) {
- case STRING:
- builder.setField(name, inspector.asString());
- break;
- case LONG:
- builder.setField(name, String.valueOf(inspector.asLong()));
- break;
- case DOUBLE:
- builder.setField(name, String.valueOf(inspector.asDouble()));
- break;
- case BOOL:
- builder.setField(name, String.valueOf(inspector.asBool()));
- break;
- case OBJECT:
- ConfigPayloadBuilder objectBuilder = builder.getObject(name);
- decodeObject(slime, objectBuilder, inspector);
- break;
- case ARRAY:
- ConfigPayloadBuilder.Array array = builder.getArray(name);
- decodeArray(slime, array, inspector);
- break;
+ case STRING -> builder.setField(name, inspector.asString());
+ case LONG -> builder.setField(name, String.valueOf(inspector.asLong()));
+ case DOUBLE -> builder.setField(name, String.valueOf(inspector.asDouble()));
+ case BOOL -> builder.setField(name, String.valueOf(inspector.asBool()));
+ case OBJECT -> decodeObject(slime, builder.getObject(name), inspector);
+ case ARRAY -> decodeArray(slime, builder.getArray(name), inspector);
}
}
@@ -479,8 +474,10 @@ public class ConfigPayloadBuilder {
}
private static class BuilderObjectTraverser implements ObjectTraverser {
+
private final ConfigPayloadBuilder builder;
private final Slime slime;
+
public BuilderObjectTraverser(Slime slime, ConfigPayloadBuilder builder) {
this.slime = slime;
this.builder = builder;
@@ -490,11 +487,14 @@ public class ConfigPayloadBuilder {
public void field(String name, Inspector inspector) {
decode(slime, name, inspector, builder);
}
+
}
private static class BuilderArrayTraverser implements ArrayTraverser {
+
private final Array array;
private final Slime slime;
+
public BuilderArrayTraverser(Slime slime, Array array) {
this.array = array;
this.slime = slime;
@@ -503,14 +503,13 @@ public class ConfigPayloadBuilder {
@Override
public void entry(int idx, Inspector inspector) {
switch (inspector.type()) {
- case STRING:
- array.append(inspector.asString());
- break;
- case OBJECT:
- decodeObject(slime, array.append(), inspector);
- break;
+ case STRING -> array.append(inspector.asString());
+ case OBJECT -> decodeObject(slime, array.append(), inspector);
}
}
+
}
+
}
+
}
diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java
index 873df75ce23..5104475d836 100644
--- a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java
@@ -15,7 +15,8 @@ import static org.junit.Assert.fail;
* @author gjoranv
*/
public class ConfigInstanceTest {
- private ConfigSourceSet sourceSet = new ConfigSourceSet("config-instance-test");
+
+ private final ConfigSourceSet sourceSet = new ConfigSourceSet("config-instance-test");
/**
* Verifies that the subscriber's configure() method is only
diff --git a/config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java b/config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java
new file mode 100644
index 00000000000..4d3b6b93b3b
--- /dev/null
+++ b/config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java
@@ -0,0 +1,49 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.config.ModelReference;
+import com.yahoo.config.ResolvedTypesConfig;
+import com.yahoo.config.UrlReference;
+import org.junit.Test;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Optional;
+
+/**
+ * @author bratseth
+ */
+public class ConfigPayloadApplierTest {
+
+ @Test
+ public void testConfigApplier() {
+ var applier = new ConfigPayloadApplier<>(new ResolvedTypesConfig.Builder(), new MockAcquirer(), new MockDownloader());
+ var config = new ResolvedTypesConfig.Builder();
+ config.myPath(new FileReference("mock/myPath.txt"));
+ config.myUrl(new UrlReference("mock/myUrl.txt"));
+ config.myModel(new ModelReference(Optional.empty(),
+ Optional.of(new UrlReference("mockPath/myPath.txt")),
+ Optional.of(new FileReference("mockUrl/myUrl.txt"))));
+ applier.applyPayload(ConfigPayload.fromInstance(config.build()));
+ }
+
+ private static class MockAcquirer implements ConfigTransformer.PathAcquirer {
+
+ @Override
+ public Path getPath(FileReference fileReference) {
+ return Path.of("mockPath", fileReference.value());
+ }
+
+ }
+
+ private static class MockDownloader extends UrlDownloader {
+
+ @Override
+ public File waitFor(UrlReference urlReference, long timeout) {
+ return new File("mockUrl", urlReference.value());
+ }
+
+ }
+
+}
diff --git a/config/src/test/resources/configs/def-files/resolved-types.def b/config/src/test/resources/configs/def-files/resolved-types.def
new file mode 100644
index 00000000000..184e98d51d9
--- /dev/null
+++ b/config/src/test/resources/configs/def-files/resolved-types.def
@@ -0,0 +1,6 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=config
+
+myPath path
+myUrl url
+myModel model
diff --git a/configdefinitions/src/vespa/embedding.bert-base-embedder.def b/configdefinitions/src/vespa/embedding.bert-base-embedder.def
index 115e021972c..14d953eeef9 100644
--- a/configdefinitions/src/vespa/embedding.bert-base-embedder.def
+++ b/configdefinitions/src/vespa/embedding.bert-base-embedder.def
@@ -1,13 +1,10 @@
namespace=embedding
-# Settings for wordpiece tokenizer
-tokenizerVocabUrl url
-tokenizerVocabPath path
+# Wordpiece tokenizer
+tokenizerVocab model
-# Transformer model settings
-transformerModelUrl url
-transformerModelPath path
+transformerModel model
# Max length of token sequence model can handle
transformerMaxTokens int default=384
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
index a0717a1060f..78ef17f613a 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
@@ -4,6 +4,7 @@ package com.yahoo.config.codegen;
import com.yahoo.config.codegen.LeafCNode.FileLeaf;
import com.yahoo.config.codegen.LeafCNode.PathLeaf;
import com.yahoo.config.codegen.LeafCNode.UrlLeaf;
+import com.yahoo.config.codegen.LeafCNode.ModelLeaf;
import java.util.ArrayList;
import java.util.List;
@@ -270,11 +271,11 @@ public class BuilderGenerator {
String bType = builderType(n);
String stringSetter = "";
- if ( ! "String".equals(bType) && ! "FileReference".equals(bType)) {
+ if ( ! "String".equals(bType) && ! "FileReference".equals(bType) && ! "ModelReference".equals(bType)) {
String type = boxedDataType(n);
if ("UrlReference".equals(bType))
type = bType;
- stringSetter = String.format("\nprivate Builder %s(String %svalue) {\n" + //
+ stringSetter = String.format("\nprivate Builder %s(String %svalue) {\n" +
" return %s(%s.valueOf(%svalue));\n" + //
"}", name, INTERNAL_PREFIX, name, type, INTERNAL_PREFIX);
}
@@ -282,9 +283,9 @@ public class BuilderGenerator {
String getNullGuard = bType.equals(boxedBuilderType(n)) ? String.format(
"\nif (%svalue == null) throw new IllegalArgumentException(\"Null value is not allowed.\");", INTERNAL_PREFIX) : "";
- return String.format("public Builder %s(%s %svalue) {%s\n" + //
+ return String.format("public Builder %s(%s %svalue) {%s\n" +
" %s = %svalue;\n" + //
- "%s", name, bType, INTERNAL_PREFIX, getNullGuard, name, INTERNAL_PREFIX, signalInitialized) + //
+ "%s", name, bType, INTERNAL_PREFIX, getNullGuard, name, INTERNAL_PREFIX, signalInitialized) +
" return this;" + "\n}\n" + stringSetter;
}
}
@@ -312,6 +313,12 @@ public class BuilderGenerator {
return name + "(" + nodeClass(child) + ".toUrlReferenceMap(config." + name + "));";
} else if (child instanceof UrlLeaf) {
return name + "(config." + name + ".getUrlReference());";
+ } else if (child instanceof ModelLeaf && isArray) {
+ return name + "(" + nodeClass(child) + ".toModelReferences(config." + name + "));";
+ } else if (child instanceof ModelLeaf && isMap) {
+ return name + "(" + nodeClass(child) + ".toModelReferenceMap(config." + name + "));";
+ } else if (child instanceof ModelLeaf) {
+ return name + "(config." + name + ".getModelReference());";
} else if (child instanceof LeafCNode) {
return name + "(config." + name + "());";
} else if (child instanceof InnerCNode && isArray) {
@@ -403,6 +410,8 @@ public class BuilderGenerator {
return "FileReference";
} else if (node instanceof UrlLeaf) {
return "UrlReference";
+ } else if (node instanceof ModelLeaf) {
+ return "ModelReference";
} else if (node instanceof LeafCNode && (node.isArray || node.isMap)) {
return boxedDataType(node);
} else {
@@ -417,6 +426,8 @@ public class BuilderGenerator {
return "FileReference";
} else if (node instanceof UrlLeaf) {
return "UrlReference";
+ } else if (node instanceof ModelLeaf) {
+ return "ModelReference";
} else {
return boxedDataType(node);
}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ClassBuilder.java b/configgen/src/main/java/com/yahoo/config/codegen/ClassBuilder.java
index 1ac817e7091..3732791740c 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/ClassBuilder.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/ClassBuilder.java
@@ -7,6 +7,6 @@ package com.yahoo.config.codegen;
public interface ClassBuilder {
/** Generate config class file(s). */
- public void createConfigClasses();
+ void createConfigClasses();
}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java
index b9a93995f46..5ffe18b1699 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java
@@ -11,6 +11,7 @@ import com.yahoo.config.codegen.LeafCNode.PathLeaf;
import com.yahoo.config.codegen.LeafCNode.ReferenceLeaf;
import com.yahoo.config.codegen.LeafCNode.StringLeaf;
import com.yahoo.config.codegen.LeafCNode.UrlLeaf;
+import com.yahoo.config.codegen.LeafCNode.ModelLeaf;
import java.util.LinkedList;
import java.util.List;
@@ -166,6 +167,8 @@ public class ConfigGenerator {
return name + " = LeafNodeVector.createPathNodeVector(builder." + name + ");";
} else if (child instanceof UrlLeaf && isArray) {
return name + " = LeafNodeVector.createUrlNodeVector(builder." + name + ");";
+ } else if (child instanceof ModelLeaf && isArray) {
+ return name + " = LeafNodeVector.createModelNodeVector(builder." + name + ");";
} else if (child instanceof LeafCNode && isArray) {
return name + " = new LeafNodeVector<>(builder." + name + ", new " + className + "());";
} else if (child instanceof FileLeaf && isMap) {
@@ -174,6 +177,8 @@ public class ConfigGenerator {
return name + " = LeafNodeMaps.asPathNodeMap(builder." + name + ");";
} else if (child instanceof UrlLeaf && isMap) {
return name + " = LeafNodeMaps.asUrlNodeMap(builder." + name + ");";
+ } else if (child instanceof ModelLeaf && isMap) {
+ return name + " = LeafNodeMaps.asModelNodeMap(builder." + name + ");";
} else if (child instanceof LeafCNode && isMap) {
return name + " = LeafNodeMaps.asNodeMap(builder." + name + ", new " + className + "());";
} else if (child instanceof InnerCNode && isArray) {
@@ -398,6 +403,8 @@ public class ConfigGenerator {
return "PathNode";
} else if (node instanceof UrlLeaf) {
return "UrlNode";
+ } else if (node instanceof ModelLeaf) {
+ return "ModelNode";
} else if (node instanceof IntegerLeaf) {
return "IntegerNode";
} else if (node instanceof LongLeaf) {
@@ -426,6 +433,8 @@ public class ConfigGenerator {
return "Path";
} else if (node instanceof UrlLeaf) {
return "File";
+ } else if (node instanceof ModelLeaf) {
+ return "Path";
} else if (node instanceof IntegerLeaf) {
return "int";
} else if (node instanceof LongLeaf) {
@@ -433,7 +442,7 @@ public class ConfigGenerator {
} else if (node instanceof StringLeaf) {
return "String";
} else {
- throw new IllegalStateException("Cannot determine user data type for node"); // should not occur
+ throw new IllegalStateException("Cannot determine user data type for node '" + node + "'"); // should not occur
}
}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java b/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java
index eeca50201b7..753fad0d41a 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java
@@ -251,7 +251,7 @@ public class DefLine {
} else if (whitespaceMatcher.matches()) {
break;
} else {
- throw new IllegalArgumentException(name + " contains unexpected character");
+ throw new IllegalArgumentException("'" + name + "' contains an unexpected character");
}
}
}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/DefParser.java b/configgen/src/main/java/com/yahoo/config/codegen/DefParser.java
index cebb7ca8108..2be824658b4 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/DefParser.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/DefParser.java
@@ -210,7 +210,7 @@ public class DefParser {
sb.append(" = ").append(((LeafCNode)root).getDefaultValue().getValue());
}
}
- System.out.println(sb.toString());
+ System.out.println(sb);
if (!root.getComment().isEmpty()) {
String comment = root.getComment();
if (comment.contains("\n")) {
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/DefaultValue.java b/configgen/src/main/java/com/yahoo/config/codegen/DefaultValue.java
index 9d8ee58f364..ed68bb7d9d8 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/DefaultValue.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/DefaultValue.java
@@ -13,30 +13,22 @@ public class DefaultValue {
// The variable type. Always set UNLESS the value is null.
private DefLine.Type type = null;
- /**
- * Null value
- */
+ /** Null value. */
public DefaultValue() {
}
- /**
- * A default value with the given value and type.
- */
+ /** A default value with the given value and type. */
public DefaultValue(String value, DefLine.Type type) {
this.value = value;
this.type = type;
}
- /**
- * Returns the toString of the default value.
- */
+ /** Returns the toString of the default value. */
public String getValue() {
return value;
}
- /**
- * Returns the string representation of this value
- */
+ /** Returns the string representation of this value. */
public String getStringRepresentation() {
if (value == null)
return "null";
@@ -60,7 +52,7 @@ public class DefaultValue {
sb.append(c);
}
}
- return "\"" + sb.toString() + "\"";
+ return "\"" + sb + "\"";
}
}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/InnerCNode.java b/configgen/src/main/java/com/yahoo/config/codegen/InnerCNode.java
index 74b0bbf7bba..295558a469c 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/InnerCNode.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/InnerCNode.java
@@ -15,7 +15,7 @@ public class InnerCNode extends CNode {
* The children of this Node. Mapped using their short name as
* string. This variable is null only if Node is a leaf Node.
*/
- private final Map<String, CNode> children = new LinkedHashMap<String, CNode>();
+ private final Map<String, CNode> children = new LinkedHashMap<>();
private boolean restart = false;
/**
@@ -66,8 +66,7 @@ public class InnerCNode extends CNode {
} else {
newChild = LeafCNode.newInstance(type, this, key);
if (newChild == null)
- throw new IllegalArgumentException
- ("Could not create " + type.name + " " + name);
+ throw new IllegalArgumentException("Could not create " + type.name + " " + name);
}
return children.containsKey(newChild.getName())
? children.get(newChild.getName())
@@ -77,6 +76,7 @@ public class InnerCNode extends CNode {
/**
* Adds a child to this node with the given type, name and value. Necessary children on the path
* to the given leaf node will be added as well.
+ *
* @param name the full name/path of the node to add.
* @param defLine the parsed .def-file line to add.
* @param comment comment extracted from the .def-file.
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java b/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java
index fe1566aa133..78977f43bdd 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java
@@ -105,12 +105,9 @@ public class JavaClassBuilder implements ClassBuilder {
}
/**
- * @param rootDir
- * The root directory for the destination path.
- * @param javaPackage
- * The java package
- * @return the destination path for the generated config file, including the
- * given rootDir.
+ * @param rootDir the root directory for the destination path.
+ * @param javaPackage the java package
+ * @return the destination path for the generated config file, including the given rootDir.
*/
private File getDestPath(File rootDir, String javaPackage) {
File dir = rootDir;
@@ -141,7 +138,7 @@ public class JavaClassBuilder implements ClassBuilder {
for (int i = 1;; i++) {
String candidate = (i < basis.length()) ? basis.substring(0, i)
: ReservedWords.INTERNAL_PREFIX + basis + rng.nextInt(Integer.MAX_VALUE);
- if (usedSymbols.contains(candidate) == false) {
+ if ( ! usedSymbols.contains(candidate)) {
return candidate;
}
}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java b/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java
index a50bb758be7..1395c6814df 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java
@@ -28,6 +28,7 @@ public abstract class LeafCNode extends CNode {
case "path": return new PathLeaf(parent, name);
case "enum": return new EnumLeaf(parent, name, type.enumArray);
case "url" : return new UrlLeaf(parent, name);
+ case "model" : return new ModelLeaf(parent, name);
default: return null;
}
} catch (NumberFormatException e) {
@@ -73,8 +74,7 @@ public abstract class LeafCNode extends CNode {
}
@Override
- protected void setLeaf(String name, DefLine defLine, String comment)
- throws IllegalArgumentException {
+ protected void setLeaf(String name, DefLine defLine, String comment) throws IllegalArgumentException {
DefLine.Type type = defLine.getType();
// TODO: why the !is... conditions?
if (!isMap && !isArray && isInitialized) {
@@ -100,8 +100,7 @@ public abstract class LeafCNode extends CNode {
checkDefaultValue(defaultValue);
setDefaultValue(defaultValue);
} catch (IllegalArgumentException e) {
- throw new IllegalArgumentException
- ("Invalid default value", e);
+ throw new IllegalArgumentException("Invalid default value", e);
}
}
@@ -229,6 +228,17 @@ public abstract class LeafCNode extends CNode {
}
}
+ public static class ModelLeaf extends NoClassLeafCNode {
+ ModelLeaf(InnerCNode parent, String name) {
+ super(parent, name);
+ }
+
+ @Override
+ public String getType() {
+ return "model";
+ }
+ }
+
public static class EnumLeaf extends LeafCNode {
private final String[] legalValues;
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/MakeConfig.java b/configgen/src/main/java/com/yahoo/config/codegen/MakeConfig.java
index 04f7c90c9b9..a24d88102bd 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/MakeConfig.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/MakeConfig.java
@@ -98,9 +98,9 @@ public class MakeConfig {
static class Exceptions {
/**
- * <p>Returns a use friendly error message string which includes information from all nested exceptions.
+ * Returns a use friendly error message string which includes information from all nested exceptions.
*
- * <p>The form of this string is
+ * The form of this string is
* <code>e.getMessage(): e.getCause().getMessage(): e.getCause().getCause().getMessage()...</code>
* In addition, some heuristics are used to clean up common cases where exception nesting causes bad messages.
*/
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/NormalizedDefinition.java b/configgen/src/main/java/com/yahoo/config/codegen/NormalizedDefinition.java
index fde9c171546..5d36b3cb77d 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/NormalizedDefinition.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/NormalizedDefinition.java
@@ -23,7 +23,7 @@ public class NormalizedDefinition {
// Patterns used for finding ranges in config definitions
private static final Pattern intPattern = Pattern.compile(".*int.*range.*");
private static final Pattern doublePattern = Pattern.compile(".*double.*range.*");
- private MessageDigest md5;
+ private final MessageDigest md5;
String defMd5 = null;
List<String> normalizedContent = null;
@@ -61,8 +61,8 @@ public class NormalizedDefinition {
* </ul>
* The supplied list is changed in-place
*
- * @param line A config definition line
- * @return a normalized config definition line
+ * @param line a config definition line
+ * @return a normalized config definition line
*/
public static String normalize(String line) {
//System.out.println("before line=" + line + ";");
@@ -150,7 +150,8 @@ public class NormalizedDefinition {
}
/**
- * Replaces sequences of spaces with 1 space, unless inside quotes. Public for testing;
+ * Replaces sequences of spaces with 1 space, unless inside quotes. Public for testing.
+ *
* @param str String to strip spaces from
* @return String with spaces stripped
*/
@@ -186,6 +187,7 @@ public class NormalizedDefinition {
return normalizedContent;
}
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (String line : normalizedContent) {
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ReservedWords.java b/configgen/src/main/java/com/yahoo/config/codegen/ReservedWords.java
index 3310ceb30f5..15465bccae3 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/ReservedWords.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/ReservedWords.java
@@ -44,7 +44,7 @@ public class ReservedWords {
private static final HashMap<String, String> allKeyWords;
static {
- allKeyWords = new HashMap<String, String>();
+ allKeyWords = new HashMap<>();
for (String s : cKeywords) {
allKeyWords.put(s, "C");
}
diff --git a/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java b/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java
index 53d02689fed..0e2f6cc4d05 100644
--- a/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java
+++ b/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java
@@ -121,6 +121,13 @@ public class DefLineParsingTest {
assertEquals("url", l.getType().getName());
}
+ @Test
+ void testParseModels() {
+ DefLine l = new DefLine("modelVal model");
+
+ assertEquals("modelVal", l.getName());
+ assertEquals("model", l.getType().getName());
+ }
@Test
void testParseDefaultInt() {
diff --git a/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java b/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java
index 4fbf01892cc..45d1f21763c 100644
--- a/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java
+++ b/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java
@@ -28,7 +28,7 @@ public class DefParserTest {
CNode root = new DefParser("test", new FileReader(defFile)).getTree();
assertNotNull(root);
CNode[] children = root.getChildren();
- assertEquals(34, children.length);
+ assertEquals(37, children.length);
int numGrandChildren = 0;
int numGreatGrandChildren = 0;
@@ -70,7 +70,7 @@ public class DefParserTest {
void testMd5Sum() throws IOException {
File defFile = new File(DEF_NAME);
CNode root = new DefParser("test", new FileReader(defFile)).getTree();
- assertEquals("f901bdc5c96e7005130399c63f247823", root.defMd5);
+ assertEquals("0501f9e2c4ecc8c283e100e0b1178ca4", root.defMd5);
}
@Test
@@ -194,7 +194,7 @@ public class DefParserTest {
@Test
void testIllegalCharacterInName() {
assertLineFails("a-b int",
- "a-b contains unexpected character");
+ "'a-b' contains an unexpected character");
}
@Test
diff --git a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java
index 69a690b0e82..428576e340f 100644
--- a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java
+++ b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java
@@ -33,6 +33,7 @@ public class JavaClassBuilderTest {
"pathArr[] path\n" + //
"u url\n" + //
"urlArr[] url\n" + //
+ "modelArr[] model\n" + //
"f file\n" + //
"fileArr[] file\n" + //
"i int default=0\n" + //
diff --git a/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java b/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java
index 61b5eb5a759..57b3ed962eb 100644
--- a/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java
+++ b/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java
@@ -70,7 +70,7 @@ public class NormalizedDefinitionTest {
}
assertNotNull(out);
- assertEquals(72, out.size());
+ assertEquals(75, out.size());
assertNotNull(fileReader);
fileReader.close();
diff --git a/configgen/src/test/resources/allfeatures.reference b/configgen/src/test/resources/allfeatures.reference
index 6ebcfc4ba12..8a681048f65 100644
--- a/configgen/src/test/resources/allfeatures.reference
+++ b/configgen/src/test/resources/allfeatures.reference
@@ -35,7 +35,7 @@ import com.yahoo.config.*;
*/
public final class AllfeaturesConfig extends ConfigInstance {
- public final static String CONFIG_DEF_MD5 = "f901bdc5c96e7005130399c63f247823";
+ public final static String CONFIG_DEF_MD5 = "0501f9e2c4ecc8c283e100e0b1178ca4";
public final static String CONFIG_DEF_NAME = "allfeatures";
public final static String CONFIG_DEF_NAMESPACE = "configgen";
public final static String[] CONFIG_DEF_SCHEMA = {
@@ -57,6 +57,7 @@ public final class AllfeaturesConfig extends ConfigInstance {
"fileVal file",
"pathVal path",
"urlVal url",
+ "modelVal model",
"boolarr[] bool",
"intarr[] int",
"longarr[] long",
@@ -67,9 +68,11 @@ public final class AllfeaturesConfig extends ConfigInstance {
"filearr[] file",
"pathArr[] path",
"urlArr[] url",
+ "modelArr[] model",
"intMap{} int",
"pathMap{} file",
"urlMap{} url",
+ "modelMap{} model",
"basic_struct.foo string default=\"foo\"",
"basic_struct.bar int default=0",
"struct_of_struct.inner0.name string default=\"inner0\"",
@@ -107,7 +110,8 @@ public final class AllfeaturesConfig extends ConfigInstance {
"refVal",
"fileVal",
"pathVal",
- "urlVal"
+ "urlVal",
+ "modelVal"
));
private Boolean boolVal = null;
@@ -127,6 +131,7 @@ public final class AllfeaturesConfig extends ConfigInstance {
private String fileVal = null;
private FileReference pathVal = null;
private UrlReference urlVal = null;
+ private ModelReference modelVal = null;
public List<Boolean> boolarr = new ArrayList<>();
public List<Integer> intarr = new ArrayList<>();
public List<Long> longarr = new ArrayList<>();
@@ -137,9 +142,11 @@ public final class AllfeaturesConfig extends ConfigInstance {
public List<String> filearr = new ArrayList<>();
public List<FileReference> pathArr = new ArrayList<>();
public List<UrlReference> urlArr = new ArrayList<>();
+ public List<ModelReference> modelArr = new ArrayList<>();
public Map<String, Integer> intMap = new LinkedHashMap<>();
public Map<String, String> pathMap = new LinkedHashMap<>();
public Map<String, UrlReference> urlMap = new LinkedHashMap<>();
+ public Map<String, ModelReference> modelMap = new LinkedHashMap<>();
public Basic_struct.Builder basic_struct = new Basic_struct.Builder();
public Struct_of_struct.Builder struct_of_struct = new Struct_of_struct.Builder();
public List<MyArray.Builder> myArray = new ArrayList<>();
@@ -165,6 +172,7 @@ public final class AllfeaturesConfig extends ConfigInstance {
fileVal(config.fileVal().value());
pathVal(config.pathVal.getFileReference());
urlVal(config.urlVal.getUrlReference());
+ modelVal(config.modelVal.getModelReference());
boolarr(config.boolarr());
intarr(config.intarr());
longarr(config.longarr());
@@ -175,9 +183,11 @@ public final class AllfeaturesConfig extends ConfigInstance {
filearr(FileReference.toValues(config.filearr()));
pathArr(PathNode.toFileReferences(config.pathArr));
urlArr(UrlNode.toUrlReferences(config.urlArr));
+ modelArr(ModelNode.toModelReferences(config.modelArr));
intMap(config.intMap());
pathMap(FileReference.toValueMap(config.pathMap()));
urlMap(UrlNode.toUrlReferenceMap(config.urlMap));
+ modelMap(ModelNode.toModelReferenceMap(config.modelMap));
basic_struct(new Basic_struct.Builder(config.basic_struct()));
struct_of_struct(new Struct_of_struct.Builder(config.struct_of_struct()));
for (MyArray m : config.myArray()) {
@@ -223,6 +233,8 @@ public final class AllfeaturesConfig extends ConfigInstance {
pathVal(__superior.pathVal);
if (__superior.urlVal != null)
urlVal(__superior.urlVal);
+ if (__superior.modelVal != null)
+ modelVal(__superior.modelVal);
if (!__superior.boolarr.isEmpty())
boolarr.addAll(__superior.boolarr);
if (!__superior.intarr.isEmpty())
@@ -243,9 +255,12 @@ public final class AllfeaturesConfig extends ConfigInstance {
pathArr.addAll(__superior.pathArr);
if (!__superior.urlArr.isEmpty())
urlArr.addAll(__superior.urlArr);
+ if (!__superior.modelArr.isEmpty())
+ modelArr.addAll(__superior.modelArr);
intMap(__superior.intMap);
pathMap(__superior.pathMap);
urlMap(__superior.urlMap);
+ modelMap(__superior.modelMap);
basic_struct(basic_struct.override(__superior.basic_struct));
struct_of_struct(struct_of_struct.override(__superior.struct_of_struct));
if (!__superior.myArray.isEmpty())
@@ -408,6 +423,14 @@ public final class AllfeaturesConfig extends ConfigInstance {
return urlVal(UrlReference.valueOf(__value));
}
+ public Builder modelVal(ModelReference __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ modelVal = __value;
+ __uninitialized.remove("modelVal");
+ return this;
+ }
+
+
public Builder boolarr(Boolean __value) {
boolarr.add(__value);
return this;
@@ -532,6 +555,20 @@ public final class AllfeaturesConfig extends ConfigInstance {
return urlArr(UrlReference.valueOf(__value));
}
+ public Builder modelArr(ModelReference __value) {
+ modelArr.add(__value);
+ return this;
+ }
+
+ public Builder modelArr(Collection<ModelReference> __values) {
+ modelArr.addAll(__values);
+ return this;
+ }
+
+ private Builder modelArr(String __value) {
+ return modelArr(ModelReference.valueOf(__value));
+ }
+
public Builder intMap(String __key, Integer __value) {
intMap.put(__key, __value);
return this;
@@ -570,6 +607,20 @@ public final class AllfeaturesConfig extends ConfigInstance {
return urlMap(__key, UrlReference.valueOf(__value));
}
+ public Builder modelMap(String __key, ModelReference __value) {
+ modelMap.put(__key, __value);
+ return this;
+ }
+
+ public Builder modelMap(Map<String, ModelReference> __values) {
+ modelMap.putAll(__values);
+ return this;
+ }
+
+ private Builder modelMap(String __key, String __value) {
+ return modelMap(__key, ModelReference.valueOf(__value));
+ }
+
public Builder basic_struct(Basic_struct.Builder __builder) {
basic_struct = __builder;
return this;
@@ -709,6 +760,7 @@ public final class AllfeaturesConfig extends ConfigInstance {
private final FileNode fileVal;
private final PathNode pathVal;
private final UrlNode urlVal;
+ private final ModelNode modelVal;
private final LeafNodeVector<Boolean, BooleanNode> boolarr;
private final LeafNodeVector<Integer, IntegerNode> intarr;
private final LeafNodeVector<Long, LongNode> longarr;
@@ -719,9 +771,11 @@ public final class AllfeaturesConfig extends ConfigInstance {
private final LeafNodeVector<FileReference, FileNode> filearr;
private final LeafNodeVector<Path, PathNode> pathArr;
private final LeafNodeVector<File, UrlNode> urlArr;
+ private final LeafNodeVector<Path, ModelNode> modelArr;
private final Map<String, IntegerNode> intMap;
private final Map<String, FileNode> pathMap;
private final Map<String, UrlNode> urlMap;
+ private final Map<String, ModelNode> modelMap;
private final Basic_struct basic_struct;
private final Struct_of_struct struct_of_struct;
private final InnerNodeVector<MyArray> myArray;
@@ -770,6 +824,8 @@ public final class AllfeaturesConfig extends ConfigInstance {
new PathNode() : new PathNode(builder.pathVal);
urlVal = (builder.urlVal == null) ?
new UrlNode() : new UrlNode(builder.urlVal);
+ modelVal = (builder.modelVal == null) ?
+ new ModelNode() : new ModelNode(builder.modelVal);
boolarr = new LeafNodeVector<>(builder.boolarr, new BooleanNode());
intarr = new LeafNodeVector<>(builder.intarr, new IntegerNode());
longarr = new LeafNodeVector<>(builder.longarr, new LongNode());
@@ -780,9 +836,11 @@ public final class AllfeaturesConfig extends ConfigInstance {
filearr = LeafNodeVector.createFileNodeVector(builder.filearr);
pathArr = LeafNodeVector.createPathNodeVector(builder.pathArr);
urlArr = LeafNodeVector.createUrlNodeVector(builder.urlArr);
+ modelArr = LeafNodeVector.createModelNodeVector(builder.modelArr);
intMap = LeafNodeMaps.asNodeMap(builder.intMap, new IntegerNode());
pathMap = LeafNodeMaps.asFileNodeMap(builder.pathMap);
urlMap = LeafNodeMaps.asUrlNodeMap(builder.urlMap);
+ modelMap = LeafNodeMaps.asModelNodeMap(builder.modelMap);
basic_struct = new Basic_struct(builder.basic_struct, throwIfUninitialized);
struct_of_struct = new Struct_of_struct(builder.struct_of_struct, throwIfUninitialized);
myArray = MyArray.createVector(builder.myArray);
@@ -909,6 +967,13 @@ public final class AllfeaturesConfig extends ConfigInstance {
}
/**
+ * @return allfeatures.modelVal
+ */
+ public Path modelVal() {
+ return modelVal.value();
+ }
+
+ /**
* @return allfeatures.boolarr[]
*/
public List<Boolean> boolarr() {
@@ -1059,6 +1124,21 @@ public final class AllfeaturesConfig extends ConfigInstance {
}
/**
+ * @return allfeatures.modelArr[]
+ */
+ public List<Path> modelArr() {
+ return modelArr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.modelArr[]
+ */
+ public Path modelArr(int i) {
+ return modelArr.get(i).value();
+ }
+
+ /**
* @return allfeatures.intMap{}
*/
public Map<String, Integer> intMap() {
@@ -1104,6 +1184,21 @@ public final class AllfeaturesConfig extends ConfigInstance {
}
/**
+ * @return allfeatures.modelMap{}
+ */
+ public Map<String, Path> modelMap() {
+ return LeafNodeMaps.asValueMap(modelMap);
+ }
+
+ /**
+ * @param key the key of the value to return
+ * @return allfeatures.modelMap{}
+ */
+ public Path modelMap(String key) {
+ return modelMap.get(key).value();
+ }
+
+ /**
* @return allfeatures.basic_struct
*/
public Basic_struct basic_struct() {
diff --git a/configgen/src/test/resources/configgen.allfeatures.def b/configgen/src/test/resources/configgen.allfeatures.def
index df20665f1b7..1f93e29b73b 100644
--- a/configgen/src/test/resources/configgen.allfeatures.def
+++ b/configgen/src/test/resources/configgen.allfeatures.def
@@ -40,6 +40,7 @@ refwithdef reference default=":parent:"
fileVal file
pathVal path
urlVal url
+modelVal model
boolarr[] bool
intarr[] int
@@ -51,10 +52,12 @@ refarr[] reference
filearr[] file
pathArr[] path
urlArr[] url
+modelArr[] model
intMap{} int
pathMap{} file
urlMap{} url
+modelMap{} model
# A basic struct
basic_struct.foo string default="foo"
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionContentListResponse.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionContentListResponse.java
index b8d998a5b3d..0a9d6e36767 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionContentListResponse.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionContentListResponse.java
@@ -11,7 +11,6 @@ import java.util.List;
* Represents a request for listing files within an application package.
*
* @author Ulf Lilleengen
- * @since 5.1
*/
class SessionContentListResponse extends SlimeJsonResponse {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionHandler.java
index d0c4f43359a..d63dc714b9d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/SessionHandler.java
@@ -29,7 +29,7 @@ public class SessionHandler extends HttpHandler {
* Set to make sure that timeout for the handler is higher than any timeouts used inside the handler (e.g. zookeeper barrier timeout)
* Setting this too low will lead to a response with status code 504 and empty response body.
*/
- @Override
+ @Override
public Duration getTimeout() {
return Duration.ofSeconds(applicationRepository.configserverConfig().zookeeper().barrierTimeout()).plus(Duration.ofSeconds(30));
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java
index 95196abf16d..4656834d033 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java
@@ -25,8 +25,7 @@ public class SessionContentHandler extends SessionHandler {
private final ContentHandler contentHandler = new ContentHandler();
@Inject
- public SessionContentHandler(Context ctx,
- ApplicationRepository applicationRepository) {
+ public SessionContentHandler(Context ctx, ApplicationRepository applicationRepository) {
super(ctx, applicationRepository);
}
diff --git a/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java b/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java
index f49c127cb01..106b8cef35f 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/LogReaderTest.java
@@ -3,6 +3,7 @@ package com.yahoo.container.handler;
import com.yahoo.compress.ZstdCompressor;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -53,6 +54,7 @@ public class LogReaderTest {
Files.write(logDirectory.resolve("vespa.log"), logv.getBytes(UTF_8));
}
+ @Disabled
@Test
void testThatLogsOutsideRangeAreExcluded() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -71,6 +73,7 @@ public class LogReaderTest {
assertEquals(log101 + logv11, baos.toString(UTF_8));
}
+ @Disabled // TODO: zts log line missing on Mac
@Test
void testZippedStreaming() {
ByteArrayOutputStream zippedBaos = new ByteArrayOutputStream();
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/IndexedSegmentItem.java b/container-search/src/main/java/com/yahoo/prelude/query/IndexedSegmentItem.java
index aaace3043ba..ff637e623f7 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/IndexedSegmentItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/IndexedSegmentItem.java
@@ -29,7 +29,7 @@ public abstract class IndexedSegmentItem extends TaggableSegmentItem implements
/**
* The name of the index this belongs to, or "" (never null) if not specified
- **/
+ */
public String getIndexName() {
return index;
}
diff --git a/model-integration/src/main/java/ai/vespa/embedding/BertBaseEmbedder.java b/model-integration/src/main/java/ai/vespa/embedding/BertBaseEmbedder.java
index bc3f08ce3d6..149598ee2dd 100644
--- a/model-integration/src/main/java/ai/vespa/embedding/BertBaseEmbedder.java
+++ b/model-integration/src/main/java/ai/vespa/embedding/BertBaseEmbedder.java
@@ -11,13 +11,10 @@ import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorAddress;
import com.yahoo.tensor.TensorType;
-import java.io.File;
-import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-
/**
* A BERT Base compatible embedder. This embedder uses a WordPiece embedder to
* produce a token sequence that is input to a transformer model. A BERT base
@@ -60,22 +57,12 @@ public class BertBaseEmbedder implements Embedder {
options.setInterOpThreads(modifyThreadCount(config.onnxInterOpThreads()));
options.setIntraOpThreads(modifyThreadCount(config.onnxIntraOpThreads()));
- String tokenizerFile = pathOrUrl(config.tokenizerVocabPath(), config.tokenizerVocabUrl());
- String modelFile = pathOrUrl(config.transformerModelPath(), config.transformerModelUrl());
-
- tokenizer = new WordPieceEmbedder.Builder(tokenizerFile).build();
- evaluator = new OnnxEvaluator(modelFile, options);
+ tokenizer = new WordPieceEmbedder.Builder(config.tokenizerVocab().toString()).build();
+ evaluator = new OnnxEvaluator(config.transformerModel().toString(), options);
validateModel();
}
- private String pathOrUrl(Path path, File url) {
- if (path.endsWith("services.xml")) {
- return url.getAbsolutePath();
- }
- return path.toAbsolutePath().toString();
- }
-
private void validateModel() {
Map<String, TensorType> inputs = evaluator.getInputInfo();
validateName(inputs, inputIdsName, "input");
diff --git a/model-integration/src/test/java/ai/vespa/embedding/BertBaseEmbedderTest.java b/model-integration/src/test/java/ai/vespa/embedding/BertBaseEmbedderTest.java
index c224b87982d..82a78115e63 100644
--- a/model-integration/src/test/java/ai/vespa/embedding/BertBaseEmbedderTest.java
+++ b/model-integration/src/test/java/ai/vespa/embedding/BertBaseEmbedderTest.java
@@ -2,6 +2,7 @@ package ai.vespa.embedding;
import ai.vespa.modelintegration.evaluator.OnnxEvaluator;
import com.yahoo.config.FileReference;
+import com.yahoo.config.ModelReference;
import com.yahoo.config.UrlReference;
import com.yahoo.embedding.BertBaseEmbedderConfig;
import com.yahoo.tensor.Tensor;
@@ -22,10 +23,8 @@ public class BertBaseEmbedderTest {
assumeTrue(OnnxEvaluator.isRuntimeAvailable(modelPath));
BertBaseEmbedderConfig.Builder builder = new BertBaseEmbedderConfig.Builder();
- builder.tokenizerVocabPath(new FileReference(vocabPath));
- builder.tokenizerVocabUrl(new UrlReference(""));
- builder.transformerModelPath(new FileReference(modelPath));
- builder.transformerModelUrl(new UrlReference(""));
+ builder.tokenizerVocab(ModelReference.fromPath(vocabPath));
+ builder.transformerModel(ModelReference.fromPath(modelPath));
BertBaseEmbedder embedder = new BertBaseEmbedder(builder.build());
TensorType destType = TensorType.fromSpec("tensor<float>(x[7])");
diff --git a/vespajlib/src/main/java/com/yahoo/text/Utf8.java b/vespajlib/src/main/java/com/yahoo/text/Utf8.java
index b2b6fa13b70..2a42cb5cdee 100644
--- a/vespajlib/src/main/java/com/yahoo/text/Utf8.java
+++ b/vespajlib/src/main/java/com/yahoo/text/Utf8.java
@@ -117,10 +117,10 @@ public final class Utf8 {
/**
* Decode a UTF-8 string.
*
- * @param utf8 The bytes to decode.
+ * @param utf8 the bytes to decode
* @return Utf8 encoded array
*/
- public static String toString(byte [] utf8) {
+ public static String toString(byte[] utf8) {
// This is just wrapper for String::new. Pre-Java 9 this had a more efficient approach for ASCII-onlu strings.
return new String(utf8, StandardCharsets.UTF_8);
}