Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,21 @@
* @since 4.1
*/
boolean positiveScoreImpact() default true;

/**
* to be used in combination with {@link FieldType#Object}
*
* @since 4.1
*/
boolean enabled() default true;

/**
* @since 4.1
*/
boolean eagerGlobalOrdinals() default false;

/**
* @since 4.1
*/
NullValueType nullValueType() default NullValueType.String;
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,14 @@
* @since 4.1
*/
boolean positiveScoreImpact() default true;

/**
* @since 4.1
*/
boolean eagerGlobalOrdinals() default false;

/**
* @since 4.1
*/
NullValueType nullValueType() default NullValueType.String;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2020 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.annotations;

/**
* @author Peter-Josef Meisch
* @since 4.1
*/
public enum NullValueType {
String, Integer, Long, Double
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.springframework.data.elasticsearch.annotations.IndexOptions;
import org.springframework.data.elasticsearch.annotations.IndexPrefixes;
import org.springframework.data.elasticsearch.annotations.InnerField;
import org.springframework.data.elasticsearch.annotations.NullValueType;
import org.springframework.data.elasticsearch.annotations.Similarity;
import org.springframework.data.elasticsearch.annotations.TermVector;
import org.springframework.util.Assert;
Expand All @@ -44,8 +45,10 @@ public final class MappingParameters {

static final String FIELD_PARAM_COERCE = "coerce";
static final String FIELD_PARAM_COPY_TO = "copy_to";
static final String FIELD_PARAM_DOC_VALUES = "doc_values";
static final String FIELD_PARAM_DATA = "fielddata";
static final String FIELD_PARAM_DOC_VALUES = "doc_values";
static final String FIELD_PARAM_EAGER_GLOBAL_ORDINALS = "eager_global_ordinals";
static final String FIELD_PARAM_ENABLED = "enabled";
static final String FIELD_PARAM_FORMAT = "format";
static final String FIELD_PARAM_IGNORE_ABOVE = "ignore_above";
static final String FIELD_PARAM_IGNORE_MALFORMED = "ignore_malformed";
Expand All @@ -56,44 +59,47 @@ public final class MappingParameters {
static final String FIELD_PARAM_INDEX_PREFIXES_MIN_CHARS = "min_chars";
static final String FIELD_PARAM_INDEX_PREFIXES_MAX_CHARS = "max_chars";
static final String FIELD_PARAM_INDEX_ANALYZER = "analyzer";
static final String FIELD_PARAM_MAX_SHINGLE_SIZE = "max_shingle_size";
static final String FIELD_PARAM_NORMALIZER = "normalizer";
static final String FIELD_PARAM_NORMS = "norms";
static final String FIELD_PARAM_NULL_VALUE = "null_value";
static final String FIELD_PARAMETER_NAME_POSITION_INCREMENT_GAP = "position_increment_gap";
static final String FIELD_PARAM_POSITION_INCREMENT_GAP = "position_increment_gap";
static final String FIELD_PARAM_POSITIVE_SCORE_IMPACT = "positive_score_impact";
static final String FIELD_PARAM_SCALING_FACTOR = "scaling_factor";
static final String FIELD_PARAM_SEARCH_ANALYZER = "search_analyzer";
static final String FIELD_PARAM_STORE = "store";
static final String FIELD_PARAM_SIMILARITY = "similarity";
static final String FIELD_PARAM_TERM_VECTOR = "term_vector";
static final String FIELD_PARAM_TYPE = "type";
static final String FIELD_PARAM_MAX_SHINGLE_SIZE = "max_shingle_size";
static final String FIELD_PARAM_POSITIVE_SCORE_IMPACT = "positive_score_impact";

private boolean index = true;
private boolean store = false;
private boolean fielddata = false;
private FieldType type = null;
private DateFormat dateFormat = null;
private String datePattern = null;
private String analyzer = null;
private String searchAnalyzer = null;
private String normalizer = null;
private String[] copyTo = null;
private Integer ignoreAbove = null;
private boolean coerce = true;
private boolean docValues = true;
private boolean ignoreMalformed = false;
private IndexOptions indexOptions = null;
boolean indexPhrases = false;
private IndexPrefixes indexPrefixes = null;
private boolean norms = true;
private String nullValue = null;
private Integer positionIncrementGap = null;
private Similarity similarity = Similarity.Default;
private TermVector termVector = TermVector.none;
private double scalingFactor = 1.0;
@Nullable private Integer maxShingleSize;
private boolean positiveScoreImpact = true;
private final String analyzer;
private final boolean coerce;
@Nullable private final String[] copyTo;
private final String datePattern;
private final boolean docValues;
private final boolean eagerGlobalOrdinals;
private final boolean enabled;
private final boolean fielddata;
private final DateFormat format;
@Nullable private final Integer ignoreAbove;
private final boolean ignoreMalformed;
private final boolean index;
private final IndexOptions indexOptions;
private final boolean indexPhrases;
@Nullable private final IndexPrefixes indexPrefixes;
private final String normalizer;
private final boolean norms;
@Nullable private final Integer maxShingleSize;
private final String nullValue;
private final NullValueType nullValueType;
private final Integer positionIncrementGap;
private final boolean positiveScoreImpact;
private final String searchAnalyzer;
private final double scalingFactor;
private final Similarity similarity;
private final boolean store;
private final TermVector termVector;
private final FieldType type;

/**
* extracts the mapping parameters from the relevant annotations.
Expand All @@ -119,7 +125,7 @@ private MappingParameters(Field field) {
store = field.store();
fielddata = field.fielddata();
type = field.type();
dateFormat = field.format();
format = field.format();
datePattern = field.pattern();
analyzer = field.analyzer();
searchAnalyzer = field.searchAnalyzer();
Expand All @@ -133,11 +139,10 @@ private MappingParameters(Field field) {
ignoreMalformed = field.ignoreMalformed();
indexOptions = field.indexOptions();
indexPhrases = field.indexPhrases();
if (field.indexPrefixes().length > 0) {
indexPrefixes = field.indexPrefixes()[0];
}
indexPrefixes = field.indexPrefixes().length > 0 ? field.indexPrefixes()[0] : null;
norms = field.norms();
nullValue = field.nullValue();
nullValueType = field.nullValueType();
positionIncrementGap = field.positionIncrementGap();
similarity = field.similarity();
termVector = field.termVector();
Expand All @@ -148,18 +153,22 @@ private MappingParameters(Field field) {
|| (maxShingleSize >= 2 && maxShingleSize <= 4), //
"maxShingleSize must be in inclusive range from 2 to 4 for field type search_as_you_type");
positiveScoreImpact = field.positiveScoreImpact();
Assert.isTrue(field.enabled() || type == FieldType.Object, "enabled false is only allowed for field type object");
enabled = field.enabled();
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
}

private MappingParameters(InnerField field) {
index = field.index();
store = field.store();
fielddata = field.fielddata();
type = field.type();
dateFormat = field.format();
format = field.format();
datePattern = field.pattern();
analyzer = field.analyzer();
searchAnalyzer = field.searchAnalyzer();
normalizer = field.normalizer();
copyTo = null;
ignoreAbove = field.ignoreAbove() >= 0 ? field.ignoreAbove() : null;
coerce = field.coerce();
docValues = field.docValues();
Expand All @@ -168,11 +177,10 @@ private MappingParameters(InnerField field) {
ignoreMalformed = field.ignoreMalformed();
indexOptions = field.indexOptions();
indexPhrases = field.indexPhrases();
if (field.indexPrefixes().length > 0) {
indexPrefixes = field.indexPrefixes()[0];
}
indexPrefixes = field.indexPrefixes().length > 0 ? field.indexPrefixes()[0] : null;
norms = field.norms();
nullValue = field.nullValue();
nullValueType = field.nullValueType();
positionIncrementGap = field.positionIncrementGap();
similarity = field.similarity();
termVector = field.termVector();
Expand All @@ -183,6 +191,8 @@ private MappingParameters(InnerField field) {
|| (maxShingleSize >= 2 && maxShingleSize <= 4), //
"maxShingleSize must be in inclusive range from 2 to 4 for field type search_as_you_type");
positiveScoreImpact = field.positiveScoreImpact();
enabled = true;
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
}

public boolean isStore() {
Expand All @@ -204,8 +214,8 @@ public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException

if (type != FieldType.Auto) {
builder.field(FIELD_PARAM_TYPE, type.name().toLowerCase());
if (type == FieldType.Date && dateFormat != DateFormat.none) {
builder.field(FIELD_PARAM_FORMAT, dateFormat == DateFormat.custom ? datePattern : dateFormat.toString());
if (type == FieldType.Date && format != DateFormat.none) {
builder.field(FIELD_PARAM_FORMAT, format == DateFormat.custom ? datePattern : format.toString());
}
}

Expand Down Expand Up @@ -270,11 +280,27 @@ public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException
}

if (!StringUtils.isEmpty(nullValue)) {
builder.field(FIELD_PARAM_NULL_VALUE, nullValue);
Object value;
switch (nullValueType) {
case Integer:
value = Integer.valueOf(nullValue);
break;
case Long:
value = Long.valueOf(nullValue);
break;
case Double:
value = Double.valueOf(nullValue);
break;
case String:
default:
value = nullValue;
break;
}
builder.field(FIELD_PARAM_NULL_VALUE, value);
}

if (positionIncrementGap != null && positionIncrementGap >= 0) {
builder.field(FIELD_PARAMETER_NAME_POSITION_INCREMENT_GAP, positionIncrementGap);
builder.field(FIELD_PARAM_POSITION_INCREMENT_GAP, positionIncrementGap);
}

if (similarity != Similarity.Default) {
Expand All @@ -296,5 +322,13 @@ public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException
if (!positiveScoreImpact) {
builder.field(FIELD_PARAM_POSITIVE_SCORE_IMPACT, positiveScoreImpact);
}

if (!enabled) {
builder.field(FIELD_PARAM_ENABLED, enabled);
}

if (eagerGlobalOrdinals) {
builder.field(FIELD_PARAM_EAGER_GLOBAL_ORDINALS, eagerGlobalOrdinals);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ public void shouldUseIgnoreAbove() throws JSONException {
assertEquals(expected, mapping, false);
}

@Test
@Test // DATAES-621, DATAES-943
public void shouldSetFieldMappingProperties() throws JSONException {
String expected = "{\n" + //
" \"properties\": {\n" + //
Expand Down Expand Up @@ -364,9 +364,15 @@ public void shouldSetFieldMappingProperties() throws JSONException {
" \"normsFalse\": {\n" + //
" \"norms\": false\n" + //
" },\n" + //
" \"nullValueSet\": {\n" + //
" \"nullValueString\": {\n" + //
" \"null_value\": \"NULLNULL\"\n" + //
" },\n" + //
" \"nullValueInteger\": {\n" + //
" \"null_value\": 42\n" + //
" },\n" + //
" \"nullValueDouble\": {\n" + //
" \"null_value\": 42.0\n" + //
" },\n" + //
" \"positionIncrementGap\": {\n" + //
" \"position_increment_gap\": 42\n" + //
" },\n" + //
Expand All @@ -379,6 +385,20 @@ public void shouldSetFieldMappingProperties() throws JSONException {
" \"scaledFloat\": {\n" + //
" \"type\": \"scaled_float\",\n" + //
" \"scaling_factor\": 100.0\n" + //
" },\n" + //
" \"enabledObject\": {\n" + //
" \"type\": \"object\"\n" + //
" },\n" + //
" \"disabledObject\": {\n" + //
" \"type\": \"object\",\n" + //
" \"enabled\": false\n" + //
" },\n" + //
" \"eagerGlobalOrdinalsTrue\": {\n" + //
" \"type\": \"text\",\n" + //
" \"eager_global_ordinals\": true\n" + //
" },\n" + //
" \"eagerGlobalOrdinalsFalse\": {\n" + //
" \"type\": \"text\"\n" + //
" }\n" + //
" }\n" + //
"}\n"; //
Expand Down Expand Up @@ -857,14 +877,20 @@ static class FieldMappingParameters {
@Nullable @Field private String normsTrue;
@Nullable @Field(norms = false) private String normsFalse;
@Nullable @Field private String nullValueNotSet;
@Nullable @Field(nullValue = "NULLNULL") private String nullValueSet;
@Nullable @Field(nullValue = "NULLNULL") private String nullValueString;
@Nullable @Field(nullValue = "42", nullValueType = NullValueType.Integer) private String nullValueInteger;
@Nullable @Field(nullValue = "42.0", nullValueType = NullValueType.Double) private String nullValueDouble;
@Nullable @Field(positionIncrementGap = 42) private String positionIncrementGap;
@Nullable @Field private String similarityDefault;
@Nullable @Field(similarity = Similarity.Boolean) private String similarityBoolean;
@Nullable @Field private String termVectorDefault;
@Nullable @Field(termVector = TermVector.with_offsets) private String termVectorWithOffsets;
@Nullable @Field(type = FieldType.Scaled_Float, scalingFactor = 100.0) Double scaledFloat;
@Nullable @Field(type = Auto) String autoField;
@Nullable @Field(type = Object, enabled = true) private String enabledObject;
@Nullable @Field(type = Object, enabled = false) private String disabledObject;
@Nullable @Field(type = Text, eagerGlobalOrdinals = true) private String eagerGlobalOrdinalsTrue;
@Nullable @Field(type = Text, eagerGlobalOrdinals = false) private String eagerGlobalOrdinalsFalse;
}

@Document(indexName = "test-index-configure-dynamic-mapping")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.springframework.data.elasticsearch.core.index;

import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.annotations.FieldType.Object;

import java.lang.annotation.Annotation;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
Expand Down Expand Up @@ -61,12 +63,28 @@ public void shouldNotAllowDocValuesFalseOnFieldTypeNested() {
assertThatThrownBy(() -> MappingParameters.from(annotation)).isInstanceOf(IllegalArgumentException.class);
}

@Test // DATAES-943
@DisplayName("should allow enabled false only on object fields")
void shouldAllowEnabledFalseOnlyOnObjectFields() {
ElasticsearchPersistentEntity<?> failEntity = elasticsearchConverter.get().getMappingContext()
.getRequiredPersistentEntity(InvalidEnabledFieldClass.class);
Annotation annotation = failEntity.getRequiredPersistentProperty("disabledObject").findAnnotation(Field.class);

assertThatThrownBy(() -> MappingParameters.from(annotation)).isInstanceOf(IllegalArgumentException.class);
}

static class AnnotatedClass {
@Nullable @Field private String field;
@Nullable @MultiField(mainField = @Field,
otherFields = { @InnerField(suffix = "test", type = FieldType.Text) }) private String mainField;
@Score private float score;
@Nullable @Field(type = FieldType.Text, docValues = false) private String docValuesText;
@Nullable @Field(type = FieldType.Nested, docValues = false) private String docValuesNested;
@Nullable @Field(type = Object, enabled = true) private String enabledObject;
@Nullable @Field(type = Object, enabled = false) private String disabledObject;
}

static class InvalidEnabledFieldClass {
@Nullable @Field(type = FieldType.Text, enabled = false) private String disabledObject;
}
}