mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 09:28:55 -04:00
IngestDocument readability improvements (#124322)
This commit is contained in:
parent
0e87e8454d
commit
f15cc9667b
4 changed files with 152 additions and 153 deletions
|
@ -14,15 +14,15 @@ import java.util.Locale;
|
|||
import java.util.MissingResourceException;
|
||||
|
||||
/**
|
||||
* Utilities for for dealing with {@link Locale} objects
|
||||
* Utilities for dealing with {@link Locale} objects
|
||||
*/
|
||||
public class LocaleUtils {
|
||||
|
||||
/**
|
||||
* Parse the given locale as {@code language}, {@code language-country} or
|
||||
* {@code language-country-variant}.
|
||||
* Either underscores or hyphens may be used as separators, but consistently, ie.
|
||||
* you may not use an hyphen to separate the language from the country and an
|
||||
* Either underscores or hyphens may be used as separators, but consistently, i.e.
|
||||
* you may not use a hyphen to separate the language from the country and an
|
||||
* underscore to separate the country from the variant.
|
||||
* @throws IllegalArgumentException if there are too many parts in the locale string
|
||||
* @throws IllegalArgumentException if the language or country is not recognized
|
||||
|
|
|
@ -543,18 +543,38 @@ public final class ConfigurationUtils {
|
|||
Script script = new Script(ScriptType.INLINE, DEFAULT_TEMPLATE_LANG, propertyValue, Map.of());
|
||||
return scriptService.compile(script, TemplateScript.CONTEXT);
|
||||
} else {
|
||||
return (params) -> new TemplateScript(params) {
|
||||
@Override
|
||||
public String execute() {
|
||||
return propertyValue;
|
||||
}
|
||||
};
|
||||
return new ConstantTemplateScriptFactory(propertyValue);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw ConfigurationUtils.newConfigurationException(processorType, processorTag, propertyName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A 'template script' that ignores the model to which it is applied and just always returns a constant String.
|
||||
* <p>
|
||||
* Having a separate named class for this allows for some hot code paths to pre-apply the 'template script' statically,
|
||||
* rather than bothering to invoke it per-document. Note that this is probably only useful if something expensive
|
||||
* is being done with the result of calling the script, and the code can then avoid doing that thing per-document.
|
||||
*/
|
||||
public static class ConstantTemplateScriptFactory implements TemplateScript.Factory {
|
||||
final TemplateScript script;
|
||||
|
||||
private ConstantTemplateScriptFactory(String value) {
|
||||
this.script = new TemplateScript(Map.of()) {
|
||||
@Override
|
||||
public String execute() {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateScript newInstance(Map<String, Object> params) {
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addMetadataToException(
|
||||
ElasticsearchException exception,
|
||||
String processorType,
|
||||
|
|
|
@ -83,7 +83,7 @@ public final class IngestDocument {
|
|||
* of the pipeline was that the _index value did not change and so only 'foo' would appear
|
||||
* in the index history.
|
||||
*/
|
||||
private Set<String> indexHistory = new LinkedHashSet<>();
|
||||
private final Set<String> indexHistory = new LinkedHashSet<>();
|
||||
|
||||
private boolean doNoSelfReferencesCheck = false;
|
||||
private boolean reroute = false;
|
||||
|
@ -238,9 +238,7 @@ public final class IngestDocument {
|
|||
} else if (object instanceof String string) {
|
||||
return Base64.getDecoder().decode(string);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Content field [" + path + "] of unknown type [" + object.getClass().getName() + "], must be string or byte array"
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.notStringOrByteArray(path, object));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,51 +266,42 @@ public final class IngestDocument {
|
|||
String pathElement = fieldPath.pathElements[i];
|
||||
if (context == null) {
|
||||
return false;
|
||||
}
|
||||
if (context instanceof Map<?, ?> map) {
|
||||
} else if (context instanceof Map<?, ?> map) {
|
||||
context = map.get(pathElement);
|
||||
} else if (context instanceof List<?> list) {
|
||||
int index;
|
||||
try {
|
||||
int index = Integer.parseInt(pathElement);
|
||||
if (index < 0 || index >= list.size()) {
|
||||
if (failOutOfRange) {
|
||||
throw new IllegalArgumentException(
|
||||
"["
|
||||
+ index
|
||||
+ "] is out of bounds for array with length ["
|
||||
+ list.size()
|
||||
+ "] as part of path ["
|
||||
+ path
|
||||
+ "]"
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
context = list.get(index);
|
||||
index = Integer.parseInt(pathElement);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= list.size()) {
|
||||
if (failOutOfRange) {
|
||||
throw new IllegalArgumentException(Errors.outOfBounds(path, index, list.size()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
context = list.get(index);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String leafKey = fieldPath.pathElements[fieldPath.pathElements.length - 1];
|
||||
if (context instanceof Map<?, ?> map) {
|
||||
if (context == null) {
|
||||
return false;
|
||||
} else if (context instanceof Map<?, ?> map) {
|
||||
return map.containsKey(leafKey);
|
||||
}
|
||||
if (context instanceof List<?> list) {
|
||||
} else if (context instanceof List<?> list) {
|
||||
try {
|
||||
int index = Integer.parseInt(leafKey);
|
||||
if (index >= 0 && index < list.size()) {
|
||||
return true;
|
||||
} else {
|
||||
if (failOutOfRange) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + index + "] is out of bounds for array with length [" + list.size() + "] as part of path [" + path + "]"
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.outOfBounds(path, index, list.size()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -320,9 +309,10 @@ public final class IngestDocument {
|
|||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the field identified by the provided path.
|
||||
|
@ -342,79 +332,58 @@ public final class IngestDocument {
|
|||
}
|
||||
|
||||
String leafKey = fieldPath.pathElements[fieldPath.pathElements.length - 1];
|
||||
if (context instanceof Map<?, ?> map) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException(Errors.cannotRemove(path, leafKey, null));
|
||||
} else if (context instanceof Map<?, ?> map) {
|
||||
if (map.containsKey(leafKey)) {
|
||||
map.remove(leafKey);
|
||||
return;
|
||||
} else {
|
||||
throw new IllegalArgumentException(Errors.notPresent(path, leafKey));
|
||||
}
|
||||
throw new IllegalArgumentException("field [" + leafKey + "] not present as part of path [" + path + "]");
|
||||
}
|
||||
if (context instanceof List<?> list) {
|
||||
} else if (context instanceof List<?> list) {
|
||||
int index;
|
||||
try {
|
||||
index = Integer.parseInt(leafKey);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + leafKey + "] is not an integer, cannot be used as an index as part of path [" + path + "]",
|
||||
e
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.notInteger(path, leafKey), e);
|
||||
}
|
||||
if (index < 0 || index >= list.size()) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + index + "] is out of bounds for array with length [" + list.size() + "] as part of path [" + path + "]"
|
||||
);
|
||||
}
|
||||
throw new IllegalArgumentException(Errors.outOfBounds(path, index, list.size()));
|
||||
} else {
|
||||
list.remove(index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("cannot remove [" + leafKey + "] from null as part of path [" + path + "]");
|
||||
} else {
|
||||
throw new IllegalArgumentException(Errors.cannotRemove(path, leafKey, context));
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"cannot remove [" + leafKey + "] from object of type [" + context.getClass().getName() + "] as part of path [" + path + "]"
|
||||
);
|
||||
}
|
||||
|
||||
private static ResolveResult resolve(String pathElement, String fullPath, Object context) {
|
||||
if (context == null) {
|
||||
return ResolveResult.error("cannot resolve [" + pathElement + "] from null as part of path [" + fullPath + "]");
|
||||
}
|
||||
if (context instanceof Map<?, ?>) {
|
||||
return ResolveResult.error(Errors.cannotResolve(fullPath, pathElement, null));
|
||||
} else if (context instanceof Map<?, ?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) context;
|
||||
Object object = map.getOrDefault(pathElement, NOT_FOUND); // getOrDefault is faster than containsKey + get
|
||||
if (object == NOT_FOUND) {
|
||||
return ResolveResult.error("field [" + pathElement + "] not present as part of path [" + fullPath + "]");
|
||||
return ResolveResult.error(Errors.notPresent(fullPath, pathElement));
|
||||
} else {
|
||||
return ResolveResult.success(object);
|
||||
}
|
||||
}
|
||||
if (context instanceof List<?> list) {
|
||||
} else if (context instanceof List<?> list) {
|
||||
int index;
|
||||
try {
|
||||
index = Integer.parseInt(pathElement);
|
||||
} catch (NumberFormatException e) {
|
||||
return ResolveResult.error(
|
||||
"[" + pathElement + "] is not an integer, cannot be used as an index as part of path [" + fullPath + "]"
|
||||
);
|
||||
return ResolveResult.error(Errors.notInteger(fullPath, pathElement));
|
||||
}
|
||||
if (index < 0 || index >= list.size()) {
|
||||
return ResolveResult.error(
|
||||
"[" + index + "] is out of bounds for array with length [" + list.size() + "] as part of path [" + fullPath + "]"
|
||||
);
|
||||
}
|
||||
return ResolveResult.error(Errors.outOfBounds(fullPath, index, list.size()));
|
||||
} else {
|
||||
return ResolveResult.success(list.get(index));
|
||||
}
|
||||
return ResolveResult.error(
|
||||
"cannot resolve ["
|
||||
+ pathElement
|
||||
+ "] from object of type ["
|
||||
+ context.getClass().getName()
|
||||
+ "] as part of path ["
|
||||
+ fullPath
|
||||
+ "]"
|
||||
);
|
||||
} else {
|
||||
return ResolveResult.error(Errors.cannotResolve(fullPath, pathElement, context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -515,7 +484,6 @@ public final class IngestDocument {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setFieldValue(path, value);
|
||||
}
|
||||
|
||||
|
@ -540,7 +508,6 @@ public final class IngestDocument {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
setFieldValue(path, value);
|
||||
}
|
||||
|
||||
|
@ -550,9 +517,8 @@ public final class IngestDocument {
|
|||
for (int i = 0; i < fieldPath.pathElements.length - 1; i++) {
|
||||
String pathElement = fieldPath.pathElements[i];
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("cannot resolve [" + pathElement + "] from null as part of path [" + path + "]");
|
||||
}
|
||||
if (context instanceof Map) {
|
||||
throw new IllegalArgumentException(Errors.cannotResolve(path, pathElement, null));
|
||||
} else if (context instanceof Map<?, ?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) context;
|
||||
Object object = map.getOrDefault(pathElement, NOT_FOUND); // getOrDefault is faster than containsKey + get
|
||||
|
@ -568,35 +534,22 @@ public final class IngestDocument {
|
|||
try {
|
||||
index = Integer.parseInt(pathElement);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + pathElement + "] is not an integer, cannot be used as an index as part of path [" + path + "]",
|
||||
e
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.notInteger(path, pathElement), e);
|
||||
}
|
||||
if (index < 0 || index >= list.size()) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + index + "] is out of bounds for array with length [" + list.size() + "] as part of path [" + path + "]"
|
||||
);
|
||||
}
|
||||
context = list.get(index);
|
||||
throw new IllegalArgumentException(Errors.outOfBounds(path, index, list.size()));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"cannot resolve ["
|
||||
+ pathElement
|
||||
+ "] from object of type ["
|
||||
+ context.getClass().getName()
|
||||
+ "] as part of path ["
|
||||
+ path
|
||||
+ "]"
|
||||
);
|
||||
context = list.get(index);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(Errors.cannotResolve(path, pathElement, context));
|
||||
}
|
||||
}
|
||||
|
||||
String leafKey = fieldPath.pathElements[fieldPath.pathElements.length - 1];
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("cannot set [" + leafKey + "] with null parent as part of path [" + path + "]");
|
||||
}
|
||||
if (context instanceof Map) {
|
||||
throw new IllegalArgumentException(Errors.cannotSet(path, leafKey, null));
|
||||
} else if (context instanceof Map<?, ?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) context;
|
||||
if (append) {
|
||||
|
@ -614,23 +567,18 @@ public final class IngestDocument {
|
|||
return;
|
||||
}
|
||||
map.put(leafKey, value);
|
||||
} else if (context instanceof List) {
|
||||
} else if (context instanceof List<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> list = (List<Object>) context;
|
||||
int index;
|
||||
try {
|
||||
index = Integer.parseInt(leafKey);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + leafKey + "] is not an integer, cannot be used as an index as part of path [" + path + "]",
|
||||
e
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.notInteger(path, leafKey), e);
|
||||
}
|
||||
if (index < 0 || index >= list.size()) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + index + "] is out of bounds for array with length [" + list.size() + "] as part of path [" + path + "]"
|
||||
);
|
||||
}
|
||||
throw new IllegalArgumentException(Errors.outOfBounds(path, index, list.size()));
|
||||
} else {
|
||||
if (append) {
|
||||
Object object = list.get(index);
|
||||
Object newList = appendValues(object, value, allowDuplicates);
|
||||
|
@ -640,16 +588,9 @@ public final class IngestDocument {
|
|||
return;
|
||||
}
|
||||
list.set(index, value);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"cannot set ["
|
||||
+ leafKey
|
||||
+ "] with parent object of type ["
|
||||
+ context.getClass().getName()
|
||||
+ "] as part of path ["
|
||||
+ path
|
||||
+ "]"
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.cannotSet(path, leafKey, context));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -706,9 +647,7 @@ public final class IngestDocument {
|
|||
if (clazz.isInstance(object)) {
|
||||
return clazz.cast(object);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"field [" + path + "] of type [" + object.getClass().getName() + "] cannot be cast to [" + clazz.getName() + "]"
|
||||
);
|
||||
throw new IllegalArgumentException(Errors.cannotCast(path, object, clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -824,15 +763,12 @@ public final class IngestDocument {
|
|||
@SuppressWarnings("unchecked")
|
||||
private static Set<String> getAllFields(Map<String, Object> input, String prefix) {
|
||||
Set<String> allFields = Sets.newHashSet();
|
||||
|
||||
input.forEach((k, v) -> {
|
||||
allFields.add(prefix + k);
|
||||
|
||||
if (v instanceof Map<?, ?> mapValue) {
|
||||
allFields.addAll(getAllFields((Map<String, Object>) mapValue, prefix + k + "."));
|
||||
}
|
||||
});
|
||||
|
||||
return allFields;
|
||||
}
|
||||
|
||||
|
@ -1055,24 +991,13 @@ public final class IngestDocument {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ResolveResult {
|
||||
boolean wasSuccessful;
|
||||
String errorMessage;
|
||||
Object resolvedObject;
|
||||
|
||||
private record ResolveResult(boolean wasSuccessful, Object resolvedObject, String errorMessage) {
|
||||
static ResolveResult success(Object resolvedObject) {
|
||||
ResolveResult result = new ResolveResult();
|
||||
result.wasSuccessful = true;
|
||||
result.resolvedObject = resolvedObject;
|
||||
return result;
|
||||
return new ResolveResult(true, resolvedObject, null);
|
||||
}
|
||||
|
||||
static ResolveResult error(String errorMessage) {
|
||||
ResolveResult result = new ResolveResult();
|
||||
result.wasSuccessful = false;
|
||||
result.errorMessage = errorMessage;
|
||||
return result;
|
||||
|
||||
return new ResolveResult(false, null, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1153,4 +1078,57 @@ public final class IngestDocument {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Errors {
|
||||
private Errors() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
private static String cannotCast(String path, Object value, Class<?> clazz) {
|
||||
return "field [" + path + "] of type [" + value.getClass().getName() + "] cannot be cast to [" + clazz.getName() + "]";
|
||||
}
|
||||
|
||||
private static String cannotRemove(String path, String key, Object value) {
|
||||
if (value == null) {
|
||||
return "cannot remove [" + key + "] from null as part of path [" + path + "]";
|
||||
} else {
|
||||
final String type = value.getClass().getName();
|
||||
return "cannot remove [" + key + "] from object of type [" + type + "] as part of path [" + path + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private static String cannotResolve(String path, String key, Object value) {
|
||||
if (value == null) {
|
||||
return "cannot resolve [" + key + "] from null as part of path [" + path + "]";
|
||||
} else {
|
||||
final String type = value.getClass().getName();
|
||||
return "cannot resolve [" + key + "] from object of type [" + type + "] as part of path [" + path + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private static String cannotSet(String path, String key, Object value) {
|
||||
if (value == null) {
|
||||
return "cannot set [" + key + "] with null parent as part of path [" + path + "]";
|
||||
} else {
|
||||
final String type = value.getClass().getName();
|
||||
return "cannot set [" + key + "] with parent object of type [" + type + "] as part of path [" + path + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private static String outOfBounds(String path, int index, int length) {
|
||||
return "[" + index + "] is out of bounds for array with length [" + length + "] as part of path [" + path + "]";
|
||||
}
|
||||
|
||||
private static String notInteger(String path, String key) {
|
||||
return "[" + key + "] is not an integer, cannot be used as an index as part of path [" + path + "]";
|
||||
}
|
||||
|
||||
private static String notPresent(String path, String key) {
|
||||
return "field [" + key + "] not present as part of path [" + path + "]";
|
||||
}
|
||||
|
||||
private static String notStringOrByteArray(String path, Object value) {
|
||||
return "Content field [" + path + "] of unknown type [" + value.getClass().getName() + "], must be string or byte array";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,6 +290,7 @@ public class ConfigurationUtilsTests extends ESTestCase {
|
|||
propertyValue,
|
||||
scriptService
|
||||
);
|
||||
assertThat(result, instanceOf(ConfigurationUtils.ConstantTemplateScriptFactory.class));
|
||||
assertThat(result.newInstance(null).execute(), equalTo(propertyValue));
|
||||
verify(scriptService, times(0)).compile(any(), any());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue