Skip to content

Commit 836187c

Browse files
authored
Allow to customize mappings parameters.
Signed-off-by: Andriy Redko <drreta@gmail.com>
1 parent 87427d9 commit 836187c

6 files changed

Lines changed: 222 additions & 4 deletions

File tree

src/main/java/org/springframework/data/elasticsearch/core/index/MappingBuilder.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,15 @@ public class MappingBuilder {
112112

113113
protected final ElasticsearchConverter elasticsearchConverter;
114114
private final ObjectMapper objectMapper = new ObjectMapper();
115+
private final MappingParametersCustomizer customizer;
115116

116117
public MappingBuilder(ElasticsearchConverter elasticsearchConverter) {
118+
this(elasticsearchConverter, MappingParameters::from);
119+
}
120+
121+
public MappingBuilder(ElasticsearchConverter elasticsearchConverter, MappingParametersCustomizer customizer) {
117122
this.elasticsearchConverter = elasticsearchConverter;
123+
this.customizer = customizer;
118124
}
119125

120126
/**
@@ -589,7 +595,7 @@ private void addMultiFieldMapping(ObjectNode propertyNode, ElasticsearchPersiste
589595
private void addFieldMappingParameters(ObjectNode fieldNode, Annotation annotation, boolean nestedOrObjectField)
590596
throws IOException {
591597

592-
MappingParameters mappingParameters = MappingParameters.from(annotation);
598+
MappingParameters mappingParameters = customizer.from(annotation);
593599

594600
if (!nestedOrObjectField && mappingParameters.isStore()) {
595601
fieldNode.put(FIELD_PARAM_STORE, true);

src/main/java/org/springframework/data/elasticsearch/core/index/MappingParameters.java

Lines changed: 134 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,19 @@
3535
* A class to hold the mapping parameters that might be set on
3636
* {@link org.springframework.data.elasticsearch.annotations.Field } or
3737
* {@link org.springframework.data.elasticsearch.annotations.InnerField} annotation.
38+
* The class allows extensibility (non-final) to simplify mapping parameters customization,
39+
* provided by {@link org.springframework.data.elasticsearch.core.index.MappingParametersCustomizer}.
3840
*
3941
* @author Peter-Josef Meisch
4042
* @author Aleksei Arsenev
4143
* @author Brian Kimmig
4244
* @author Morgan Lutz
4345
* @author Sascha Woo
4446
* @author Haibo Liu
47+
* @author Andriy Redko
4548
* @since 4.0
4649
*/
47-
public final class MappingParameters {
50+
public class MappingParameters {
4851

4952
static final String FIELD_PARAM_COERCE = "coerce";
5053
static final String FIELD_PARAM_COPY_TO = "copy_to";
@@ -137,7 +140,7 @@ public static MappingParameters from(Annotation annotation) {
137140
}
138141
}
139142

140-
private MappingParameters(Field field) {
143+
protected MappingParameters(Field field) {
141144
index = field.index();
142145
store = field.store();
143146
fielddata = field.fielddata();
@@ -184,7 +187,7 @@ private MappingParameters(Field field) {
184187
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
185188
}
186189

187-
private MappingParameters(InnerField field) {
190+
protected MappingParameters(InnerField field) {
188191
index = field.index();
189192
store = field.store();
190193
fielddata = field.fielddata();
@@ -417,4 +420,132 @@ public void writeTypeAndParametersTo(ObjectNode objectNode) throws IOException {
417420
objectNode.put(FIELD_PARAM_EAGER_GLOBAL_ORDINALS, eagerGlobalOrdinals);
418421
}
419422
}
423+
424+
protected String analyzer() {
425+
return analyzer;
426+
}
427+
428+
protected boolean coerce() {
429+
return coerce;
430+
}
431+
432+
protected String[] copyTo() {
433+
return copyTo;
434+
}
435+
436+
protected DateFormat[] dateFormats() {
437+
return dateFormats;
438+
}
439+
440+
protected String[] dateFormatPatterns() {
441+
return dateFormatPatterns;
442+
}
443+
444+
protected boolean hasDocValues() {
445+
return docValues;
446+
}
447+
448+
protected boolean hasEagerGlobalOrdinals() {
449+
return eagerGlobalOrdinals;
450+
}
451+
452+
protected boolean isEnabled() {
453+
return enabled;
454+
}
455+
456+
protected boolean hasFielddata() {
457+
return fielddata;
458+
}
459+
460+
protected Integer ignoreAbove() {
461+
return ignoreAbove;
462+
}
463+
464+
protected boolean isIgnoreMalformed() {
465+
return ignoreMalformed;
466+
}
467+
468+
protected boolean isIndex() {
469+
return index;
470+
}
471+
472+
protected IndexOptions indexOptions() {
473+
return indexOptions;
474+
}
475+
476+
protected boolean isIndexPhrases() {
477+
return indexPhrases;
478+
}
479+
480+
protected IndexPrefixes indexPrefixes() {
481+
return indexPrefixes;
482+
}
483+
484+
protected String normalizer() {
485+
return normalizer;
486+
}
487+
488+
protected boolean hasNorms() {
489+
return norms;
490+
}
491+
492+
protected Integer maxShingleSize() {
493+
return maxShingleSize;
494+
}
495+
496+
protected String nullValue() {
497+
return nullValue;
498+
}
499+
500+
protected NullValueType nullValueType() {
501+
return nullValueType;
502+
}
503+
504+
protected Integer positionIncrementGap() {
505+
return positionIncrementGap;
506+
}
507+
508+
protected boolean positiveScoreImpact() {
509+
return positiveScoreImpact;
510+
}
511+
512+
protected Integer dims() {
513+
return dims;
514+
}
515+
516+
protected String elementType() {
517+
return elementType;
518+
}
519+
520+
protected KnnSimilarity knnSimilarity() {
521+
return knnSimilarity;
522+
}
523+
524+
protected KnnIndexOptions knnIndexOptions() {
525+
return knnIndexOptions;
526+
}
527+
528+
protected String searchAnalyzer() {
529+
return searchAnalyzer;
530+
}
531+
532+
protected double scalingFactor() {
533+
return scalingFactor;
534+
}
535+
536+
protected String similarity() {
537+
return similarity;
538+
}
539+
540+
protected TermVector termVector() {
541+
return termVector;
542+
}
543+
544+
protected FieldType type() {
545+
return type;
546+
}
547+
548+
protected String mappedTypeName() {
549+
return mappedTypeName;
550+
}
420551
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2019-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.core.index;
17+
18+
import java.lang.annotation.Annotation;
19+
20+
import org.jspecify.annotations.NonNull;
21+
22+
/**
23+
* Allows to customize {@link org.springframework.data.elasticsearch.core.index.MappingParameters}
24+
* that are being emitted for each supported annotation.
25+
*
26+
* @author Andriy Redko
27+
* @since 6.1.0
28+
*/
29+
public interface MappingParametersCustomizer {
30+
/**
31+
* Customize @link org.springframework.data.elasticsearch.core.index.MappingParameters}
32+
* for each supported annotation.
33+
*
34+
* @param annotation supported annotation
35+
* @return customized @link org.springframework.data.elasticsearch.core.index.MappingParameters}
36+
*/
37+
@NonNull MappingParameters from(@NonNull Annotation annotation);
38+
}

src/main/java/org/springframework/data/elasticsearch/core/index/ReactiveMappingBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,18 @@
3131
* Subclass of {@link MappingBuilder} with specialized methods To inhibit blocking calls
3232
*
3333
* @author Peter-Josef Meisch
34+
* @author Andriy Redko
3435
* @since 4.3
3536
*/
3637
public class ReactiveMappingBuilder extends MappingBuilder {
3738

3839
public ReactiveMappingBuilder(ElasticsearchConverter elasticsearchConverter) {
3940
super(elasticsearchConverter);
4041
}
42+
43+
public ReactiveMappingBuilder(ElasticsearchConverter elasticsearchConverter, MappingParametersCustomizer customizer) {
44+
super(elasticsearchConverter, customizer);
45+
}
4146

4247
@Override
4348
public String buildPropertyMapping(Class<?> clazz) throws MappingException {

src/test/java/org/springframework/data/elasticsearch/core/MappingContextBaseTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
2020
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
2121
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
22+
import org.springframework.data.elasticsearch.core.index.MappingParametersCustomizer;
2223
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
2324
import org.springframework.data.util.Lazy;
2425

2526
/**
2627
* @author Peter-Josef Meisch
28+
* @author Andriy Redko
2729
*/
2830
public abstract class MappingContextBaseTests {
2931

@@ -42,6 +44,10 @@ private SimpleElasticsearchMappingContext setupMappingContext() {
4244
return mappingContext;
4345
}
4446

47+
final protected MappingBuilder getMappingBuilder(MappingParametersCustomizer customizer) {
48+
return new MappingBuilder(elasticsearchConverter.get(), customizer);
49+
}
50+
4551
final protected MappingBuilder getMappingBuilder() {
4652
return new MappingBuilder(elasticsearchConverter.get());
4753
}

src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderUnitTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.skyscreamer.jsonassert.JSONAssert.*;
2121
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
2222

23+
import java.io.IOException;
2324
import java.math.BigDecimal;
2425
import java.time.Instant;
2526
import java.time.LocalDate;
@@ -49,6 +50,8 @@
4950
import org.springframework.data.geo.Polygon;
5051
import org.springframework.data.mapping.MappingException;
5152

53+
import tools.jackson.databind.node.ObjectNode;
54+
5255
/**
5356
* @author Stuart Stevenson
5457
* @author Jakub Vavrik
@@ -1339,6 +1342,35 @@ void shouldMapNullityParameters() throws JSONException {
13391342
assertEquals(expected, result, true);
13401343
}
13411344

1345+
@Test // #1700
1346+
@DisplayName("should allow mapping parameters tion")
1347+
void shouldAllowMappingParametersCustomization() throws JSONException {
1348+
String expected = """
1349+
{
1350+
"properties": {
1351+
"my_vector": {
1352+
"type": "dense_vector",
1353+
"dimensions": 16
1354+
}
1355+
}
1356+
}
1357+
""";
1358+
1359+
final MappingParametersCustomizer customizer = annotation -> new MappingParameters((Field) annotation) {
1360+
@Override
1361+
public void writeTypeAndParametersTo(ObjectNode objectNode) throws IOException {
1362+
if (type() == FieldType.Dense_Vector) {
1363+
objectNode.put(FIELD_PARAM_TYPE, mappedTypeName());
1364+
objectNode.put("dimensions", dims());
1365+
}
1366+
}
1367+
};
1368+
1369+
String mapping = getMappingBuilder(customizer)
1370+
.buildPropertyMapping(DenseVectorEntity.class);
1371+
1372+
assertEquals(expected, mapping, false);
1373+
}
13421374
// region entities
13431375

13441376
@Document(indexName = "ignore-above-index")

0 commit comments

Comments
 (0)