Skip to content

Commit 668a05d

Browse files
alexshadow007talevy
authored andcommitted
Add target_field parameter to gsub, join, lowercase, sort, split, trim, uppercase (#24133)
Closes #23682 #23228
1 parent 681a96a commit 668a05d

26 files changed

+476
-293
lines changed

docs/reference/ingest/ingest-node.asciidoc

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,10 +1487,12 @@ If the field is not a string, the processor will throw an exception.
14871487
.Gsub Options
14881488
[options="header"]
14891489
|======
1490-
| Name | Required | Default | Description
1491-
| `field` | yes | - | The field to apply the replacement to
1492-
| `pattern` | yes | - | The pattern to be replaced
1493-
| `replacement` | yes | - | The string to replace the matching patterns with
1490+
| Name | Required | Default | Description
1491+
| `field` | yes | - | The field to apply the replacement to
1492+
| `pattern` | yes | - | The pattern to be replaced
1493+
| `replacement` | yes | - | The string to replace the matching patterns with
1494+
| `target_field` | no | `field` | The field to assign the converted value to, by default `field` is updated in-place
1495+
| `ignore_missing` | no | `false` | If `true` and `field` does not exist or is `null`, the processor quietly exits without modifying the document
14941496
|======
14951497

14961498
[source,js]
@@ -1514,9 +1516,10 @@ Throws an error when the field is not an array.
15141516
.Join Options
15151517
[options="header"]
15161518
|======
1517-
| Name | Required | Default | Description
1518-
| `field` | yes | - | The field to be separated
1519-
| `separator` | yes | - | The separator character
1519+
| Name | Required | Default | Description
1520+
| `field` | yes | - | The field to be separated
1521+
| `separator` | yes | - | The separator character
1522+
| `target_field` | no | `field` | The field to assign the joined value to, by default `field` is updated in-place
15201523
|======
15211524

15221525
[source,js]
@@ -1660,6 +1663,7 @@ Converts a string to its lowercase equivalent.
16601663
|======
16611664
| Name | Required | Default | Description
16621665
| `field` | yes | - | The field to make lowercase
1666+
| `target_field` | no | `field` | The field to assign the converted value to, by default `field` is updated in-place
16631667
| `ignore_missing` | no | `false` | If `true` and `field` does not exist or is `null`, the processor quietly exits without modifying the document
16641668
|======
16651669

@@ -1816,6 +1820,7 @@ Splits a field into an array using a separator character. Only works on string f
18161820
| Name | Required | Default | Description
18171821
| `field` | yes | - | The field to split
18181822
| `separator` | yes | - | A regex which matches the separator, eg `,` or `\s+`
1823+
| `target_field` | no | `field` | The field to assign the split value to, by default `field` is updated in-place
18191824
| `ignore_missing` | no | `false` | If `true` and `field` does not exist, the processor quietly exits without modifying the document
18201825
|======
18211826

@@ -1841,9 +1846,10 @@ Throws an error when the field is not an array.
18411846
.Sort Options
18421847
[options="header"]
18431848
|======
1844-
| Name | Required | Default | Description
1845-
| `field` | yes | - | The field to be sorted
1846-
| `order` | no | `"asc"` | The sort order to use. Accepts `"asc"` or `"desc"`.
1849+
| Name | Required | Default | Description
1850+
| `field` | yes | - | The field to be sorted
1851+
| `order` | no | `"asc"` | The sort order to use. Accepts `"asc"` or `"desc"`.
1852+
| `target_field` | no | `field` | The field to assign the sorted value to, by default `field` is updated in-place
18471853
|======
18481854

18491855
[source,js]
@@ -1869,6 +1875,7 @@ NOTE: This only works on leading and trailing whitespace.
18691875
|======
18701876
| Name | Required | Default | Description
18711877
| `field` | yes | - | The string-valued field to trim whitespace from
1878+
| `target_field` | no | `field` | The field to assign the trimmed value to, by default `field` is updated in-place
18721879
| `ignore_missing` | no | `false` | If `true` and `field` does not exist, the processor quietly exits without modifying the document
18731880
|======
18741881

@@ -1892,6 +1899,7 @@ Converts a string to its uppercase equivalent.
18921899
|======
18931900
| Name | Required | Default | Description
18941901
| `field` | yes | - | The field to make uppercase
1902+
| `target_field` | no | `field` | The field to assign the converted value to, by default `field` is updated in-place
18951903
| `ignore_missing` | no | `false` | If `true` and `field` does not exist or is `null`, the processor quietly exits without modifying the document
18961904
|======
18971905

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/AbstractStringProcessor.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333
abstract class AbstractStringProcessor extends AbstractProcessor {
3434
private final String field;
3535
private final boolean ignoreMissing;
36+
private final String targetField;
3637

37-
AbstractStringProcessor(String tag, String field, boolean ignoreMissing) {
38+
AbstractStringProcessor(String tag, String field, boolean ignoreMissing, String targetField) {
3839
super(tag);
3940
this.field = field;
4041
this.ignoreMissing = ignoreMissing;
42+
this.targetField = targetField;
4143
}
4244

4345
public String getField() {
@@ -48,6 +50,10 @@ boolean isIgnoreMissing() {
4850
return ignoreMissing;
4951
}
5052

53+
String getTargetField() {
54+
return targetField;
55+
}
56+
5157
@Override
5258
public final void execute(IngestDocument document) {
5359
String val = document.getFieldValue(field, String.class, ignoreMissing);
@@ -58,7 +64,7 @@ public final void execute(IngestDocument document) {
5864
throw new IllegalArgumentException("field [" + field + "] is null, cannot process it.");
5965
}
6066

61-
document.setFieldValue(field, process(val));
67+
document.setFieldValue(targetField, process(val));
6268
}
6369

6470
protected abstract String process(String value);
@@ -75,9 +81,12 @@ public AbstractStringProcessor create(Map<String, Processor.Factory> registry, S
7581
Map<String, Object> config) throws Exception {
7682
String field = ConfigurationUtils.readStringProperty(processorType, tag, config, "field");
7783
boolean ignoreMissing = ConfigurationUtils.readBooleanProperty(processorType, tag, config, "ignore_missing", false);
78-
return newProcessor(tag, field, ignoreMissing);
84+
String targetField = ConfigurationUtils.readStringProperty(processorType, tag, config, "target_field", field);
85+
86+
return newProcessor(tag, config, field, ignoreMissing, targetField);
7987
}
8088

81-
protected abstract AbstractStringProcessor newProcessor(String processorTag, String field, boolean ignoreMissing);
89+
protected abstract AbstractStringProcessor newProcessor(String processorTag, Map<String, Object> config, String field,
90+
boolean ignoreMissing, String targetField);
8291
}
8392
}

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/GsubProcessor.java

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@
1919

2020
package org.elasticsearch.ingest.common;
2121

22-
import org.elasticsearch.ingest.AbstractProcessor;
23-
import org.elasticsearch.ingest.IngestDocument;
24-
import org.elasticsearch.ingest.Processor;
25-
2622
import java.util.Map;
27-
import java.util.regex.Matcher;
2823
import java.util.regex.Pattern;
2924

3025
import static org.elasticsearch.ingest.ConfigurationUtils.newConfigurationException;
@@ -34,25 +29,19 @@
3429
* Processor that allows to search for patterns in field content and replace them with corresponding string replacement.
3530
* Support fields of string type only, throws exception if a field is of a different type.
3631
*/
37-
public final class GsubProcessor extends AbstractProcessor {
32+
public final class GsubProcessor extends AbstractStringProcessor {
3833

3934
public static final String TYPE = "gsub";
4035

41-
private final String field;
4236
private final Pattern pattern;
4337
private final String replacement;
4438

45-
GsubProcessor(String tag, String field, Pattern pattern, String replacement) {
46-
super(tag);
47-
this.field = field;
39+
GsubProcessor(String tag, String field, Pattern pattern, String replacement, boolean ignoreMissing, String targetField) {
40+
super(tag, field, ignoreMissing, targetField);
4841
this.pattern = pattern;
4942
this.replacement = replacement;
5043
}
5144

52-
String getField() {
53-
return field;
54-
}
55-
5645
Pattern getPattern() {
5746
return pattern;
5847
}
@@ -61,28 +50,25 @@ String getReplacement() {
6150
return replacement;
6251
}
6352

64-
6553
@Override
66-
public void execute(IngestDocument document) {
67-
String oldVal = document.getFieldValue(field, String.class);
68-
if (oldVal == null) {
69-
throw new IllegalArgumentException("field [" + field + "] is null, cannot match pattern.");
70-
}
71-
Matcher matcher = pattern.matcher(oldVal);
72-
String newVal = matcher.replaceAll(replacement);
73-
document.setFieldValue(field, newVal);
54+
protected String process(String value) {
55+
return pattern.matcher(value).replaceAll(replacement);
7456
}
7557

7658
@Override
7759
public String getType() {
7860
return TYPE;
7961
}
8062

81-
public static final class Factory implements Processor.Factory {
63+
public static final class Factory extends AbstractStringProcessor.Factory {
64+
65+
public Factory() {
66+
super(TYPE);
67+
}
68+
8269
@Override
83-
public GsubProcessor create(Map<String, Processor.Factory> registry, String processorTag,
84-
Map<String, Object> config) throws Exception {
85-
String field = readStringProperty(TYPE, processorTag, config, "field");
70+
protected AbstractStringProcessor newProcessor(String processorTag, Map<String, Object> config, String field,
71+
boolean ignoreMissing, String targetField) {
8672
String pattern = readStringProperty(TYPE, processorTag, config, "pattern");
8773
String replacement = readStringProperty(TYPE, processorTag, config, "replacement");
8874
Pattern searchPattern;
@@ -91,7 +77,7 @@ public GsubProcessor create(Map<String, Processor.Factory> registry, String proc
9177
} catch (Exception e) {
9278
throw newConfigurationException(TYPE, processorTag, "pattern", "Invalid regex pattern. " + e.getMessage());
9379
}
94-
return new GsubProcessor(processorTag, field, searchPattern, replacement);
80+
return new GsubProcessor(processorTag, field, searchPattern, replacement, ignoreMissing, targetField);
9581
}
9682
}
9783
}

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/JoinProcessor.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ public final class JoinProcessor extends AbstractProcessor {
3838

3939
private final String field;
4040
private final String separator;
41+
private final String targetField;
4142

42-
JoinProcessor(String tag, String field, String separator) {
43+
JoinProcessor(String tag, String field, String separator, String targetField) {
4344
super(tag);
4445
this.field = field;
4546
this.separator = separator;
47+
this.targetField = targetField;
4648
}
4749

4850
String getField() {
@@ -53,6 +55,10 @@ String getSeparator() {
5355
return separator;
5456
}
5557

58+
String getTargetField() {
59+
return targetField;
60+
}
61+
5662
@Override
5763
public void execute(IngestDocument document) {
5864
List<?> list = document.getFieldValue(field, List.class);
@@ -62,7 +68,7 @@ public void execute(IngestDocument document) {
6268
String joined = list.stream()
6369
.map(Object::toString)
6470
.collect(Collectors.joining(separator));
65-
document.setFieldValue(field, joined);
71+
document.setFieldValue(targetField, joined);
6672
}
6773

6874
@Override
@@ -76,7 +82,8 @@ public JoinProcessor create(Map<String, Processor.Factory> registry, String proc
7682
Map<String, Object> config) throws Exception {
7783
String field = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "field");
7884
String separator = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "separator");
79-
return new JoinProcessor(processorTag, field, separator);
85+
String targetField = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "target_field", field);
86+
return new JoinProcessor(processorTag, field, separator, targetField);
8087
}
8188
}
8289
}

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/LowercaseProcessor.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.ingest.common;
2121

2222
import java.util.Locale;
23+
import java.util.Map;
2324

2425
/**
2526
* Processor that converts the content of string fields to lowercase.
@@ -30,8 +31,8 @@ public final class LowercaseProcessor extends AbstractStringProcessor {
3031

3132
public static final String TYPE = "lowercase";
3233

33-
LowercaseProcessor(String processorTag, String field, boolean ignoreMissing) {
34-
super(processorTag, field, ignoreMissing);
34+
LowercaseProcessor(String processorTag, String field, boolean ignoreMissing, String targetField) {
35+
super(processorTag, field, ignoreMissing, targetField);
3536
}
3637

3738
@Override
@@ -51,8 +52,9 @@ public Factory() {
5152
}
5253

5354
@Override
54-
protected LowercaseProcessor newProcessor(String tag, String field, boolean ignoreMissing) {
55-
return new LowercaseProcessor(tag, field, ignoreMissing);
55+
protected LowercaseProcessor newProcessor(String tag, Map<String, Object> config, String field,
56+
boolean ignoreMissing, String targetField) {
57+
return new LowercaseProcessor(tag, field, ignoreMissing, targetField);
5658
}
5759
}
5860
}

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/SortProcessor.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@ public static SortOrder fromString(String value) {
6969

7070
private final String field;
7171
private final SortOrder order;
72+
private final String targetField;
7273

73-
SortProcessor(String tag, String field, SortOrder order) {
74+
SortProcessor(String tag, String field, SortOrder order, String targetField) {
7475
super(tag);
7576
this.field = field;
7677
this.order = order;
78+
this.targetField = targetField;
7779
}
7880

7981
String getField() {
@@ -84,6 +86,10 @@ SortOrder getOrder() {
8486
return order;
8587
}
8688

89+
String getTargetField() {
90+
return targetField;
91+
}
92+
8793
@Override
8894
@SuppressWarnings("unchecked")
8995
public void execute(IngestDocument document) {
@@ -103,7 +109,7 @@ public void execute(IngestDocument document) {
103109
Collections.sort(list, Collections.reverseOrder());
104110
}
105111

106-
document.setFieldValue(field, list);
112+
document.setFieldValue(targetField, list);
107113
}
108114

109115
@Override
@@ -117,6 +123,7 @@ public static final class Factory implements Processor.Factory {
117123
public SortProcessor create(Map<String, Processor.Factory> registry, String processorTag,
118124
Map<String, Object> config) throws Exception {
119125
String field = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, FIELD);
126+
String targetField = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "target_field", field);
120127
try {
121128
SortOrder direction = SortOrder.fromString(
122129
ConfigurationUtils.readStringProperty(
@@ -125,7 +132,7 @@ public SortProcessor create(Map<String, Processor.Factory> registry, String proc
125132
config,
126133
ORDER,
127134
DEFAULT_ORDER));
128-
return new SortProcessor(processorTag, field, direction);
135+
return new SortProcessor(processorTag, field, direction, targetField);
129136
} catch (IllegalArgumentException e) {
130137
throw ConfigurationUtils.newConfigurationException(TYPE, processorTag, ORDER, e.getMessage());
131138
}

0 commit comments

Comments
 (0)