1
0
mirror of synced 2026-05-22 20:23:18 +00:00

Allow to customize mappings parameters.

Signed-off-by: Andriy Redko <drreta@gmail.com>
This commit is contained in:
Andriy Redko
2026-03-14 08:07:01 -04:00
committed by GitHub
parent 87427d96a2
commit 836187c170
6 changed files with 222 additions and 4 deletions
@@ -112,9 +112,15 @@ public class MappingBuilder {
protected final ElasticsearchConverter elasticsearchConverter;
private final ObjectMapper objectMapper = new ObjectMapper();
private final MappingParametersCustomizer customizer;
public MappingBuilder(ElasticsearchConverter elasticsearchConverter) {
this(elasticsearchConverter, MappingParameters::from);
}
public MappingBuilder(ElasticsearchConverter elasticsearchConverter, MappingParametersCustomizer customizer) {
this.elasticsearchConverter = elasticsearchConverter;
this.customizer = customizer;
}
/**
@@ -589,7 +595,7 @@ public class MappingBuilder {
private void addFieldMappingParameters(ObjectNode fieldNode, Annotation annotation, boolean nestedOrObjectField)
throws IOException {
MappingParameters mappingParameters = MappingParameters.from(annotation);
MappingParameters mappingParameters = customizer.from(annotation);
if (!nestedOrObjectField && mappingParameters.isStore()) {
fieldNode.put(FIELD_PARAM_STORE, true);
@@ -35,6 +35,8 @@ import org.springframework.util.StringUtils;
* A class to hold the mapping parameters that might be set on
* {@link org.springframework.data.elasticsearch.annotations.Field } or
* {@link org.springframework.data.elasticsearch.annotations.InnerField} annotation.
* The class allows extensibility (non-final) to simplify mapping parameters customization,
* provided by {@link org.springframework.data.elasticsearch.core.index.MappingParametersCustomizer}.
*
* @author Peter-Josef Meisch
* @author Aleksei Arsenev
@@ -42,9 +44,10 @@ import org.springframework.util.StringUtils;
* @author Morgan Lutz
* @author Sascha Woo
* @author Haibo Liu
* @author Andriy Redko
* @since 4.0
*/
public final class MappingParameters {
public class MappingParameters {
static final String FIELD_PARAM_COERCE = "coerce";
static final String FIELD_PARAM_COPY_TO = "copy_to";
@@ -137,7 +140,7 @@ public final class MappingParameters {
}
}
private MappingParameters(Field field) {
protected MappingParameters(Field field) {
index = field.index();
store = field.store();
fielddata = field.fielddata();
@@ -184,7 +187,7 @@ public final class MappingParameters {
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
}
private MappingParameters(InnerField field) {
protected MappingParameters(InnerField field) {
index = field.index();
store = field.store();
fielddata = field.fielddata();
@@ -417,4 +420,132 @@ public final class MappingParameters {
objectNode.put(FIELD_PARAM_EAGER_GLOBAL_ORDINALS, eagerGlobalOrdinals);
}
}
protected String analyzer() {
return analyzer;
}
protected boolean coerce() {
return coerce;
}
protected String[] copyTo() {
return copyTo;
}
protected DateFormat[] dateFormats() {
return dateFormats;
}
protected String[] dateFormatPatterns() {
return dateFormatPatterns;
}
protected boolean hasDocValues() {
return docValues;
}
protected boolean hasEagerGlobalOrdinals() {
return eagerGlobalOrdinals;
}
protected boolean isEnabled() {
return enabled;
}
protected boolean hasFielddata() {
return fielddata;
}
protected Integer ignoreAbove() {
return ignoreAbove;
}
protected boolean isIgnoreMalformed() {
return ignoreMalformed;
}
protected boolean isIndex() {
return index;
}
protected IndexOptions indexOptions() {
return indexOptions;
}
protected boolean isIndexPhrases() {
return indexPhrases;
}
protected IndexPrefixes indexPrefixes() {
return indexPrefixes;
}
protected String normalizer() {
return normalizer;
}
protected boolean hasNorms() {
return norms;
}
protected Integer maxShingleSize() {
return maxShingleSize;
}
protected String nullValue() {
return nullValue;
}
protected NullValueType nullValueType() {
return nullValueType;
}
protected Integer positionIncrementGap() {
return positionIncrementGap;
}
protected boolean positiveScoreImpact() {
return positiveScoreImpact;
}
protected Integer dims() {
return dims;
}
protected String elementType() {
return elementType;
}
protected KnnSimilarity knnSimilarity() {
return knnSimilarity;
}
protected KnnIndexOptions knnIndexOptions() {
return knnIndexOptions;
}
protected String searchAnalyzer() {
return searchAnalyzer;
}
protected double scalingFactor() {
return scalingFactor;
}
protected String similarity() {
return similarity;
}
protected TermVector termVector() {
return termVector;
}
protected FieldType type() {
return type;
}
protected String mappedTypeName() {
return mappedTypeName;
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2019-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import java.lang.annotation.Annotation;
import org.jspecify.annotations.NonNull;
/**
* Allows to customize {@link org.springframework.data.elasticsearch.core.index.MappingParameters}
* that are being emitted for each supported annotation.
*
* @author Andriy Redko
* @since 6.1.0
*/
public interface MappingParametersCustomizer {
/**
* Customize @link org.springframework.data.elasticsearch.core.index.MappingParameters}
* for each supported annotation.
*
* @param annotation supported annotation
* @return customized @link org.springframework.data.elasticsearch.core.index.MappingParameters}
*/
@NonNull MappingParameters from(@NonNull Annotation annotation);
}
@@ -31,6 +31,7 @@ import org.springframework.data.mapping.MappingException;
* Subclass of {@link MappingBuilder} with specialized methods To inhibit blocking calls
*
* @author Peter-Josef Meisch
* @author Andriy Redko
* @since 4.3
*/
public class ReactiveMappingBuilder extends MappingBuilder {
@@ -38,6 +39,10 @@ public class ReactiveMappingBuilder extends MappingBuilder {
public ReactiveMappingBuilder(ElasticsearchConverter elasticsearchConverter) {
super(elasticsearchConverter);
}
public ReactiveMappingBuilder(ElasticsearchConverter elasticsearchConverter, MappingParametersCustomizer customizer) {
super(elasticsearchConverter, customizer);
}
@Override
public String buildPropertyMapping(Class<?> clazz) throws MappingException {
@@ -19,11 +19,13 @@ import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationS
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
import org.springframework.data.elasticsearch.core.index.MappingParametersCustomizer;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.util.Lazy;
/**
* @author Peter-Josef Meisch
* @author Andriy Redko
*/
public abstract class MappingContextBaseTests {
@@ -42,6 +44,10 @@ public abstract class MappingContextBaseTests {
return mappingContext;
}
final protected MappingBuilder getMappingBuilder(MappingParametersCustomizer customizer) {
return new MappingBuilder(elasticsearchConverter.get(), customizer);
}
final protected MappingBuilder getMappingBuilder() {
return new MappingBuilder(elasticsearchConverter.get());
}
@@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.*;
import static org.skyscreamer.jsonassert.JSONAssert.*;
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
@@ -49,6 +50,8 @@ import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.data.mapping.MappingException;
import tools.jackson.databind.node.ObjectNode;
/**
* @author Stuart Stevenson
* @author Jakub Vavrik
@@ -1339,6 +1342,35 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
assertEquals(expected, result, true);
}
@Test // #1700
@DisplayName("should allow mapping parameters tion")
void shouldAllowMappingParametersCustomization() throws JSONException {
String expected = """
{
"properties": {
"my_vector": {
"type": "dense_vector",
"dimensions": 16
}
}
}
""";
final MappingParametersCustomizer customizer = annotation -> new MappingParameters((Field) annotation) {
@Override
public void writeTypeAndParametersTo(ObjectNode objectNode) throws IOException {
if (type() == FieldType.Dense_Vector) {
objectNode.put(FIELD_PARAM_TYPE, mappedTypeName());
objectNode.put("dimensions", dims());
}
}
};
String mapping = getMappingBuilder(customizer)
.buildPropertyMapping(DenseVectorEntity.class);
assertEquals(expected, mapping, false);
}
// region entities
@Document(indexName = "ignore-above-index")