Skip to content

Commit 353f189

Browse files
authored
Simplify RuntimeField creation (#75009)
* Simplify RuntimeField creation Now that AbstractScriptFieldType and LeafRuntimeField are separate, we can further simplify the creation of runtime fields. Their builder always creates a new instance of the same class (LeafRuntimeField), which can be shared throughout all the builders. The only bit that changes is the MappedFieldType instance, which becomes the only required abstract method in the base builder. Also, the dynamically created runtime field variant that parses its values from source can be created through a builder which makes sure that we reuse as much code as possible. * checkstyle * restore MappedFieldType
1 parent 4d462e7 commit 353f189

13 files changed

+145
-187
lines changed

server/src/main/java/org/elasticsearch/index/mapper/AbstractScriptFieldType.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,22 @@ abstract static class Builder<Factory> extends RuntimeField.Builder {
210210
this.parseFromSourceFactory = parseFromSourceFactory;
211211
}
212212

213-
abstract RuntimeField newRuntimeField(Factory scriptFactory);
214-
215213
@Override
216214
protected final RuntimeField createRuntimeField(MappingParserContext parserContext) {
217215
if (script.get() == null) {
218-
return newRuntimeField(parseFromSourceFactory);
216+
return createRuntimeField(parseFromSourceFactory);
219217
}
220218
Factory factory = parserContext.scriptCompiler().compile(script.getValue(), scriptContext);
221-
return newRuntimeField(factory);
219+
return createRuntimeField(factory);
220+
}
221+
222+
final RuntimeField createRuntimeField(Factory scriptFactory) {
223+
AbstractScriptFieldType<?> fieldType = createFieldType(name, scriptFactory, getScript(), meta());
224+
return new LeafRuntimeField(name, fieldType, this);
222225
}
223226

227+
abstract AbstractScriptFieldType<?> createFieldType(String name, Factory factory, Script script, Map<String, String> meta);
228+
224229
@Override
225230
protected List<FieldMapper.Parameter<?>> getParameters() {
226231
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());

server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptFieldType.java

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.elasticsearch.common.Strings;
1515
import org.elasticsearch.common.lucene.search.Queries;
1616
import org.elasticsearch.common.time.DateMathParser;
17-
import org.elasticsearch.common.xcontent.ToXContent;
1817
import org.elasticsearch.core.Booleans;
1918
import org.elasticsearch.index.fielddata.BooleanScriptFieldData;
2019
import org.elasticsearch.index.query.SearchExecutionContext;
@@ -27,38 +26,29 @@
2726

2827
import java.time.ZoneId;
2928
import java.util.Collection;
30-
import java.util.Collections;
3129
import java.util.Map;
3230
import java.util.function.Supplier;
3331

3432
public final class BooleanScriptFieldType extends AbstractScriptFieldType<BooleanFieldScript.LeafFactory> {
3533

36-
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name ->
37-
new Builder<>(name, BooleanFieldScript.CONTEXT, BooleanFieldScript.PARSE_FROM_SOURCE) {
38-
@Override
39-
RuntimeField newRuntimeField(BooleanFieldScript.Factory scriptFactory) {
40-
return runtimeField(name, this, scriptFactory, getScript(), meta());
41-
}
42-
});
34+
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(Builder::new);
4335

44-
private static RuntimeField runtimeField(
45-
String name,
46-
ToXContent toXContent,
47-
BooleanFieldScript.Factory scriptFactory,
48-
Script script,
49-
Map<String, String> meta
50-
) {
51-
return new LeafRuntimeField(name, new BooleanScriptFieldType(name, scriptFactory, script, meta), toXContent);
36+
private static class Builder extends AbstractScriptFieldType.Builder<BooleanFieldScript.Factory> {
37+
Builder(String name) {
38+
super(name, BooleanFieldScript.CONTEXT, BooleanFieldScript.PARSE_FROM_SOURCE);
39+
}
40+
41+
@Override
42+
AbstractScriptFieldType<?> createFieldType(String name,
43+
BooleanFieldScript.Factory factory,
44+
Script script,
45+
Map<String, String> meta) {
46+
return new BooleanScriptFieldType(name, factory, script, meta);
47+
}
5248
}
5349

5450
public static RuntimeField sourceOnly(String name) {
55-
return runtimeField(
56-
name,
57-
(builder, params) -> builder,
58-
BooleanFieldScript.PARSE_FROM_SOURCE,
59-
DEFAULT_SCRIPT,
60-
Collections.emptyMap()
61-
);
51+
return new Builder(name).createRuntimeField(BooleanFieldScript.PARSE_FROM_SOURCE);
6252
}
6353

6454
BooleanScriptFieldType(

server/src/main/java/org/elasticsearch/index/mapper/DateScriptFieldType.java

Lines changed: 47 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.elasticsearch.common.time.DateFormatter;
1717
import org.elasticsearch.common.time.DateMathParser;
1818
import org.elasticsearch.common.util.LocaleUtils;
19-
import org.elasticsearch.common.xcontent.ToXContent;
2019
import org.elasticsearch.core.Nullable;
2120
import org.elasticsearch.core.TimeValue;
2221
import org.elasticsearch.index.fielddata.DateScriptFieldData;
@@ -45,77 +44,62 @@
4544

4645
public class DateScriptFieldType extends AbstractScriptFieldType<DateFieldScript.LeafFactory> {
4746

48-
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name ->
49-
new Builder<>(name, DateFieldScript.CONTEXT, DateFieldScript.PARSE_FROM_SOURCE) {
50-
private final FieldMapper.Parameter<String> format = FieldMapper.Parameter.stringParam(
51-
"format",
52-
true,
53-
initializerNotSupported(),
54-
null
55-
).setSerializer((b, n, v) -> {
56-
if (v != null && false == v.equals(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern())) {
57-
b.field(n, v);
58-
}
59-
}, Object::toString).acceptsNull();
60-
61-
private final FieldMapper.Parameter<Locale> locale = new FieldMapper.Parameter<>(
62-
"locale",
63-
true,
64-
() -> null,
65-
(n, c, o) -> o == null ? null : LocaleUtils.parse(o.toString()),
66-
initializerNotSupported()
67-
).setSerializer((b, n, v) -> {
68-
if (v != null && false == v.equals(Locale.ROOT)) {
69-
b.field(n, v.toString());
70-
}
71-
}, Object::toString).acceptsNull();
72-
73-
@Override
74-
protected List<FieldMapper.Parameter<?>> getParameters() {
75-
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());
76-
parameters.add(format);
77-
parameters.add(locale);
78-
return Collections.unmodifiableList(parameters);
47+
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(Builder::new);
48+
49+
private static class Builder extends AbstractScriptFieldType.Builder<DateFieldScript.Factory> {
50+
private final FieldMapper.Parameter<String> format = FieldMapper.Parameter.stringParam(
51+
"format",
52+
true,
53+
initializerNotSupported(),
54+
null
55+
).setSerializer((b, n, v) -> {
56+
if (v != null && false == v.equals(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern())) {
57+
b.field(n, v);
7958
}
80-
81-
@Override
82-
RuntimeField newRuntimeField(DateFieldScript.Factory scriptFactory) {
83-
String pattern = format.getValue() == null ? DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern() : format.getValue();
84-
Locale locale = this.locale.getValue() == null ? Locale.ROOT : this.locale.getValue();
85-
DateFormatter dateTimeFormatter = DateFormatter.forPattern(pattern).withLocale(locale);
86-
return runtimeField(name, this, dateTimeFormatter, scriptFactory, getScript(), meta());
59+
}, Object::toString).acceptsNull();
60+
61+
private final FieldMapper.Parameter<Locale> locale = new FieldMapper.Parameter<>(
62+
"locale",
63+
true,
64+
() -> null,
65+
(n, c, o) -> o == null ? null : LocaleUtils.parse(o.toString()),
66+
initializerNotSupported()
67+
).setSerializer((b, n, v) -> {
68+
if (v != null && false == v.equals(Locale.ROOT)) {
69+
b.field(n, v.toString());
8770
}
88-
});
71+
}, Object::toString).acceptsNull();
8972

90-
private final DateFormatter dateTimeFormatter;
91-
private final DateMathParser dateMathParser;
73+
Builder(String name) {
74+
super(name, DateFieldScript.CONTEXT, DateFieldScript.PARSE_FROM_SOURCE);
75+
}
9276

93-
private static RuntimeField runtimeField(
94-
String name,
95-
ToXContent toXContent,
96-
DateFormatter dateFormatter,
97-
DateFieldScript.Factory scriptFactory,
98-
Script script,
99-
Map<String, String> meta
100-
) {
101-
return new LeafRuntimeField(name, new DateScriptFieldType(name, scriptFactory, dateFormatter, script, meta), toXContent);
77+
@Override
78+
protected List<FieldMapper.Parameter<?>> getParameters() {
79+
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());
80+
parameters.add(format);
81+
parameters.add(locale);
82+
return Collections.unmodifiableList(parameters);
83+
}
84+
85+
@Override
86+
AbstractScriptFieldType<?> createFieldType(String name, DateFieldScript.Factory factory, Script script, Map<String, String> meta) {
87+
String pattern = format.getValue() == null ? DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern() : format.getValue();
88+
Locale locale = this.locale.getValue() == null ? Locale.ROOT : this.locale.getValue();
89+
DateFormatter dateTimeFormatter = DateFormatter.forPattern(pattern).withLocale(locale);
90+
return new DateScriptFieldType(name, factory, dateTimeFormatter, script, meta);
91+
}
10292
}
10393

10494
public static RuntimeField sourceOnly(String name, DateFormatter dateTimeFormatter) {
105-
return runtimeField(
106-
name,
107-
(builder, params) -> {
108-
if (DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern().equals(dateTimeFormatter.pattern()) == false) {
109-
builder.field("format", dateTimeFormatter.pattern());
110-
}
111-
return builder;
112-
},
113-
dateTimeFormatter,
114-
DateFieldScript.PARSE_FROM_SOURCE,
115-
DEFAULT_SCRIPT,
116-
Collections.emptyMap());
95+
Builder builder = new Builder(name);
96+
builder.format.setValue(dateTimeFormatter.pattern());
97+
return builder.createRuntimeField(DateFieldScript.PARSE_FROM_SOURCE);
11798
}
11899

100+
private final DateFormatter dateTimeFormatter;
101+
private final DateMathParser dateMathParser;
102+
119103
DateScriptFieldType(
120104
String name,
121105
DateFieldScript.Factory scriptFactory,

server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptFieldType.java

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.apache.lucene.search.Query;
1515
import org.elasticsearch.common.lucene.search.Queries;
1616
import org.elasticsearch.common.time.DateMathParser;
17-
import org.elasticsearch.common.xcontent.ToXContent;
1817
import org.elasticsearch.index.fielddata.DoubleScriptFieldData;
1918
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
2019
import org.elasticsearch.index.query.SearchExecutionContext;
@@ -29,37 +28,29 @@
2928

3029
import java.time.ZoneId;
3130
import java.util.Collection;
32-
import java.util.Collections;
3331
import java.util.Map;
3432
import java.util.function.Supplier;
3533

3634
public final class DoubleScriptFieldType extends AbstractScriptFieldType<DoubleFieldScript.LeafFactory> {
3735

38-
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name ->
39-
new Builder<>(name, DoubleFieldScript.CONTEXT, DoubleFieldScript.PARSE_FROM_SOURCE) {
40-
@Override
41-
RuntimeField newRuntimeField(DoubleFieldScript.Factory scriptFactory) {
42-
return runtimeField(name, this, scriptFactory, getScript(), meta());
43-
}
44-
});
36+
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(Builder::new);
4537

46-
private static RuntimeField runtimeField(
47-
String name,
48-
ToXContent toXContent,
49-
DoubleFieldScript.Factory scriptFactory,
50-
Script script,
51-
Map<String, String> meta
52-
) {
53-
return new LeafRuntimeField(name, new DoubleScriptFieldType(name, scriptFactory, script, meta), toXContent);
38+
private static class Builder extends AbstractScriptFieldType.Builder<DoubleFieldScript.Factory> {
39+
Builder(String name) {
40+
super(name, DoubleFieldScript.CONTEXT, DoubleFieldScript.PARSE_FROM_SOURCE);
41+
}
42+
43+
@Override
44+
AbstractScriptFieldType<?> createFieldType(String name,
45+
DoubleFieldScript.Factory factory,
46+
Script script,
47+
Map<String, String> meta) {
48+
return new DoubleScriptFieldType(name, factory, script, meta);
49+
}
5450
}
5551

5652
public static RuntimeField sourceOnly(String name) {
57-
return runtimeField(
58-
name,
59-
(builder, params) -> builder,
60-
DoubleFieldScript.PARSE_FROM_SOURCE,
61-
DEFAULT_SCRIPT,
62-
Collections.emptyMap());
53+
return new Builder(name).createRuntimeField(DoubleFieldScript.PARSE_FROM_SOURCE);
6354
}
6455

6556
DoubleScriptFieldType(

server/src/main/java/org/elasticsearch/index/mapper/GeoPointScriptFieldType.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ public final class GeoPointScriptFieldType extends AbstractScriptFieldType<GeoPo
3838
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name ->
3939
new Builder<>(name, GeoPointFieldScript.CONTEXT, GeoPointFieldScript.PARSE_FROM_SOURCE) {
4040
@Override
41-
RuntimeField newRuntimeField(GeoPointFieldScript.Factory scriptFactory) {
42-
return new LeafRuntimeField(name, new GeoPointScriptFieldType(name, scriptFactory, getScript(), meta()), this);
41+
AbstractScriptFieldType<?> createFieldType(String name,
42+
GeoPointFieldScript.Factory factory,
43+
Script script,
44+
Map<String, String> meta) {
45+
return new GeoPointScriptFieldType(name, factory, getScript(), meta());
4346
}
4447
});
4548

server/src/main/java/org/elasticsearch/index/mapper/IpScriptFieldType.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ public final class IpScriptFieldType extends AbstractScriptFieldType<IpFieldScri
4444
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name ->
4545
new Builder<>(name, IpFieldScript.CONTEXT, IpFieldScript.PARSE_FROM_SOURCE) {
4646
@Override
47-
RuntimeField newRuntimeField(IpFieldScript.Factory scriptFactory) {
48-
return new LeafRuntimeField(name, new IpScriptFieldType(name, scriptFactory, getScript(), meta()), this);
47+
AbstractScriptFieldType<?> createFieldType(String name,
48+
IpFieldScript.Factory factory,
49+
Script script,
50+
Map<String, String> meta) {
51+
return new IpScriptFieldType(name, factory, getScript(), meta());
4952
}
5053
});
5154

server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptFieldType.java

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.elasticsearch.common.lucene.BytesRefs;
1515
import org.elasticsearch.common.time.DateMathParser;
1616
import org.elasticsearch.common.unit.Fuzziness;
17-
import org.elasticsearch.common.xcontent.ToXContent;
1817
import org.elasticsearch.index.fielddata.StringScriptFieldData;
1918
import org.elasticsearch.index.query.SearchExecutionContext;
2019
import org.elasticsearch.script.Script;
@@ -31,7 +30,6 @@
3130

3231
import java.time.ZoneId;
3332
import java.util.Collection;
34-
import java.util.Collections;
3533
import java.util.Map;
3634
import java.util.Objects;
3735
import java.util.Set;
@@ -41,31 +39,24 @@
4139

4240
public final class KeywordScriptFieldType extends AbstractScriptFieldType<StringFieldScript.LeafFactory> {
4341

44-
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name ->
45-
new Builder<>(name, StringFieldScript.CONTEXT, StringFieldScript.PARSE_FROM_SOURCE) {
46-
@Override
47-
RuntimeField newRuntimeField(StringFieldScript.Factory scriptFactory) {
48-
return runtimeField(name, this, scriptFactory, getScript(), meta());
49-
}
50-
});
42+
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(Builder::new);
5143

52-
private static RuntimeField runtimeField(
53-
String name,
54-
ToXContent toXContent,
55-
StringFieldScript.Factory scriptFactory,
56-
Script script,
57-
Map<String, String> meta
58-
) {
59-
return new LeafRuntimeField(name, new KeywordScriptFieldType(name, scriptFactory, script, meta), toXContent);
44+
private static class Builder extends AbstractScriptFieldType.Builder<StringFieldScript.Factory> {
45+
Builder(String name) {
46+
super(name, StringFieldScript.CONTEXT, StringFieldScript.PARSE_FROM_SOURCE);
47+
}
48+
49+
@Override
50+
AbstractScriptFieldType<?> createFieldType(String name,
51+
StringFieldScript.Factory factory,
52+
Script script,
53+
Map<String, String> meta) {
54+
return new KeywordScriptFieldType(name, factory, script, meta);
55+
}
6056
}
6157

6258
public static RuntimeField sourceOnly(String name) {
63-
return runtimeField(
64-
name,
65-
(builder, params) -> builder,
66-
StringFieldScript.PARSE_FROM_SOURCE,
67-
DEFAULT_SCRIPT,
68-
Collections.emptyMap());
59+
return new Builder(name).createRuntimeField(StringFieldScript.PARSE_FROM_SOURCE);
6960
}
7061

7162
public KeywordScriptFieldType(

server/src/main/java/org/elasticsearch/index/mapper/LeafRuntimeField.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020
* a single MappedFieldType from {@link RuntimeField#asMappedFieldTypes()}
2121
*/
2222
public final class LeafRuntimeField implements RuntimeField {
23-
24-
protected final String name;
25-
protected final ToXContent toXContent;
26-
protected final MappedFieldType mappedFieldType;
23+
private final String name;
24+
private final ToXContent toXContent;
25+
private final MappedFieldType mappedFieldType;
2726

2827
public LeafRuntimeField(String name, MappedFieldType mappedFieldType, ToXContent toXContent) {
2928
this.name = name;

0 commit comments

Comments
 (0)