From e18be113b03bb8138109ba1c183ab8e282c23ae3 Mon Sep 17 00:00:00 2001 From: Tor Egge Date: Thu, 22 Nov 2018 11:49:02 +0100 Subject: Handle import of array of struct fields, map of struct fields, and map of primitive fields as long as required attributes are present. --- .../searchdefinition/derived/ImportedFields.java | 14 +- .../searchdefinition/document/ImportedFields.java | 5 +- ...ttributeTransformToSummaryOfImportedFields.java | 10 ++ .../processing/ImportedFieldsResolver.java | 122 +++++++++++-- .../SummaryFieldsMustHaveValidSource.java | 1 + .../derived/imported_struct_fields/attributes.cfg | 168 ++++++++++++++++++ .../test/derived/imported_struct_fields/child.sd | 19 ++ .../imported_struct_fields/imported-fields.cfg | 35 ++++ .../derived/imported_struct_fields/index-info.cfg | 37 ++++ .../derived/imported_struct_fields/indexschema.cfg | 0 .../test/derived/imported_struct_fields/parent.sd | 43 +++++ .../derived/imported_struct_fields/summary.cfg | 31 ++++ .../derived/imported_struct_fields/summarymap.cfg | 16 ++ .../derived/ImportedFieldsTestCase.java | 5 + ...buteTransformToSummaryOfImportedFieldsTest.java | 2 +- .../processing/ImportedFieldsTestCase.java | 196 ++++++++++++++++++++- .../processing/ValidateFieldTypesTest.java | 2 +- 17 files changed, 676 insertions(+), 30 deletions(-) create mode 100644 config-model/src/test/derived/imported_struct_fields/attributes.cfg create mode 100644 config-model/src/test/derived/imported_struct_fields/child.sd create mode 100644 config-model/src/test/derived/imported_struct_fields/imported-fields.cfg create mode 100644 config-model/src/test/derived/imported_struct_fields/index-info.cfg create mode 100644 config-model/src/test/derived/imported_struct_fields/indexschema.cfg create mode 100644 config-model/src/test/derived/imported_struct_fields/parent.sd create mode 100644 config-model/src/test/derived/imported_struct_fields/summary.cfg create mode 100644 config-model/src/test/derived/imported_struct_fields/summarymap.cfg diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java b/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java index cfe33ef019f..a69581559e5 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java @@ -3,6 +3,7 @@ package com.yahoo.searchdefinition.derived; import com.yahoo.searchdefinition.Search; import com.yahoo.searchdefinition.document.Attribute; +import com.yahoo.searchdefinition.document.ImmutableSDField; import com.yahoo.searchdefinition.document.ImportedField; import com.yahoo.vespa.config.search.ImportedFieldsConfig; @@ -39,8 +40,17 @@ public class ImportedFields extends Derived implements ImportedFieldsConfig.Prod } private static void considerField(ImportedFieldsConfig.Builder builder, ImportedField field) { - if (field.targetField().doesAttributing()) { - builder.attribute.add(createAttributeBuilder(field)); + ImmutableSDField targetField = field.targetField(); + String targetFieldName = targetField.getName(); + if (targetFieldName.indexOf('.') == -1) { + if (field.targetField().doesAttributing()) { + builder.attribute.add(createAttributeBuilder(field)); + } + } else { + Attribute attribute = targetField.getAttributes().get(targetFieldName); + if (attribute != null) { + builder.attribute.add(createAttributeBuilder(field)); + } } } 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 index 2192a7e7bb1..7c67fc422d4 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/document/ImportedFields.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/document/ImportedFields.java @@ -12,12 +12,15 @@ import java.util.Map; public class ImportedFields { private final Map fields; + private final Map complexFields; - public ImportedFields(Map fields) { + public ImportedFields(Map fields, Map complexFields) { this.fields = fields; + this.complexFields = complexFields; } public Map fields() { return Collections.unmodifiableMap(fields); } + public Map complexFields() { return Collections.unmodifiableMap(complexFields); } } diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFields.java b/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFields.java index fefb54a7fe3..c10b52eb1e6 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFields.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFields.java @@ -8,6 +8,7 @@ import com.yahoo.searchdefinition.document.ImmutableSDField; import com.yahoo.vespa.documentmodel.SummaryField; import com.yahoo.vespa.documentmodel.SummaryTransform; import com.yahoo.vespa.model.container.search.QueryProfiles; +import com.yahoo.searchdefinition.document.ImmutableImportedSDField; import java.util.stream.Stream; @@ -31,6 +32,11 @@ public class AddAttributeTransformToSummaryOfImportedFields extends Processor { search.allImportedFields() .flatMap(this::getSummaryFieldsForImportedField) .forEach(AddAttributeTransformToSummaryOfImportedFields::setAttributeTransform); + search.importedFields().map(fields -> fields.complexFields().values().stream()). + orElse(Stream.empty()). + map(ImmutableImportedSDField::new). + flatMap(this::getSummaryFieldsForImportedField). + forEach(AddAttributeTransformToSummaryOfImportedFields::setAttributeCombinerTransform); } private Stream getSummaryFieldsForImportedField(ImmutableSDField importedField) { @@ -40,4 +46,8 @@ public class AddAttributeTransformToSummaryOfImportedFields extends Processor { private static void setAttributeTransform(SummaryField summaryField) { summaryField.setTransform(SummaryTransform.ATTRIBUTE); } + + private static void setAttributeCombinerTransform(SummaryField summaryField) { + summaryField.setTransform(SummaryTransform.ATTRIBUTECOMBINER); + } } diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/processing/ImportedFieldsResolver.java b/config-model/src/main/java/com/yahoo/searchdefinition/processing/ImportedFieldsResolver.java index a3efd086c6a..bfb2fa9c120 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/processing/ImportedFieldsResolver.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/processing/ImportedFieldsResolver.java @@ -2,11 +2,15 @@ package com.yahoo.searchdefinition.processing; import com.yahoo.config.application.api.DeployLogger; +import com.yahoo.document.ArrayDataType; import com.yahoo.document.DataType; +import com.yahoo.document.MapDataType; +import com.yahoo.document.StructDataType; import com.yahoo.searchdefinition.DocumentReference; import com.yahoo.searchdefinition.DocumentReferences; import com.yahoo.searchdefinition.RankProfileRegistry; import com.yahoo.searchdefinition.Search; +import com.yahoo.searchdefinition.document.Attribute; import com.yahoo.searchdefinition.document.ImmutableSDField; import com.yahoo.searchdefinition.document.ImportedField; import com.yahoo.searchdefinition.document.ImportedFields; @@ -17,6 +21,10 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; +import static com.yahoo.searchdefinition.document.ComplexAttributeFieldUtils.isArrayOfSimpleStruct; +import static com.yahoo.searchdefinition.document.ComplexAttributeFieldUtils.isMapOfPrimitiveType; +import static com.yahoo.searchdefinition.document.ComplexAttributeFieldUtils.isMapOfSimpleStruct; + /** * Iterates all imported fields from SD-parsing and validates and resolves them into concrete fields from referenced document types. * @@ -25,6 +33,7 @@ import java.util.Optional; public class ImportedFieldsResolver extends Processor { private final Map importedFields = new LinkedHashMap<>(); + private final Map importedComplexFields = new LinkedHashMap<>(); private final Optional references; public ImportedFieldsResolver(Search search, DeployLogger deployLogger, RankProfileRegistry rankProfileRegistry, QueryProfiles queryProfiles) { @@ -35,12 +44,86 @@ public class ImportedFieldsResolver extends Processor { @Override public void process(boolean validate, boolean documentsOnly) { search.temporaryImportedFields().get().fields().forEach((name, field) -> resolveImportedField(field, validate)); - search.setImportedFields(new ImportedFields(importedFields)); + search.setImportedFields(new ImportedFields(importedFields, importedComplexFields)); } private void resolveImportedField(TemporaryImportedField importedField, boolean validate) { DocumentReference reference = validateDocumentReference(importedField); - ImmutableSDField targetField = validateTargetField(importedField, reference, validate); + ImmutableSDField targetField = getTargetField(importedField, reference); + if (isArrayOfSimpleStruct(targetField)) { + resolveImportedArrayOfStructField(importedField, reference, targetField, validate); + } else if (isMapOfSimpleStruct(targetField)) { + resolveImportedMapOfStructField(importedField, reference, targetField, validate); + } else if (isMapOfPrimitiveType(targetField)) { + resolveImportedMapOfPrimitiveField(importedField, reference, targetField, validate); + } else { + resolveImportedNormalField(importedField, reference, targetField, validate); + } + } + + private void resolveImportedArrayOfStructField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetField, boolean validate) { + resolveImportedNestedStructField(importedField, reference, targetField, validate); + makeImportedComplexField(importedField, reference, targetField); + } + + private void resolveImportedMapOfStructField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetField, boolean validate) { + resolveImportedNestedField(importedField, reference, targetField.getStructField("key"), validate); + resolveImportedNestedStructField(importedField, reference, targetField.getStructField("value"), validate); + makeImportedComplexField(importedField, reference, targetField); + } + + private void makeImportedComplexField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetField) { + String name = importedField.fieldName(); + importedComplexFields.put(name, new ImportedField(name, reference, targetField)); + } + + private static String makeImportedNestedFieldName(TemporaryImportedField importedField, ImmutableSDField targetNestedField) { + return importedField.fieldName() + targetNestedField.getName().substring(importedField.targetFieldName().length()); + } + + private boolean resolveImportedNestedField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetNestedField, boolean requireAttribute) { + Attribute attribute = targetNestedField.getAttributes().get(targetNestedField.getName()); + String importedNestedFieldName = makeImportedNestedFieldName(importedField, targetNestedField); + if (attribute != null) { + importedFields.put(importedNestedFieldName, new ImportedField(importedNestedFieldName, reference, targetNestedField)); + } else if (requireAttribute) { + fail(importedField, importedNestedFieldName, targetFieldAsString(targetNestedField.getName(), reference) + + ": Is not an attribute field. Only attribute fields supported"); + } + return attribute != null; + } + + private void resolveImportedNestedStructField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetNestedField, boolean validate) { + boolean foundAttribute = false; + for (ImmutableSDField targetStructField : targetNestedField.getStructFields()) { + if (resolveImportedNestedField(importedField, reference, targetStructField, false)) { + foundAttribute = true; + }; + } + if (validate && !foundAttribute) { + String importedNestedFieldName = makeImportedNestedFieldName(importedField, targetNestedField); + fail(importedField, importedNestedFieldName, targetFieldAsString(targetNestedField.getName(), reference) + + ": Is not a struct containing an attribute field."); + } + } + + private void resolveImportedMapOfPrimitiveField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetField, boolean validate) { + resolveImportedNestedField(importedField, reference, targetField.getStructField("key"), validate); + resolveImportedNestedField(importedField, reference, targetField.getStructField("value"), validate); + makeImportedComplexField(importedField, reference, targetField); + } + + private void resolveImportedNormalField(TemporaryImportedField importedField, DocumentReference reference, + ImmutableSDField targetField, boolean validate) { + if (validate) { + validateTargetField(importedField, targetField, reference); + } importedFields.put(importedField.fieldName(), new ImportedField(importedField.fieldName(), reference, targetField)); } @@ -53,30 +136,31 @@ public class ImportedFieldsResolver extends Processor { return reference; } - private ImmutableSDField validateTargetField(TemporaryImportedField importedField, - DocumentReference reference, - boolean validate) { + private ImmutableSDField getTargetField(TemporaryImportedField importedField, + DocumentReference reference) { String targetFieldName = importedField.targetFieldName(); Search targetSearch = reference.targetSearch(); ImmutableSDField targetField = targetSearch.getField(targetFieldName); if (targetField == null) { fail(importedField, targetFieldAsString(targetFieldName, reference) + ": Not found"); } - if (validate) { - if (!targetField.doesAttributing()) { - fail(importedField, targetFieldAsString(targetFieldName, reference) + - ": Is not an attribute field. Only attribute fields supported"); - } else if (targetField.doesIndexing()) { - fail(importedField, targetFieldAsString(targetFieldName, reference) + - ": Is an index field. Not supported"); - } else if (targetField.getDataType().equals(DataType.PREDICATE)) { - fail(importedField, targetFieldAsString(targetFieldName, reference) + - ": Is of type 'predicate'. Not supported"); - } - } return targetField; } + private void validateTargetField(TemporaryImportedField importedField, + ImmutableSDField targetField, DocumentReference reference) { + if (!targetField.doesAttributing()) { + fail(importedField, targetFieldAsString(targetField.getName(), reference) + + ": Is not an attribute field. Only attribute fields supported"); + } else if (targetField.doesIndexing()) { + fail(importedField, targetFieldAsString(targetField.getName(), reference) + + ": Is an index field. Not supported"); + } else if (targetField.getDataType().equals(DataType.PREDICATE)) { + fail(importedField, targetFieldAsString(targetField.getName(), reference) + + ": Is of type 'predicate'. Not supported"); + } + } + private static String targetFieldAsString(String targetFieldName, DocumentReference reference) { return "Field '" + targetFieldName + "' via reference field '" + reference.referenceField().getName() + "'"; } @@ -85,4 +169,8 @@ public class ImportedFieldsResolver extends Processor { throw new IllegalArgumentException("For search '" + search.getName() + "', import field '" + importedField.fieldName() + "': " + msg); } + private void fail(TemporaryImportedField importedField, String importedNestedFieldName, String msg) { + throw new IllegalArgumentException("For search '" + search.getName() + "', import field '" + + importedField.fieldName() + "' (nested to '" + importedNestedFieldName + "'): " + msg); + } } diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/processing/SummaryFieldsMustHaveValidSource.java b/config-model/src/main/java/com/yahoo/searchdefinition/processing/SummaryFieldsMustHaveValidSource.java index c87801685bb..008b3182d8f 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/processing/SummaryFieldsMustHaveValidSource.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/processing/SummaryFieldsMustHaveValidSource.java @@ -51,6 +51,7 @@ public class SummaryFieldsMustHaveValidSource extends Processor { return isDocumentField(source) || (isNotInThisSummaryClass(summary, source) && isSummaryField(source)) || (isInThisSummaryClass(summary, source) && !source.equals(summaryField.getName())) || + (search.importedFields().map(fields -> fields.complexFields().get(source) != null).orElse(false)) || (SummaryClass.DOCUMENT_ID_FIELD.equals(source)); } diff --git a/config-model/src/test/derived/imported_struct_fields/attributes.cfg b/config-model/src/test/derived/imported_struct_fields/attributes.cfg new file mode 100644 index 00000000000..ce6ff5e54ae --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/attributes.cfg @@ -0,0 +1,168 @@ +attribute[0].name "parent_ref" +attribute[0].datatype REFERENCE +attribute[0].collectiontype SINGLE +attribute[0].removeifzero false +attribute[0].createifnonexistent false +attribute[0].fastsearch false +attribute[0].huge false +attribute[0].ismutable false +attribute[0].sortascending true +attribute[0].sortfunction UCA +attribute[0].sortstrength PRIMARY +attribute[0].sortlocale "" +attribute[0].enablebitvectors false +attribute[0].enableonlybitvector false +attribute[0].fastaccess false +attribute[0].arity 8 +attribute[0].lowerbound -9223372036854775808 +attribute[0].upperbound 9223372036854775807 +attribute[0].densepostinglistthreshold 0.4 +attribute[0].tensortype "" +attribute[0].imported false +attribute[1].name "my_elem_array.name" +attribute[1].datatype STRING +attribute[1].collectiontype SINGLE +attribute[1].removeifzero false +attribute[1].createifnonexistent false +attribute[1].fastsearch true +attribute[1].huge false +attribute[1].ismutable false +attribute[1].sortascending true +attribute[1].sortfunction UCA +attribute[1].sortstrength PRIMARY +attribute[1].sortlocale "" +attribute[1].enablebitvectors false +attribute[1].enableonlybitvector false +attribute[1].fastaccess false +attribute[1].arity 8 +attribute[1].lowerbound -9223372036854775808 +attribute[1].upperbound 9223372036854775807 +attribute[1].densepostinglistthreshold 0.4 +attribute[1].tensortype "" +attribute[1].imported true +attribute[2].name "my_elem_array.weight" +attribute[2].datatype INT32 +attribute[2].collectiontype SINGLE +attribute[2].removeifzero false +attribute[2].createifnonexistent false +attribute[2].fastsearch false +attribute[2].huge false +attribute[2].ismutable false +attribute[2].sortascending true +attribute[2].sortfunction UCA +attribute[2].sortstrength PRIMARY +attribute[2].sortlocale "" +attribute[2].enablebitvectors false +attribute[2].enableonlybitvector false +attribute[2].fastaccess false +attribute[2].arity 8 +attribute[2].lowerbound -9223372036854775808 +attribute[2].upperbound 9223372036854775807 +attribute[2].densepostinglistthreshold 0.4 +attribute[2].tensortype "" +attribute[2].imported true +attribute[3].name "my_elem_map.key" +attribute[3].datatype STRING +attribute[3].collectiontype SINGLE +attribute[3].removeifzero false +attribute[3].createifnonexistent false +attribute[3].fastsearch true +attribute[3].huge false +attribute[3].ismutable false +attribute[3].sortascending true +attribute[3].sortfunction UCA +attribute[3].sortstrength PRIMARY +attribute[3].sortlocale "" +attribute[3].enablebitvectors false +attribute[3].enableonlybitvector false +attribute[3].fastaccess false +attribute[3].arity 8 +attribute[3].lowerbound -9223372036854775808 +attribute[3].upperbound 9223372036854775807 +attribute[3].densepostinglistthreshold 0.4 +attribute[3].tensortype "" +attribute[3].imported true +attribute[4].name "my_elem_map.value.name" +attribute[4].datatype STRING +attribute[4].collectiontype SINGLE +attribute[4].removeifzero false +attribute[4].createifnonexistent false +attribute[4].fastsearch true +attribute[4].huge false +attribute[4].ismutable false +attribute[4].sortascending true +attribute[4].sortfunction UCA +attribute[4].sortstrength PRIMARY +attribute[4].sortlocale "" +attribute[4].enablebitvectors false +attribute[4].enableonlybitvector false +attribute[4].fastaccess false +attribute[4].arity 8 +attribute[4].lowerbound -9223372036854775808 +attribute[4].upperbound 9223372036854775807 +attribute[4].densepostinglistthreshold 0.4 +attribute[4].tensortype "" +attribute[4].imported true +attribute[5].name "my_elem_map.value.weight" +attribute[5].datatype INT32 +attribute[5].collectiontype SINGLE +attribute[5].removeifzero false +attribute[5].createifnonexistent false +attribute[5].fastsearch false +attribute[5].huge false +attribute[5].ismutable false +attribute[5].sortascending true +attribute[5].sortfunction UCA +attribute[5].sortstrength PRIMARY +attribute[5].sortlocale "" +attribute[5].enablebitvectors false +attribute[5].enableonlybitvector false +attribute[5].fastaccess false +attribute[5].arity 8 +attribute[5].lowerbound -9223372036854775808 +attribute[5].upperbound 9223372036854775807 +attribute[5].densepostinglistthreshold 0.4 +attribute[5].tensortype "" +attribute[5].imported true +attribute[6].name "my_str_int_map.key" +attribute[6].datatype STRING +attribute[6].collectiontype SINGLE +attribute[6].removeifzero false +attribute[6].createifnonexistent false +attribute[6].fastsearch true +attribute[6].huge false +attribute[6].ismutable false +attribute[6].sortascending true +attribute[6].sortfunction UCA +attribute[6].sortstrength PRIMARY +attribute[6].sortlocale "" +attribute[6].enablebitvectors false +attribute[6].enableonlybitvector false +attribute[6].fastaccess false +attribute[6].arity 8 +attribute[6].lowerbound -9223372036854775808 +attribute[6].upperbound 9223372036854775807 +attribute[6].densepostinglistthreshold 0.4 +attribute[6].tensortype "" +attribute[6].imported true +attribute[7].name "my_str_int_map.value" +attribute[7].datatype INT32 +attribute[7].collectiontype SINGLE +attribute[7].removeifzero false +attribute[7].createifnonexistent false +attribute[7].fastsearch false +attribute[7].huge false +attribute[7].ismutable false +attribute[7].sortascending true +attribute[7].sortfunction UCA +attribute[7].sortstrength PRIMARY +attribute[7].sortlocale "" +attribute[7].enablebitvectors false +attribute[7].enableonlybitvector false +attribute[7].fastaccess false +attribute[7].arity 8 +attribute[7].lowerbound -9223372036854775808 +attribute[7].upperbound 9223372036854775807 +attribute[7].densepostinglistthreshold 0.4 +attribute[7].tensortype "" +attribute[7].imported true \ No newline at end of file diff --git a/config-model/src/test/derived/imported_struct_fields/child.sd b/config-model/src/test/derived/imported_struct_fields/child.sd new file mode 100644 index 00000000000..8453031022b --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/child.sd @@ -0,0 +1,19 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +search child { + document child { + field parent_ref type reference { + indexing: attribute | summary + } + } + import field parent_ref.elem_array as my_elem_array {} + import field parent_ref.elem_map as my_elem_map {} + import field parent_ref.str_int_map as my_str_int_map {} + + document-summary mysummary { + summary documentid type string {} + summary my_elem_array type array {} + summary my_elem_map type map {} + summary my_str_int_map type map {} + } +} + diff --git a/config-model/src/test/derived/imported_struct_fields/imported-fields.cfg b/config-model/src/test/derived/imported_struct_fields/imported-fields.cfg new file mode 100644 index 00000000000..772e5cffec9 --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/imported-fields.cfg @@ -0,0 +1,35 @@ +attribute[0].name "my_elem_array.name" +attribute[0].referencefield "parent_ref" +attribute[0].targetfield "elem_array.name" +attribute[0].datatype NONE +attribute[0].collectiontype SINGLE +attribute[1].name "my_elem_array.weight" +attribute[1].referencefield "parent_ref" +attribute[1].targetfield "elem_array.weight" +attribute[1].datatype NONE +attribute[1].collectiontype SINGLE +attribute[2].name "my_elem_map.key" +attribute[2].referencefield "parent_ref" +attribute[2].targetfield "elem_map.key" +attribute[2].datatype NONE +attribute[2].collectiontype SINGLE +attribute[3].name "my_elem_map.value.name" +attribute[3].referencefield "parent_ref" +attribute[3].targetfield "elem_map.value.name" +attribute[3].datatype NONE +attribute[3].collectiontype SINGLE +attribute[4].name "my_elem_map.value.weight" +attribute[4].referencefield "parent_ref" +attribute[4].targetfield "elem_map.value.weight" +attribute[4].datatype NONE +attribute[4].collectiontype SINGLE +attribute[5].name "my_str_int_map.key" +attribute[5].referencefield "parent_ref" +attribute[5].targetfield "str_int_map.key" +attribute[5].datatype NONE +attribute[5].collectiontype SINGLE +attribute[6].name "my_str_int_map.value" +attribute[6].referencefield "parent_ref" +attribute[6].targetfield "str_int_map.value" +attribute[6].datatype NONE +attribute[6].collectiontype SINGLE \ No newline at end of file diff --git a/config-model/src/test/derived/imported_struct_fields/index-info.cfg b/config-model/src/test/derived/imported_struct_fields/index-info.cfg new file mode 100644 index 00000000000..66448099e84 --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/index-info.cfg @@ -0,0 +1,37 @@ +indexinfo[0].name "child" +indexinfo[0].command[0].indexname "sddocname" +indexinfo[0].command[0].command "index" +indexinfo[0].command[1].indexname "sddocname" +indexinfo[0].command[1].command "word" +indexinfo[0].command[2].indexname "parent_ref" +indexinfo[0].command[2].command "index" +indexinfo[0].command[3].indexname "parent_ref" +indexinfo[0].command[3].command "attribute" +indexinfo[0].command[4].indexname "parent_ref" +indexinfo[0].command[4].command "word" +indexinfo[0].command[5].indexname "documentid" +indexinfo[0].command[5].command "index" +indexinfo[0].command[6].indexname "rankfeatures" +indexinfo[0].command[6].command "index" +indexinfo[0].command[7].indexname "summaryfeatures" +indexinfo[0].command[7].command "index" +indexinfo[0].command[8].indexname "my_elem_array.name" +indexinfo[0].command[8].command "index" +indexinfo[0].command[9].indexname "my_elem_array.weight" +indexinfo[0].command[9].command "index" +indexinfo[0].command[10].indexname "my_elem_array.weight" +indexinfo[0].command[10].command "numerical" +indexinfo[0].command[11].indexname "my_elem_map.key" +indexinfo[0].command[11].command "index" +indexinfo[0].command[12].indexname "my_elem_map.value.name" +indexinfo[0].command[12].command "index" +indexinfo[0].command[13].indexname "my_elem_map.value.weight" +indexinfo[0].command[13].command "index" +indexinfo[0].command[14].indexname "my_elem_map.value.weight" +indexinfo[0].command[14].command "numerical" +indexinfo[0].command[15].indexname "my_str_int_map.key" +indexinfo[0].command[15].command "index" +indexinfo[0].command[16].indexname "my_str_int_map.value" +indexinfo[0].command[16].command "index" +indexinfo[0].command[17].indexname "my_str_int_map.value" +indexinfo[0].command[17].command "numerical" \ No newline at end of file diff --git a/config-model/src/test/derived/imported_struct_fields/indexschema.cfg b/config-model/src/test/derived/imported_struct_fields/indexschema.cfg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/config-model/src/test/derived/imported_struct_fields/parent.sd b/config-model/src/test/derived/imported_struct_fields/parent.sd new file mode 100644 index 00000000000..7419cb465fd --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/parent.sd @@ -0,0 +1,43 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +search parent { + document parent { + struct elem { + field name type string {} + field weight type int {} + } + field elem_array type array { + indexing: summary + struct-field name { + indexing: attribute + attribute: fast-search + } + struct-field weight { + indexing: attribute + } + } + field elem_map type map { + indexing: summary + struct-field key { + indexing: attribute + attribute: fast-search + } + struct-field value.name { + indexing: attribute + attribute: fast-search + } + struct-field value.weight { + indexing: attribute + } + } + field str_int_map type map { + indexing: summary + struct-field key { + indexing: attribute + attribute: fast-search + } + struct-field value { + indexing: attribute + } + } + } +} diff --git a/config-model/src/test/derived/imported_struct_fields/summary.cfg b/config-model/src/test/derived/imported_struct_fields/summary.cfg new file mode 100644 index 00000000000..666da5bbc76 --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/summary.cfg @@ -0,0 +1,31 @@ +defaultsummaryid 1570252291 +classes[0].id 1570252291 +classes[0].name "default" +classes[0].fields[0].name "parent_ref" +classes[0].fields[0].type "longstring" +classes[0].fields[1].name "rankfeatures" +classes[0].fields[1].type "featuredata" +classes[0].fields[2].name "summaryfeatures" +classes[0].fields[2].type "featuredata" +classes[0].fields[3].name "documentid" +classes[0].fields[3].type "longstring" +classes[1].id 2126652894 +classes[1].name "mysummary" +classes[1].fields[0].name "documentid" +classes[1].fields[0].type "longstring" +classes[1].fields[1].name "my_elem_array" +classes[1].fields[1].type "jsonstring" +classes[1].fields[2].name "my_elem_map" +classes[1].fields[2].type "jsonstring" +classes[1].fields[3].name "my_str_int_map" +classes[1].fields[3].type "jsonstring" +classes[1].fields[4].name "rankfeatures" +classes[1].fields[4].type "featuredata" +classes[1].fields[5].name "summaryfeatures" +classes[1].fields[5].type "featuredata" +classes[2].id 1274088866 +classes[2].name "attributeprefetch" +classes[2].fields[0].name "rankfeatures" +classes[2].fields[0].type "featuredata" +classes[2].fields[1].name "summaryfeatures" +classes[2].fields[1].type "featuredata" \ No newline at end of file diff --git a/config-model/src/test/derived/imported_struct_fields/summarymap.cfg b/config-model/src/test/derived/imported_struct_fields/summarymap.cfg new file mode 100644 index 00000000000..0b869417aef --- /dev/null +++ b/config-model/src/test/derived/imported_struct_fields/summarymap.cfg @@ -0,0 +1,16 @@ +defaultoutputclass -1 +override[0].field "my_elem_array" +override[0].command "attributecombiner" +override[0].arguments "" +override[1].field "my_elem_map" +override[1].command "attributecombiner" +override[1].arguments "" +override[2].field "my_str_int_map" +override[2].command "attributecombiner" +override[2].arguments "" +override[3].field "rankfeatures" +override[3].command "rankfeatures" +override[3].arguments "" +override[4].field "summaryfeatures" +override[4].command "summaryfeatures" +override[4].arguments "" \ No newline at end of file diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/derived/ImportedFieldsTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/derived/ImportedFieldsTestCase.java index eecd03cbe5b..f7641f97df6 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/derived/ImportedFieldsTestCase.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/derived/ImportedFieldsTestCase.java @@ -15,4 +15,9 @@ public class ImportedFieldsTestCase extends AbstractExportingTestCase { public void configs_for_imported_fields_are_derived() throws IOException, ParseException { assertCorrectDeriving("importedfields", "child"); } + + @Test + public void configs_for_imported_struct_fields_are_derived() throws IOException, ParseException { + assertCorrectDeriving("imported_struct_fields", "child"); + } } diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFieldsTest.java b/config-model/src/test/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFieldsTest.java index 48adc0eefc5..3735b997073 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFieldsTest.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/AddAttributeTransformToSummaryOfImportedFieldsTest.java @@ -54,7 +54,7 @@ public class AddAttributeTransformToSummaryOfImportedFieldsTest { SDField targetField = new SDField("target_field", DataType.INT); DocumentReference documentReference = new DocumentReference(new Field("reference_field"), targetSearch); ImportedField importedField = new ImportedField(fieldName, documentReference, targetField); - return new ImportedFields(Collections.singletonMap(fieldName, importedField)); + return new ImportedFields(Collections.singletonMap(fieldName, importedField), Collections.emptyMap()); } private static DocumentSummary createDocumentSummary(String fieldName) { 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 index 9b63c1cafe9..bb446a15702 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java @@ -9,9 +9,13 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import java.util.ArrayList; +import java.util.List; + import static org.junit.Assert.assertEquals; import static com.yahoo.config.model.test.TestUtil.joinLines; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * @author geirst @@ -20,14 +24,14 @@ public class ImportedFieldsTestCase { @Test public void fields_can_be_imported_from_referenced_document_types() throws ParseException { - Search search = buildAdSearch(joinLines( - "search ad {", - " document ad {", - " field campaign_ref type reference { indexing: attribute }", - " field person_ref type reference { indexing: attribute }", - " }", - " import field campaign_ref.budget as my_budget {}", - " import field person_ref.name as my_name {}", + Search search = buildAdSearch(joinLines( + "search ad {", + " document ad {", + " field campaign_ref type reference { indexing: attribute }", + " field person_ref type reference { indexing: attribute }", + " }", + " import field campaign_ref.budget as my_budget {}", + " import field person_ref.name as my_name {}", "}")); assertEquals(2, search.importedFields().get().fields().size()); assertSearchContainsImportedField("my_budget", "campaign_ref", "campaign", "budget", search); @@ -65,6 +69,173 @@ public class ImportedFieldsTestCase { return builder.getSearch("ad"); } + private static void check_struct_import(ParentSdBuilder parentBuilder) throws ParseException { + Search search = buildChildSearch(parentBuilder.build(), joinLines("search child {", + " document child {", + " field parent_ref type reference {", + " indexing: attribute | summary", + " }", + " }", + " import field parent_ref.elem_array as my_elem_array {}", + " import field parent_ref.elem_map as my_elem_map {}", + " import field parent_ref.str_int_map as my_str_int_map {}", + "}")); + assertEquals(parentBuilder.countAttrs(), search.importedFields().get().fields().size()); + checkImportedField("my_elem_array.name", "parent_ref", "parent", "elem_array.name", search, parentBuilder.elem_array_name_attr); + checkImportedField("my_elem_array.weight", "parent_ref", "parent", "elem_array.weight", search, parentBuilder.elem_array_weight_attr); + checkImportedField("my_elem_map.key", "parent_ref", "parent", "elem_map.key", search, parentBuilder.elem_map_key_attr); + checkImportedField("my_elem_map.value.name", "parent_ref", "parent", "elem_map.value.name", search, parentBuilder.elem_map_value_name_attr); + checkImportedField("my_elem_map.value.weight", "parent_ref", "parent", "elem_map.value.weight", search, parentBuilder.elem_map_value_weight_attr); + checkImportedField("my_str_int_map.key", "parent_ref", "parent", "str_int_map.key", search, parentBuilder.str_int_map_key_attr); + checkImportedField("my_str_int_map.value", "parent_ref", "parent", "str_int_map.value", search, parentBuilder.str_int_map_value_attr); + } + + @Test + public void check_struct_import() throws ParseException { + check_struct_import(new ParentSdBuilder()); + check_struct_import(new ParentSdBuilder().elem_array_weight_attr(false).elem_map_value_weight_attr(false)); + check_struct_import(new ParentSdBuilder().elem_array_name_attr(false).elem_map_value_name_attr(false)); + } + + @Test + public void check_illegal_stroct_import_missing_array_of_struct_attributes() throws ParseException { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("For search 'child', import field 'my_elem_array' (nested to 'my_elem_array'): Field 'elem_array' via reference field 'parent_ref': Is not a struct containing an attribute field."); + check_struct_import(new ParentSdBuilder().elem_array_name_attr(false).elem_array_weight_attr(false)); + } + + @Test + public void check_illegal_struct_import_missing_map_of_struct_key_attribute() throws ParseException { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("For search 'child', import field 'my_elem_map' (nested to 'my_elem_map.key'): Field 'elem_map.key' via reference field 'parent_ref': Is not an attribute field. Only attribute fields supported"); + check_struct_import(new ParentSdBuilder().elem_map_key_attr(false)); + } + + @Test + public void check_illegal_struct_import_missing_map_of_struct_value_attributes() throws ParseException { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("For search 'child', import field 'my_elem_map' (nested to 'my_elem_map.value'): Field 'elem_map.value' via reference field 'parent_ref': Is not a struct containing an attribute field."); + check_struct_import(new ParentSdBuilder().elem_map_value_name_attr(false).elem_map_value_weight_attr(false)); + } + + @Test + public void check_illegal_struct_import_missing_map_of_primitive_key_attribute() throws ParseException { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("For search 'child', import field 'my_str_int_map' (nested to 'my_str_int_map.key'): Field 'str_int_map.key' via reference field 'parent_ref': Is not an attribute field. Only attribute fields supported"); + check_struct_import(new ParentSdBuilder().str_int_map_key_attr(false)); + } + + @Test + public void check_illegal_struct_import_missing_map_of_primitive_value_attribute() throws ParseException { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("For search 'child', import field 'my_str_int_map' (nested to 'my_str_int_map.value'): Field 'str_int_map.value' via reference field 'parent_ref': Is not an attribute field. Only attribute fields supported"); + check_struct_import(new ParentSdBuilder().str_int_map_value_attr(false)); + } + + private static class ParentSdBuilder { + private boolean elem_array_name_attr; + private boolean elem_array_weight_attr; + private boolean elem_map_key_attr; + private boolean elem_map_value_name_attr; + private boolean elem_map_value_weight_attr; + private boolean str_int_map_key_attr; + private boolean str_int_map_value_attr; + + public ParentSdBuilder() { + elem_array_name_attr = true; + elem_array_weight_attr = true; + elem_map_key_attr = true; + elem_map_value_name_attr = true; + elem_map_value_weight_attr = true; + str_int_map_key_attr = true; + str_int_map_value_attr = true; + } + + public ParentSdBuilder elem_array_name_attr(boolean v) { elem_array_name_attr = v; return this; } + public ParentSdBuilder elem_array_weight_attr(boolean v) { elem_array_weight_attr = v; return this; } + public ParentSdBuilder elem_map_key_attr(boolean v) { elem_map_key_attr = v; return this; } + public ParentSdBuilder elem_map_value_name_attr(boolean v) { elem_map_value_name_attr = v; return this; } + public ParentSdBuilder elem_map_value_weight_attr(boolean v) { elem_map_value_weight_attr = v; return this; } + public ParentSdBuilder str_int_map_key_attr(boolean v) { str_int_map_key_attr = v; return this; } + public ParentSdBuilder str_int_map_value_attr(boolean v) { str_int_map_value_attr = v; return this; } + + public String build() { + return joinLines("search parent {", + " document parent {", + " struct elem {", + " field name type string {}", + " field weight type int {}", + " }", + " field elem_array type array {", + " indexing: summary", + " struct-field name {", + structFieldSpec(elem_array_name_attr, true), + " }", + " struct-field weight {", + structFieldSpec(elem_array_weight_attr, false), + " }", + " }", + " field elem_map type map {", + " indexing: summary", + " struct-field key {", + structFieldSpec(elem_map_key_attr, true), + " }", + " struct-field value.name {", + structFieldSpec(elem_map_value_name_attr, true), + " }", + " struct-field value.weight {", + structFieldSpec(elem_map_value_weight_attr, false), + " }", + " }", + " field str_int_map type map {", + " indexing: summary", + " struct-field key {", + structFieldSpec(str_int_map_key_attr, true), + " }", + " struct-field value {", + structFieldSpec(str_int_map_value_attr, false), + " }", + " }", + " }", + "}"); + } + + private static String structFieldSpec(boolean isAttribute, boolean isFastSearch) { + List result = new ArrayList(); + if (isAttribute) { + result.add(" indexing: attribute"); + if (isFastSearch) { + result.add(" attribute: fast-search"); + } + } + return String.join("\n", result); + } + + private static int b2i(boolean b) { + return b ? 1 : 0; + } + + public int countAttrs() { + int elem_array_attr_count = b2i(elem_array_name_attr) + b2i(elem_array_weight_attr); + int elem_map_attr_count = b2i(elem_map_key_attr) + b2i(elem_map_value_name_attr) + b2i(elem_map_value_weight_attr); + int str_int_map_attr_count = b2i(str_int_map_key_attr) + b2i(str_int_map_value_attr); + return elem_array_attr_count + elem_map_attr_count + str_int_map_attr_count; + } + } + + private static Search buildChildSearch(String parentSdContent, String sdContent) throws ParseException { + SearchBuilder builder = new SearchBuilder(); + builder.importString(parentSdContent); + builder.importString(sdContent); + builder.build(); + return builder.getSearch("child"); + } + + private static void assertSearchNotContainsImportedField(String fieldName, Search search) { + ImportedField importedField = search.importedFields().get().fields().get(fieldName); + assertNull(importedField); + } + private static void assertSearchContainsImportedField(String fieldName, String referenceFieldName, String referenceDocType, @@ -77,4 +248,13 @@ public class ImportedFieldsTestCase { assertEquals(referenceDocType, importedField.reference().targetSearch().getName()); assertEquals(targetFieldName, importedField.targetField().getName()); } + + private static void checkImportedField(String fieldName, String referenceFieldName, String referenceDocType, + String targetFieldName, Search search, boolean present) { + if (present) { + assertSearchContainsImportedField(fieldName, referenceFieldName, referenceDocType, targetFieldName, search); + } else { + assertSearchNotContainsImportedField(fieldName, search); + } + } } diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ValidateFieldTypesTest.java b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ValidateFieldTypesTest.java index d0b6524a7e1..e4c23f407c8 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ValidateFieldTypesTest.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ValidateFieldTypesTest.java @@ -55,7 +55,7 @@ public class ValidateFieldTypesTest { SDField targetField = new SDField("target_field", dataType); DocumentReference documentReference = new DocumentReference(new Field("reference_field"), targetSearch); ImportedField importedField = new ImportedField(fieldName, documentReference, targetField); - return new ImportedFields(Collections.singletonMap(fieldName, importedField)); + return new ImportedFields(Collections.singletonMap(fieldName, importedField), Collections.emptyMap()); } private static DocumentSummary createDocumentSummary(String fieldName, DataType dataType) { -- cgit v1.2.3 From a92d0b2c764aa4d3e0acc99955ca1abc23a96f9d Mon Sep 17 00:00:00 2001 From: Tor Egge Date: Tue, 27 Nov 2018 15:07:13 +0100 Subject: Fix typo. Factor out logic to check for nested field name. Use camel case instead of underscore for compound function name. Simplify test. --- .../searchdefinition/derived/ImportedFields.java | 8 +++- .../processing/ImportedFieldsTestCase.java | 48 +++++++++------------- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java b/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java index a69581559e5..82b56f9c961 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/derived/ImportedFields.java @@ -39,11 +39,15 @@ public class ImportedFields extends Derived implements ImportedFieldsConfig.Prod } } + private static boolean isNestedFieldName(String fieldName) { + return fieldName.indexOf('.') != -1; + } + private static void considerField(ImportedFieldsConfig.Builder builder, ImportedField field) { ImmutableSDField targetField = field.targetField(); String targetFieldName = targetField.getName(); - if (targetFieldName.indexOf('.') == -1) { - if (field.targetField().doesAttributing()) { + if (!isNestedFieldName(targetFieldName)) { + if (targetField.doesAttributing()) { builder.attribute.add(createAttributeBuilder(field)); } } else { 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 index bb446a15702..4167e534653 100644 --- a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java +++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImportedFieldsTestCase.java @@ -9,9 +9,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import java.util.ArrayList; -import java.util.List; - import static org.junit.Assert.assertEquals; import static com.yahoo.config.model.test.TestUtil.joinLines; import static org.junit.Assert.assertNotNull; @@ -69,7 +66,7 @@ public class ImportedFieldsTestCase { return builder.getSearch("ad"); } - private static void check_struct_import(ParentSdBuilder parentBuilder) throws ParseException { + private static void checkStructImport(ParentSdBuilder parentBuilder) throws ParseException { Search search = buildChildSearch(parentBuilder.build(), joinLines("search child {", " document child {", " field parent_ref type reference {", @@ -92,44 +89,44 @@ public class ImportedFieldsTestCase { @Test public void check_struct_import() throws ParseException { - check_struct_import(new ParentSdBuilder()); - check_struct_import(new ParentSdBuilder().elem_array_weight_attr(false).elem_map_value_weight_attr(false)); - check_struct_import(new ParentSdBuilder().elem_array_name_attr(false).elem_map_value_name_attr(false)); + checkStructImport(new ParentSdBuilder()); + checkStructImport(new ParentSdBuilder().elem_array_weight_attr(false).elem_map_value_weight_attr(false)); + checkStructImport(new ParentSdBuilder().elem_array_name_attr(false).elem_map_value_name_attr(false)); } @Test - public void check_illegal_stroct_import_missing_array_of_struct_attributes() throws ParseException { + public void check_illegal_struct_import_missing_array_of_struct_attributes() throws ParseException { exception.expect(IllegalArgumentException.class); exception.expectMessage("For search 'child', import field 'my_elem_array' (nested to 'my_elem_array'): Field 'elem_array' via reference field 'parent_ref': Is not a struct containing an attribute field."); - check_struct_import(new ParentSdBuilder().elem_array_name_attr(false).elem_array_weight_attr(false)); + checkStructImport(new ParentSdBuilder().elem_array_name_attr(false).elem_array_weight_attr(false)); } @Test public void check_illegal_struct_import_missing_map_of_struct_key_attribute() throws ParseException { exception.expect(IllegalArgumentException.class); exception.expectMessage("For search 'child', import field 'my_elem_map' (nested to 'my_elem_map.key'): Field 'elem_map.key' via reference field 'parent_ref': Is not an attribute field. Only attribute fields supported"); - check_struct_import(new ParentSdBuilder().elem_map_key_attr(false)); + checkStructImport(new ParentSdBuilder().elem_map_key_attr(false)); } @Test public void check_illegal_struct_import_missing_map_of_struct_value_attributes() throws ParseException { exception.expect(IllegalArgumentException.class); exception.expectMessage("For search 'child', import field 'my_elem_map' (nested to 'my_elem_map.value'): Field 'elem_map.value' via reference field 'parent_ref': Is not a struct containing an attribute field."); - check_struct_import(new ParentSdBuilder().elem_map_value_name_attr(false).elem_map_value_weight_attr(false)); + checkStructImport(new ParentSdBuilder().elem_map_value_name_attr(false).elem_map_value_weight_attr(false)); } @Test public void check_illegal_struct_import_missing_map_of_primitive_key_attribute() throws ParseException { exception.expect(IllegalArgumentException.class); exception.expectMessage("For search 'child', import field 'my_str_int_map' (nested to 'my_str_int_map.key'): Field 'str_int_map.key' via reference field 'parent_ref': Is not an attribute field. Only attribute fields supported"); - check_struct_import(new ParentSdBuilder().str_int_map_key_attr(false)); + checkStructImport(new ParentSdBuilder().str_int_map_key_attr(false)); } @Test public void check_illegal_struct_import_missing_map_of_primitive_value_attribute() throws ParseException { exception.expect(IllegalArgumentException.class); exception.expectMessage("For search 'child', import field 'my_str_int_map' (nested to 'my_str_int_map.value'): Field 'str_int_map.value' via reference field 'parent_ref': Is not an attribute field. Only attribute fields supported"); - check_struct_import(new ParentSdBuilder().str_int_map_value_attr(false)); + checkStructImport(new ParentSdBuilder().str_int_map_value_attr(false)); } private static class ParentSdBuilder { @@ -169,46 +166,39 @@ public class ImportedFieldsTestCase { " field elem_array type array {", " indexing: summary", " struct-field name {", - structFieldSpec(elem_array_name_attr, true), + structFieldSpec(elem_array_name_attr), " }", " struct-field weight {", - structFieldSpec(elem_array_weight_attr, false), + structFieldSpec(elem_array_weight_attr), " }", " }", " field elem_map type map {", " indexing: summary", " struct-field key {", - structFieldSpec(elem_map_key_attr, true), + structFieldSpec(elem_map_key_attr), " }", " struct-field value.name {", - structFieldSpec(elem_map_value_name_attr, true), + structFieldSpec(elem_map_value_name_attr), " }", " struct-field value.weight {", - structFieldSpec(elem_map_value_weight_attr, false), + structFieldSpec(elem_map_value_weight_attr), " }", " }", " field str_int_map type map {", " indexing: summary", " struct-field key {", - structFieldSpec(str_int_map_key_attr, true), + structFieldSpec(str_int_map_key_attr), " }", " struct-field value {", - structFieldSpec(str_int_map_value_attr, false), + structFieldSpec(str_int_map_value_attr), " }", " }", " }", "}"); } - private static String structFieldSpec(boolean isAttribute, boolean isFastSearch) { - List result = new ArrayList(); - if (isAttribute) { - result.add(" indexing: attribute"); - if (isFastSearch) { - result.add(" attribute: fast-search"); - } - } - return String.join("\n", result); + private static String structFieldSpec(boolean isAttribute) { + return isAttribute ? " indexing: attribute" : ""; } private static int b2i(boolean b) { -- cgit v1.2.3