diff options
author | Geir Storli <geirstorli@yahoo.no> | 2017-01-23 16:58:55 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-23 16:58:55 +0100 |
commit | a5a30171965cea021761e629b45a837d2d1c4629 (patch) | |
tree | 184dbf35c633c02d6ceadb694d38f34a9f39e3a7 /config-model/src | |
parent | f316bb001a345b259aa15b3a7cb5c07ca8c0f5c0 (diff) | |
parent | 4960f7ce8b00943a56dd750cf0b6e9fe5e5025a4 (diff) |
Merge pull request #1579 from yahoo/geirst/parsing-of-imported-fields-in-sd-file
Add parsing of imported fields in SD file.
Diffstat (limited to 'config-model/src')
8 files changed, 200 insertions, 4 deletions
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/Search.java b/config-model/src/main/java/com/yahoo/searchdefinition/Search.java index 9032f913d0b..710f49dddb6 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/Search.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/Search.java @@ -70,6 +70,8 @@ public class Search implements Serializable { // Ranking constants defined inside this s.d. private Map<String, RankingConstant> rankingConstants = new HashMap<>(); + private ImportedFields importedFields = new ImportedFields(); + private ApplicationPackage sourceApplication; /** @@ -154,6 +156,10 @@ public class Search implements Serializable { return rankingConstants.values(); } + public ImportedFields importedFields() { + return importedFields; + } + /** * Gets a document from this search definition * diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/document/ImportedFields.java b/config-model/src/main/java/com/yahoo/searchdefinition/document/ImportedFields.java new file mode 100644 index 00000000000..01d14104d2b --- /dev/null +++ b/config-model/src/main/java/com/yahoo/searchdefinition/document/ImportedFields.java @@ -0,0 +1,24 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchdefinition.document; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A set of fields that are imported from referenced document types. + * + * @author geirst + */ +public class ImportedFields { + + private final Map<String, TemporaryImportedField> fields = new LinkedHashMap<>(); + + public void add(TemporaryImportedField importedField) { + fields.put(importedField.fieldName(), importedField); + } + + public Map<String, TemporaryImportedField> fields() { + return Collections.unmodifiableMap(fields); + } +} diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/document/TemporaryFieldReference.java b/config-model/src/main/java/com/yahoo/searchdefinition/document/TemporaryFieldReference.java new file mode 100644 index 00000000000..2dea3f9bf88 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/searchdefinition/document/TemporaryFieldReference.java @@ -0,0 +1,33 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchdefinition.document; + +/** + * Temporary reference to a field in another document type. + * + * After all SD files are parsed this temporary reference can be validated and connected + * to the actual field instance in the referenced document type. + * + * @author geirst + */ +public class TemporaryFieldReference { + + private final String refFieldName; + private final String fieldNameInRefType; + + /** + * @param refFieldName points to a field of type reference (in this document type). + * @param fieldNameInRefType points to a field in the referenced document type. + */ + public TemporaryFieldReference(String refFieldName, String fieldNameInRefType) { + this.refFieldName = refFieldName; + this.fieldNameInRefType = fieldNameInRefType; + } + + public String refFieldName() { + return refFieldName; + } + + public String fieldNameInRefType() { + return fieldNameInRefType; + } +} diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/document/TemporaryImportedField.java b/config-model/src/main/java/com/yahoo/searchdefinition/document/TemporaryImportedField.java new file mode 100644 index 00000000000..23a5e05c55f --- /dev/null +++ b/config-model/src/main/java/com/yahoo/searchdefinition/document/TemporaryImportedField.java @@ -0,0 +1,29 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchdefinition.document; + +/** + * Temporary field that is imported from a field in a referenced document type. + * + * After all SD files are parsed this temporary field can be validated and connected + * to the actual field instance in the referenced document type. + * + * @author geirst + */ +public class TemporaryImportedField { + + private final String fieldName; + private final TemporaryFieldReference reference; + + public TemporaryImportedField(String fieldName, TemporaryFieldReference reference) { + this.fieldName = fieldName; + this.reference = reference; + } + + public String fieldName() { + return fieldName; + } + + public TemporaryFieldReference reference() { + return reference; + } +} diff --git a/config-model/src/main/javacc/SDParser.jj b/config-model/src/main/javacc/SDParser.jj index 30b9b77f368..a5d1af6b4cb 100644 --- a/config-model/src/main/javacc/SDParser.jj +++ b/config-model/src/main/javacc/SDParser.jj @@ -60,6 +60,7 @@ import com.yahoo.search.query.ranking.Diversity; import java.util.Map; import java.util.LinkedHashMap; import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; /** * A search definition parser @@ -193,6 +194,8 @@ TOKEN : | < FIELDS: "fields" > | < FIELDSET: "fieldset" > | < STRUCTFIELD: "struct-field" > +| < IMPORT: "import" > +| < AS: "as" > | < INDEXING: "indexing" > | < SUMMARYTO: "summary-to" > | < DOCUMENTSUMMARY: "document-summary" > @@ -421,7 +424,8 @@ Object rootSearchItem(Search search) : { } | useDocument(search) | structOutside(search) | annotationOutside(search) - | fieldSet(search) ) + | fieldSet(search) + | importField(search) ) { return null; } } @@ -2386,6 +2390,34 @@ TensorType tensorType(String errorMessage) : } } +void importField(Search search) : +{ + TemporaryFieldReference reference; + String fieldName; +} +{ + <IMPORT> <FIELD> reference = fieldReference() <AS> fieldName = identifier() lbrace() + <RBRACE> + { + search.importedFields().add(new TemporaryImportedField(fieldName, reference)); + } +} + +TemporaryFieldReference fieldReference() : +{ + String fieldRefSpec; +} +{ + fieldRefSpec = identifier() + { + if (StringUtils.countMatches(fieldRefSpec, ".") != 1) { + throw new IllegalArgumentException("Illegal field reference spec '" + fieldRefSpec + "': Does not include a single '.'"); + } + int indexOfDot = fieldRefSpec.indexOf('.'); + return new TemporaryFieldReference(fieldRefSpec.substring(0, indexOfDot), fieldRefSpec.substring(indexOfDot + 1)); + } +} + /** * This rule consumes an expression token and returns its image. * @@ -2416,6 +2448,7 @@ String identifier() : { } | <ANNOTATIONREFERENCE> | <ARITY> | <ARRAY> + | <AS> | <ASCENDING> | <ATTRIBUTE> | <BODY> @@ -2454,6 +2487,7 @@ String identifier() : { } | <IDENTICAL> | <IDENTIFIER> | <IGNOREDEFAULTRANKFEATURES> + | <IMPORT> | <INDEX> | <INDEXING> | <INDEXINGREWRITE> diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/RankingConstantTest.java b/config-model/src/test/java/com/yahoo/searchdefinition/RankingConstantTest.java index a208ac2dec0..aa65cca1b6a 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/RankingConstantTest.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/RankingConstantTest.java @@ -8,6 +8,7 @@ import java.util.Iterator; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static com.yahoo.searchdefinition.TestUtils.joinLines; /** * @author gjoranv @@ -101,7 +102,4 @@ public class RankingConstantTest { assertEquals("simplename", constant.getFileName()); } - private static String joinLines(String... lines) { - return String.join("\n", lines); - } } diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/TestUtils.java b/config-model/src/test/java/com/yahoo/searchdefinition/TestUtils.java new file mode 100644 index 00000000000..d2c963d814d --- /dev/null +++ b/config-model/src/test/java/com/yahoo/searchdefinition/TestUtils.java @@ -0,0 +1,12 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchdefinition; + +/** + * @author geirst + */ +public class TestUtils { + + public static String joinLines(String... lines) { + return String.join("\n", lines); + } +} diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java new file mode 100644 index 00000000000..434cfd72136 --- /dev/null +++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java @@ -0,0 +1,60 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.searchdefinition.processing; + +import com.yahoo.searchdefinition.Search; +import com.yahoo.searchdefinition.SearchBuilder; +import com.yahoo.searchdefinition.document.TemporaryImportedField; +import com.yahoo.searchdefinition.parser.ParseException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.junit.Assert.assertEquals; +import static com.yahoo.searchdefinition.TestUtils.joinLines; + +/** + * @author geirst + */ +public class ImportedFieldsTestCase { + + @Test + public void require_that_imported_fields_can_be_parsed_from_sd_file() throws ParseException { + Search search = build(joinLines( + "search ad {", + " document ad {}", + " import field campaign.budget as budget {}", + " import field person.name as sales_person {}", + "}")); + assertEquals(2, search.importedFields().fields().size()); + assertSearchContainsTemporaryImportedField("budget", "campaign", "budget", search); + assertSearchContainsTemporaryImportedField("sales_person", "person", "name", search); + } + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Test + public void require_that_field_reference_spec_must_include_dot() throws ParseException { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("Illegal field reference spec 'campaignbudget': Does not include a single '.'"); + build(joinLines( + "search ad {", + " document ad {}", + " import field campaignbudget as budget {}", + "}")); + } + + private static Search build(String sdContent) throws ParseException { + SearchBuilder builder = new SearchBuilder(); + builder.importString(sdContent); + builder.build(); + return builder.getSearch(); + } + + private static void assertSearchContainsTemporaryImportedField(String fieldName, String refFieldName, String fieldNameInRefType, Search search) { + TemporaryImportedField importedField = search.importedFields().fields().get(fieldName); + assertEquals(fieldName, importedField.fieldName()); + assertEquals(refFieldName, importedField.reference().refFieldName()); + assertEquals(fieldNameInRefType, importedField.reference().fieldNameInRefType()); + } +} |