diff --git a/content/modules/search/examples/search-ex1/src/main/java/com/company/demo/service/CustomerIndexDefinition.java b/content/modules/search/examples/search-ex1/src/main/java/com/company/demo/service/CustomerIndexDefinition.java index beed5343..53d30faa 100644 --- a/content/modules/search/examples/search-ex1/src/main/java/com/company/demo/service/CustomerIndexDefinition.java +++ b/content/modules/search/examples/search-ex1/src/main/java/com/company/demo/service/CustomerIndexDefinition.java @@ -29,16 +29,44 @@ public interface CustomerIndexDefinition { // tag::manual-mapping[] @ManualMappingDefinition // <1> - default MappingDefinition mapping(FilePropertyValueExtractor filePropertyValueExtractor) { // <2> + default MappingDefinition mapping(FilePropertyValueExtractor filePropertyValueExtractor, // <2> + AutoMappingStrategy autoMappingStrategy, + SimplePropertyValueExtractor simplePropertyValueExtractor) { return MappingDefinition.builder() .addStaticAttributesGroup( StaticAttributesGroupConfiguration.builder() .includeProperties("*") // <3> - .excludeProperties("hobby", "maritalStatus") // <4> + .excludeProperties("hobby", "maritalStatus", "firstName", "lastName") // <4> .withFieldMappingStrategyClass(AutoMappingStrategy.class) // <5> .withPropertyValueExtractor(filePropertyValueExtractor) // <6> .build() ) + .addStaticAttributesGroup( // <7> + StaticAttributesGroupConfiguration.builder() + .includeProperties("firstName") + .withFieldMappingStrategy(autoMappingStrategy) // <8> + .withFieldConfiguration( // <9> + "{\n" + + " \"type\": \"text\",\n" + + " \"analyzer\": \"standard\",\n" + + " \"boost\": 2\n" + + "}" + ) + .build() + ) + .addStaticAttributesGroup( + StaticAttributesGroupConfiguration.builder() + .includeProperties("lastName") + .withFieldConfiguration( // <10> + "{\n" + + " \"type\": \"text\",\n" + + " \"analyzer\": \"english\"\n" + + "}" + ) + .withPropertyValueExtractor(simplePropertyValueExtractor) // <11> + .withOrder(1) // <12> + .build() + ) .build(); } // end::manual-mapping[] @@ -56,48 +84,6 @@ default Predicate indexCustomerWithGoldStatusOnlyPredicate(DataManager }; } // end::predicate[] - - // tag::text-config[] -// @ManualMappingDefinition -// default MappingDefinition mappingMethod(AutoMappingStrategy autoMappingStrategy, -// SimplePropertyValueExtractor simplePropertyValueExtractor) { -// return MappingDefinition.builder() -// .addStaticAttributesGroup( -// StaticAttributesGroupConfiguration.builder() -// .includeProperties("*") -// .excludeProperties("firstName", "lastName") // <1> -// .withFieldMappingStrategyClass(AutoMappingStrategy.class) -// .build() -// ) -// .addStaticAttributesGroup( -// StaticAttributesGroupConfiguration.builder() -// .includeProperties("firstName") // <2> -// .withFieldMappingStrategy(autoMappingStrategy) // <3> -// .withFieldConfiguration( // <4> -// "{\n" + -// " \"type\": \"text\",\n" + -// " \"analyzer\": \"standard\",\n" + -// " \"boost\": 2\n" + -// "}" -// ) -// .build() -// ) -// .addStaticAttributesGroup( -// StaticAttributesGroupConfiguration.builder() -// .includeProperties("lastName") -// .withFieldConfiguration( // <5> -// "{\n" + -// " \"type\": \"text\",\n" + -// " \"analyzer\": \"english\"\n" + -// "}" -// ) -// .withPropertyValueExtractor(simplePropertyValueExtractor) // <6> -// .withOrder(1) // <7> -// .build() -// ) -// .build(); -// } -// end::text-config[] // tag::interface[] } // end::interface[] \ No newline at end of file diff --git a/content/modules/search/pages/index-definitions.adoc b/content/modules/search/pages/index-definitions.adoc index fa7f0ae1..45dda8a6 100644 --- a/content/modules/search/pages/index-definitions.adoc +++ b/content/modules/search/pages/index-definitions.adoc @@ -29,7 +29,7 @@ Indexed entity properties are specified using methods within the interface. Thes * They can be named arbitrarily. * They should not accept parameters. * They should not contain any implementation logic. -* Each method should be annotated with the `@AutoMappedField` annotation. +* Each method should be annotated with a field-mapping annotation: `@AutoMappedField` for static attributes, or `@DynamicAttributes` for xref:dyn-attr:index.adoc[dynamic attributes] (see xref:search:dyn-attr-support.adoc[]). [source,java,indent=0] ---- @@ -248,6 +248,11 @@ Furthermore, the system supports collection attributes, which include nested col Within the array, you'll find values of the `name` attribute from all instances of `EntityB` within all instances of `EntityA` in the root entity. +[[dynamic-attributes]] +== Dynamic Attributes + +In addition to static attributes mapped with `@AutoMappedField`, the Search add-on can index xref:dyn-attr:index.adoc[dynamic attributes] of an entity. Add the `@DynamicAttributes` annotation to a method of the index definition interface. See xref:search:dyn-attr-support.adoc[] for the annotation parameters, supported attribute types, and limitations. + [[programmatic-mapping]] == Programmatic Mapping @@ -269,30 +274,23 @@ include::example$/search-ex1/src/main/java/com/company/demo/service/CustomerInde ---- <1> The `@ManualMappingDefinition` annotation marks methods with manual creation of mapping definition. <2> You can pass Spring beans as parameters for custom mapping configuration. -<3> The list of properties that should be indexed. Here the `*` wildcard is used to include all local properties of the indexed `Customer` entity. -<4> The list of properties that should not be indexed. -<5> The `FieldMappingStrategy` implementation class that should be used to map properties. The mapping strategy can also be defined as an instance using the `withFieldMappingStrategy()` method with the strategy instance as a parameter. -<6> An explicit property value extractor. For example, a `FilePropertyValueExtractor` instance can be used for processing attributes of the `FileRef` type. - -// todo restore -// There is an option to define a text configuration for property mapping, for example: -// -// [source,java,indent=0] -// ---- -// include::example$/search-ex1/src/main/java/com/company/demo/service/CustomerIndexDefinition.java[tags=text-config] -// ---- -// <1> Excludes two specific properties: `firstName` and `lastName`. They will be processed separately by the following elements for fine-tuning. -// <2> Applies only to the `firstName` field. -// <3> First applies the automatic mapping strategy (to obtain a base mapping). -// <4> Defines field configuration as String json object with native configuration. The settings generated by the strategy are overridden and extended: -// * `"type": "text"` — explicitly specifies the text type. -// * `"analyzer": "standard"` — uses the standard Elasticsearch analyzer for token splitting. -// * `"boost": 2` — gives the firstName field double weight in search. Documents where the query matches the name will rank higher in results. -// <5> Fully defines the mapping, bypassing any strategy. The field will be indexed as text with the `"english"` analyzer, which specializes in the English language. -// <6> A mandatory parameter when specifying the configuration directly (`withFieldConfiguration`). Indicates which component should extract the value of this property from the `Customer` entity for indexing. Without an extractor, the engine will not know how to retrieve the data. -// <7> Sets the order for this mapping element. This can be important if elements conflict with each other. -// -// NOTE: There can be only one method with programmatic mapping. If a method with programmatic mapping exists, all mapping annotations are ignored. +<3> The list of properties to index. Here the `*` wildcard includes all local properties of the indexed `Customer` entity. +<4> The list of properties to exclude. `firstName` and `lastName` are excluded here because they are configured separately in the following groups for fine-tuning. +<5> The `FieldMappingStrategy` implementation class used to map the properties of this group. The strategy can also be set as an instance using the `withFieldMappingStrategy()` method. +<6> An explicit property value extractor. For example, a `FilePropertyValueExtractor` instance is used for processing attributes of the `FileRef` type. +<7> A second group that fine-tunes a single field with a native field configuration. +<8> First applies the automatic mapping strategy to obtain a base mapping. +<9> Defines a native field configuration as a JSON string that overrides and extends the settings generated by the strategy: +* `"type": "text"` — explicitly specifies the text type. +* `"analyzer": "standard"` — uses the standard analyzer for token splitting. +* `"boost": 2` — gives the `firstName` field double weight in search, so documents matching the name rank higher. +<10> Defines the field configuration directly, bypassing any strategy. The `lastName` field is indexed as text with the `"english"` analyzer. +<11> Required when only a native configuration is specified (no strategy): the extractor that reads the property value for indexing. +<12> Sets the order of this group. It matters when groups would otherwise conflict — the group with the higher order wins. + +The example above defines several static attributes groups, including native field configurations for `firstName` and `lastName`. To also index dynamic attributes programmatically, add a dynamic attributes group using `MappingDefinition.builder().addDynamicAttributesGroup()` with a `DynamicAttributesGroupConfiguration`. See xref:search:dyn-attr-support.adoc#programmatic-index-definition[Programmatic Index Definition] for details. + +NOTE: There can be only one method with programmatic mapping in an index definition interface. If such a method exists, all field-mapping annotations in the interface are ignored. [[FieldMappingStrategy]] === FieldMappingStrategy