
org.opensearch.index.mapper.ParametrizedFieldMapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opensearch Show documentation
Show all versions of opensearch Show documentation
OpenSearch subproject :server
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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
*
* http://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.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
package org.opensearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.opensearch.Version;
import org.opensearch.common.Explicit;
import org.opensearch.common.TriFunction;
import org.opensearch.common.logging.DeprecationLogger;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.xcontent.XContentBuilder;
import org.opensearch.common.xcontent.support.XContentMapValues;
import org.opensearch.index.analysis.NamedAnalyzer;
import org.opensearch.index.mapper.Mapper.TypeParser.ParserContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Defines how a particular field should be indexed and searched
*
* Configuration {@link Parameter}s for the mapper are defined on a {@link Builder} subclass,
* and returned by its {@link Builder#getParameters()} method. Merging, serialization
* and parsing of the mapper are all mediated through this set of parameters.
*
* Subclasses should implement a {@link Builder} that is returned from the
* {@link #getMergeBuilder()} method, initialised with the existing builder.
*/
public abstract class ParametrizedFieldMapper extends FieldMapper {
private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(ParametrizedFieldMapper.class);
/**
* Creates a new ParametrizedFieldMapper
*/
protected ParametrizedFieldMapper(String simpleName, MappedFieldType mappedFieldType, MultiFields multiFields, CopyTo copyTo) {
super(simpleName, new FieldType(), mappedFieldType, multiFields, copyTo);
}
/**
* Returns a {@link Builder} to be used for merging and serialization
*
* Implement as follows:
* {@code return new MyBuilder(simpleName()).init(this); }
*/
public abstract ParametrizedFieldMapper.Builder getMergeBuilder();
@Override
public final ParametrizedFieldMapper merge(Mapper mergeWith) {
if (mergeWith instanceof FieldMapper == false) {
throw new IllegalArgumentException(
"mapper ["
+ name()
+ "] cannot be changed from type ["
+ contentType()
+ "] to ["
+ mergeWith.getClass().getSimpleName()
+ "]"
);
}
String mergeWithContentType = ((FieldMapper) mergeWith).contentType();
if (Objects.equals(this.getClass(), mergeWith.getClass()) == false) {
throw new IllegalArgumentException(
"mapper [" + name() + "] cannot be changed from type [" + contentType() + "] to [" + mergeWithContentType + "]"
);
}
if (Objects.equals(contentType(), mergeWithContentType) == false) {
throw new IllegalArgumentException(
"mapper [" + name() + "] cannot be changed from type [" + contentType() + "] to [" + mergeWithContentType + "]"
);
}
ParametrizedFieldMapper.Builder builder = getMergeBuilder();
if (builder == null) {
return (ParametrizedFieldMapper) mergeWith;
}
Conflicts conflicts = new Conflicts(name());
builder.merge((FieldMapper) mergeWith, conflicts);
conflicts.check();
return builder.build(new BuilderContext(Settings.EMPTY, parentPath(name())));
}
private static ContentPath parentPath(String name) {
int endPos = name.lastIndexOf(".");
if (endPos == -1) {
return new ContentPath(0);
}
return new ContentPath(name.substring(0, endPos));
}
@Override
protected final void mergeOptions(FieldMapper other, List conflicts) {
// TODO remove when everything is parametrized
}
@Override
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType());
getMergeBuilder().toXContent(builder, includeDefaults);
multiFields.toXContent(builder, params);
copyTo.toXContent(builder, params);
}
/**
* Serializes a parameter
*/
protected interface Serializer {
void serialize(XContentBuilder builder, String name, T value) throws IOException;
}
/**
* Check on whether or not a parameter should be serialized
*/
protected interface SerializerCheck {
/**
* Check on whether or not a parameter should be serialized
* @param includeDefaults if defaults have been requested
* @param isConfigured if the parameter has a different value to the default
* @param value the parameter value
* @return {@code true} if the value should be serialized
*/
boolean check(boolean includeDefaults, boolean isConfigured, T value);
}
/**
* A configurable parameter for a field mapper
* @param the type of the value the parameter holds
*/
public static final class Parameter implements Supplier {
public final String name;
private final List deprecatedNames = new ArrayList<>();
private final Supplier defaultValue;
private final TriFunction parser;
private final Function initializer;
private boolean acceptsNull = false;
private Consumer validator = null;
private Serializer serializer = XContentBuilder::field;
private SerializerCheck serializerCheck = (includeDefaults, isConfigured, value) -> includeDefaults || isConfigured;
private Function conflictSerializer = Objects::toString;
private BiPredicate mergeValidator;
private T value;
private boolean isSet;
/**
* Creates a new Parameter
* @param name the parameter name, used in parsing and serialization
* @param updateable whether the parameter can be updated with a new value during a mapping update
* @param defaultValue the default value for the parameter, used if unspecified in mappings
* @param parser a function that converts an object to a parameter value
* @param initializer a function that reads a parameter value from an existing mapper
*/
public Parameter(
String name,
boolean updateable,
Supplier defaultValue,
TriFunction parser,
Function initializer
) {
this.name = name;
this.defaultValue = Objects.requireNonNull(defaultValue);
this.value = null;
this.parser = parser;
this.initializer = initializer;
this.mergeValidator = (previous, toMerge) -> updateable || Objects.equals(previous, toMerge);
}
/**
* Returns the current value of the parameter
*/
public T getValue() {
return isSet ? value : defaultValue.get();
}
@Override
public T get() {
return getValue();
}
/**
* Returns the default value of the parameter
*/
public T getDefaultValue() {
return defaultValue.get();
}
/**
* Sets the current value of the parameter
*/
public void setValue(T value) {
this.isSet = true;
this.value = value;
}
public boolean isConfigured() {
return isSet && Objects.equals(value, defaultValue.get()) == false;
}
/**
* Allows the parameter to accept a {@code null} value
*/
public Parameter acceptsNull() {
this.acceptsNull = true;
return this;
}
/**
* Adds a deprecated parameter name.
*
* If this parameter name is encountered during parsing, a deprecation warning will
* be emitted. The parameter will be serialized with its main name.
*/
public Parameter addDeprecatedName(String deprecatedName) {
this.deprecatedNames.add(deprecatedName);
return this;
}
/**
* Adds validation to a parameter, called after parsing and merging
*/
public Parameter setValidator(Consumer validator) {
this.validator = validator;
return this;
}
/**
* Configure a custom serializer for this parameter
*/
public Parameter setSerializer(Serializer serializer, Function conflictSerializer) {
this.serializer = serializer;
this.conflictSerializer = conflictSerializer;
return this;
}
/**
* Configure a custom serialization check for this parameter
*/
public Parameter setSerializerCheck(SerializerCheck check) {
this.serializerCheck = check;
return this;
}
/**
* Always serialize this parameter, no matter its value
*/
public Parameter alwaysSerialize() {
this.serializerCheck = (id, ic, v) -> true;
return this;
}
/**
* Never serialize this parameter, no matter its value
*/
public Parameter neverSerialize() {
this.serializerCheck = (id, ic, v) -> false;
return this;
}
/**
* Sets a custom merge validator. By default, merges are accepted if the
* parameter is updateable, or if the previous and new values are equal
*/
public Parameter setMergeValidator(BiPredicate mergeValidator) {
this.mergeValidator = mergeValidator;
return this;
}
private void validate() {
if (validator != null) {
validator.accept(getValue());
}
}
private void init(FieldMapper toInit) {
setValue(initializer.apply(toInit));
}
private void parse(String field, ParserContext context, Object in) {
setValue(parser.apply(field, context, in));
}
private void merge(FieldMapper toMerge, Conflicts conflicts) {
T value = initializer.apply(toMerge);
T current = getValue();
if (mergeValidator.test(current, value)) {
setValue(value);
} else {
conflicts.addConflict(name, conflictSerializer.apply(current), conflictSerializer.apply(value));
}
}
protected void toXContent(XContentBuilder builder, boolean includeDefaults) throws IOException {
if (serializerCheck.check(includeDefaults, isConfigured(), get())) {
serializer.serialize(builder, name, getValue());
}
}
/**
* Defines a parameter that takes the values {@code true} or {@code false}
* @param name the parameter name
* @param updateable whether the parameter can be changed by a mapping update
* @param initializer a function that reads the parameter value from an existing mapper
* @param defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter boolParam(
String name,
boolean updateable,
Function initializer,
boolean defaultValue
) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeBooleanValue(o), initializer);
}
/**
* Defines a parameter that takes the values {@code true} or {@code false}, and will always serialize
* its value if configured.
* @param name the parameter name
* @param updateable whether the parameter can be changed by a mapping update
* @param initializer a function that reads the parameter value from an existing mapper
* @param defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter> explicitBoolParam(
String name,
boolean updateable,
Function> initializer,
boolean defaultValue
) {
Explicit defaultExplicit = new Explicit<>(defaultValue, false);
return new Parameter<>(
name,
updateable,
() -> defaultExplicit,
(n, c, o) -> new Explicit<>(XContentMapValues.nodeBooleanValue(o), true),
initializer
).setSerializer((b, n, v) -> b.field(n, v.value()), v -> Boolean.toString(v.value()));
}
/**
* Defines a parameter that takes a double value
* @param name the parameter name
* @param updateable whether the parameter can be changed by a mapping update
* @param initializer a function that reads the parameter value from an existing mapper
* @param defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter doubleParam(
String name,
boolean updateable,
Function initializer,
double defaultValue
) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeDoubleValue(o), initializer);
}
/**
* Defines a parameter that takes a float value
* @param name the parameter name
* @param updateable whether the parameter can be changed by a mapping update
* @param initializer a function that reads the parameter value from an existing mapper
* @param defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter floatParam(
String name,
boolean updateable,
Function initializer,
float defaultValue
) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeFloatValue(o), initializer);
}
/**
* Defines a parameter that takes an integer value
* @param name the parameter name
* @param updateable whether the parameter can be changed by a mapping update
* @param initializer a function that reads the parameter value from an existing mapper
* @param defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter intParam(
String name,
boolean updateable,
Function initializer,
int defaultValue
) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeIntegerValue(o), initializer);
}
/**
* Defines a parameter that takes a string value
* @param name the parameter name
* @param updateable whether the parameter can be changed by a mapping update
* @param initializer a function that reads the parameter value from an existing mapper
* @param defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter stringParam(
String name,
boolean updateable,
Function initializer,
String defaultValue
) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeStringValue(o), initializer);
}
@SuppressWarnings("unchecked")
public static Parameter> stringArrayParam(
String name,
boolean updateable,
Function> initializer,
List defaultValue
) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy