From a9a59fa97546a13d5e02f26234029a673c966693 Mon Sep 17 00:00:00 2001
From: aleksandrovpv
Date: Thu, 25 Jun 2026 18:52:31 +0400
Subject: [PATCH] Search: document dynamic attributes in index-definitions;
document native field config #829
- index-definitions.adoc: mention @DynamicAttributes alongside @AutoMappedField; add a
"Dynamic Attributes" section and a note on addDynamicAttributesGroup(); document native
field configuration in the programmatic-mapping example (withFieldConfiguration: per-field
analyzer / boost)
- CustomerIndexDefinition.java: fold the native-config example into the single mapping()
method (one @ManualMappingDefinition); remove the stale commented text-config method
Verified by running the search-ex1 UserTest on Java 21.
Co-Authored-By: Claude Opus 4.8 (1M context)
---
.../demo/service/CustomerIndexDefinition.java | 74 ++++++++-----------
.../search/pages/index-definitions.adoc | 48 ++++++------
2 files changed, 53 insertions(+), 69 deletions(-)
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