Skip to content

Commit 21f660d

Browse files
authored
[Rollup] Remove builders from DateHistogramGroupConfig (#32555)
Same motivation as #32507 but for the DateHistogramGroupConfig configuration object. This pull request also changes the format of the time zone from a Joda's DateTimeZone to a simple String. It should help to port the API to the high level rest client and allows clients to not be forced to use the Joda Time library. Serialization is impacted but does not need a backward compatibility layer as DateTimeZone are serialized as String anyway. XContent also expects a String for timezone, so I found it easier to move everything to String. Related to #29827
1 parent d05f39d commit 21f660d

File tree

14 files changed

+287
-313
lines changed

14 files changed

+287
-313
lines changed
Lines changed: 103 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import org.elasticsearch.action.ActionRequestValidationException;
99
import org.elasticsearch.action.fieldcaps.FieldCapabilities;
10+
import org.elasticsearch.common.Nullable;
1011
import org.elasticsearch.common.ParseField;
1112
import org.elasticsearch.common.Strings;
1213
import org.elasticsearch.common.io.stream.StreamInput;
@@ -15,8 +16,8 @@
1516
import org.elasticsearch.common.rounding.DateTimeUnit;
1617
import org.elasticsearch.common.rounding.Rounding;
1718
import org.elasticsearch.common.unit.TimeValue;
18-
import org.elasticsearch.common.xcontent.ObjectParser;
19-
import org.elasticsearch.common.xcontent.ToXContentFragment;
19+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
20+
import org.elasticsearch.common.xcontent.ToXContentObject;
2021
import org.elasticsearch.common.xcontent.XContentBuilder;
2122
import org.elasticsearch.common.xcontent.XContentParser;
2223
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
@@ -33,6 +34,10 @@
3334
import java.util.Map;
3435
import java.util.Objects;
3536

37+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
38+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
39+
import static org.elasticsearch.common.xcontent.ObjectParser.ValueType;
40+
3641
/**
3742
* The configuration object for the histograms in the rollup config
3843
*
@@ -47,71 +52,100 @@
4752
* ]
4853
* }
4954
*/
50-
public class DateHistoGroupConfig implements Writeable, ToXContentFragment {
51-
private static final String NAME = "date_histo_group_config";
52-
public static final ObjectParser<DateHistoGroupConfig.Builder, Void> PARSER
53-
= new ObjectParser<>(NAME, DateHistoGroupConfig.Builder::new);
54-
55-
private static final ParseField INTERVAL = new ParseField("interval");
56-
private static final ParseField DELAY = new ParseField("delay");
57-
private static final ParseField FIELD = new ParseField("field");
58-
public static final ParseField TIME_ZONE = new ParseField("time_zone");
55+
public class DateHistogramGroupConfig implements Writeable, ToXContentObject {
56+
57+
private static final String NAME = "date_histogram";
58+
private static final String INTERVAL = "interval";
59+
private static final String FIELD = "field";
60+
public static final String TIME_ZONE = "time_zone";
61+
private static final String DELAY = "delay";
62+
private static final String DEFAULT_TIMEZONE = "UTC";
63+
private static final ConstructingObjectParser<DateHistogramGroupConfig, Void> PARSER;
64+
static {
65+
PARSER = new ConstructingObjectParser<>(NAME, a ->
66+
new DateHistogramGroupConfig((String) a[0], (DateHistogramInterval) a[1], (DateHistogramInterval) a[2], (String) a[3]));
67+
PARSER.declareString(constructorArg(), new ParseField(FIELD));
68+
PARSER.declareField(constructorArg(), p -> new DateHistogramInterval(p.text()), new ParseField(INTERVAL), ValueType.STRING);
69+
PARSER.declareField(optionalConstructorArg(), p -> new DateHistogramInterval(p.text()), new ParseField(DELAY), ValueType.STRING);
70+
PARSER.declareString(optionalConstructorArg(), new ParseField(TIME_ZONE));
71+
}
5972

60-
private final DateHistogramInterval interval;
6173
private final String field;
62-
private final DateTimeZone timeZone;
74+
private final DateHistogramInterval interval;
6375
private final DateHistogramInterval delay;
76+
private final String timeZone;
6477

65-
static {
66-
PARSER.declareField(DateHistoGroupConfig.Builder::setInterval,
67-
p -> new DateHistogramInterval(p.text()), INTERVAL, ObjectParser.ValueType.STRING);
68-
PARSER.declareString(DateHistoGroupConfig.Builder::setField, FIELD);
69-
PARSER.declareField(DateHistoGroupConfig.Builder::setDelay,
70-
p -> new DateHistogramInterval(p.text()), DELAY, ObjectParser.ValueType.LONG);
71-
PARSER.declareField(DateHistoGroupConfig.Builder::setTimeZone, p -> {
72-
if (p.currentToken() == XContentParser.Token.VALUE_STRING) {
73-
return DateTimeZone.forID(p.text());
74-
} else {
75-
return DateTimeZone.forOffsetHours(p.intValue());
76-
}
77-
}, TIME_ZONE, ObjectParser.ValueType.LONG);
78+
/**
79+
* Create a new {@link DateHistogramGroupConfig} using the given field and interval parameters.
80+
*/
81+
public DateHistogramGroupConfig(final String field, final DateHistogramInterval interval) {
82+
this(field, interval, null, null);
7883
}
7984

80-
private DateHistoGroupConfig(DateHistogramInterval interval,
81-
String field,
82-
DateHistogramInterval delay,
83-
DateTimeZone timeZone) {
85+
/**
86+
* Create a new {@link DateHistogramGroupConfig} using the given configuration parameters.
87+
* <p>
88+
* The {@code field} and {@code interval} are required to compute the date histogram for the rolled up documents.
89+
* The {@code delay} is optional and can be set to {@code null}. It defines how long to wait before rolling up new documents.
90+
* The {@code timeZone} is optional and can be set to {@code null}. When configured, the time zone value is resolved using
91+
* ({@link DateTimeZone#forID(String)} and must match a time zone identifier provided by the Joda Time library.
92+
* </p>
93+
* @param field the name of the date field to use for the date histogram (required)
94+
* @param interval the interval to use for the date histogram (required)
95+
* @param delay the time delay (optional)
96+
* @param timeZone the id of time zone to use to calculate the date histogram (optional). When {@code null}, the UTC timezone is used.
97+
*/
98+
public DateHistogramGroupConfig(final String field,
99+
final DateHistogramInterval interval,
100+
final @Nullable DateHistogramInterval delay,
101+
final @Nullable String timeZone) {
102+
if (field == null || field.isEmpty()) {
103+
throw new IllegalArgumentException("Field must be a non-null, non-empty string");
104+
}
105+
if (interval == null) {
106+
throw new IllegalArgumentException("Interval must be non-null");
107+
}
108+
84109
this.interval = interval;
85110
this.field = field;
86111
this.delay = delay;
87-
this.timeZone = Objects.requireNonNull(timeZone);
112+
this.timeZone = (timeZone != null && timeZone.isEmpty() == false) ? timeZone : DEFAULT_TIMEZONE;
113+
114+
// validate interval
115+
createRounding(this.interval.toString(), this.timeZone);
116+
if (delay != null) {
117+
// and delay
118+
TimeValue.parseTimeValue(this.delay.toString(), DELAY);
119+
}
88120
}
89121

90-
DateHistoGroupConfig(StreamInput in) throws IOException {
122+
DateHistogramGroupConfig(final StreamInput in) throws IOException {
91123
interval = new DateHistogramInterval(in);
92124
field = in.readString();
93125
delay = in.readOptionalWriteable(DateHistogramInterval::new);
94-
timeZone = in.readTimeZone();
126+
timeZone = in.readString();
95127
}
96128

97129
@Override
98-
public void writeTo(StreamOutput out) throws IOException {
130+
public void writeTo(final StreamOutput out) throws IOException {
99131
interval.writeTo(out);
100132
out.writeString(field);
101133
out.writeOptionalWriteable(delay);
102-
out.writeTimeZone(timeZone);
134+
out.writeString(timeZone);
103135
}
104136

105137
@Override
106-
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
107-
builder.field(INTERVAL.getPreferredName(), interval.toString());
108-
builder.field(FIELD.getPreferredName(), field);
109-
if (delay != null) {
110-
builder.field(DELAY.getPreferredName(), delay.toString());
138+
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
139+
builder.startObject();
140+
{
141+
builder.field(INTERVAL, interval.toString());
142+
builder.field(FIELD, field);
143+
if (delay != null) {
144+
builder.field(DELAY, delay.toString());
145+
}
146+
builder.field(TIME_ZONE, timeZone);
111147
}
112-
builder.field(TIME_ZONE.getPreferredName(), timeZone.toString());
113-
114-
return builder;
148+
return builder.endObject();
115149
}
116150

117151
/**
@@ -138,17 +172,17 @@ public DateHistogramInterval getDelay() {
138172
/**
139173
* Get the timezone to apply
140174
*/
141-
public DateTimeZone getTimeZone() {
175+
public String getTimeZone() {
142176
return timeZone;
143177
}
144178

145179
/**
146180
* Create the rounding for this date histogram
147181
*/
148182
public Rounding createRounding() {
149-
return createRounding(interval.toString(), timeZone, "");
183+
return createRounding(interval.toString(), timeZone);
150184
}
151-
;
185+
152186
/**
153187
* This returns a set of aggregation builders which represent the configured
154188
* set of date histograms. Used by the rollup indexer to iterate over historical data
@@ -158,7 +192,7 @@ public List<CompositeValuesSourceBuilder<?>> toBuilders() {
158192
new DateHistogramValuesSourceBuilder(RollupField.formatIndexerAggName(field, DateHistogramAggregationBuilder.NAME));
159193
vsBuilder.dateHistogramInterval(interval);
160194
vsBuilder.field(field);
161-
vsBuilder.timeZone(timeZone);
195+
vsBuilder.timeZone(toDateTimeZone(timeZone));
162196
return Collections.singletonList(vsBuilder);
163197
}
164198

@@ -168,11 +202,11 @@ public List<CompositeValuesSourceBuilder<?>> toBuilders() {
168202
public Map<String, Object> toAggCap() {
169203
Map<String, Object> map = new HashMap<>(3);
170204
map.put("agg", DateHistogramAggregationBuilder.NAME);
171-
map.put(INTERVAL.getPreferredName(), interval.toString());
205+
map.put(INTERVAL, interval.toString());
172206
if (delay != null) {
173-
map.put(DELAY.getPreferredName(), delay.toString());
207+
map.put(DELAY, delay.toString());
174208
}
175-
map.put(TIME_ZONE.getPreferredName(), timeZone.toString());
209+
map.put(TIME_ZONE, timeZone);
176210

177211
return map;
178212
}
@@ -204,21 +238,18 @@ public void validateMappings(Map<String, Map<String, FieldCapabilities>> fieldCa
204238
}
205239

206240
@Override
207-
public boolean equals(Object other) {
241+
public boolean equals(final Object other) {
208242
if (this == other) {
209243
return true;
210244
}
211-
212245
if (other == null || getClass() != other.getClass()) {
213246
return false;
214247
}
215-
216-
DateHistoGroupConfig that = (DateHistoGroupConfig) other;
217-
218-
return Objects.equals(this.interval, that.interval)
219-
&& Objects.equals(this.field, that.field)
220-
&& Objects.equals(this.delay, that.delay)
221-
&& Objects.equals(this.timeZone, that.timeZone);
248+
final DateHistogramGroupConfig that = (DateHistogramGroupConfig) other;
249+
return Objects.equals(interval, that.interval)
250+
&& Objects.equals(field, that.field)
251+
&& Objects.equals(delay, that.delay)
252+
&& Objects.equals(timeZone, that.timeZone);
222253
}
223254

224255
@Override
@@ -231,77 +262,28 @@ public String toString() {
231262
return Strings.toString(this, true, true);
232263
}
233264

234-
private static Rounding createRounding(String expr, DateTimeZone timeZone, String settingName) {
265+
public static DateHistogramGroupConfig fromXContent(final XContentParser parser) throws IOException {
266+
return PARSER.parse(parser, null);
267+
}
268+
269+
private static Rounding createRounding(final String expr, final String timeZone) {
235270
DateTimeUnit timeUnit = DateHistogramAggregationBuilder.DATE_FIELD_UNITS.get(expr);
236271
final Rounding.Builder rounding;
237272
if (timeUnit != null) {
238273
rounding = new Rounding.Builder(timeUnit);
239274
} else {
240-
rounding = new Rounding.Builder(TimeValue.parseTimeValue(expr, settingName));
275+
rounding = new Rounding.Builder(TimeValue.parseTimeValue(expr, "createRounding"));
241276
}
242-
rounding.timeZone(timeZone);
277+
rounding.timeZone(toDateTimeZone(timeZone));
243278
return rounding.build();
244279
}
245280

246-
public static class Builder {
247-
private DateHistogramInterval interval;
248-
private String field;
249-
private DateHistogramInterval delay;
250-
private DateTimeZone timeZone;
251-
252-
public DateHistogramInterval getInterval() {
253-
return interval;
254-
}
255-
256-
public DateHistoGroupConfig.Builder setInterval(DateHistogramInterval interval) {
257-
this.interval = interval;
258-
return this;
259-
}
260-
261-
public String getField() {
262-
return field;
263-
}
264-
265-
public DateHistoGroupConfig.Builder setField(String field) {
266-
this.field = field;
267-
return this;
268-
}
269-
270-
public DateTimeZone getTimeZone() {
271-
return timeZone;
272-
}
273-
274-
public DateHistoGroupConfig.Builder setTimeZone(DateTimeZone timeZone) {
275-
this.timeZone = timeZone;
276-
return this;
277-
}
278-
279-
public DateHistogramInterval getDelay() {
280-
return delay;
281-
}
282-
283-
public DateHistoGroupConfig.Builder setDelay(DateHistogramInterval delay) {
284-
this.delay = delay;
285-
return this;
286-
}
287-
288-
public DateHistoGroupConfig build() {
289-
if (field == null || field.isEmpty()) {
290-
throw new IllegalArgumentException("Parameter [" + FIELD.getPreferredName() + "] is mandatory.");
291-
}
292-
if (timeZone == null) {
293-
timeZone = DateTimeZone.UTC;
294-
}
295-
if (interval == null) {
296-
throw new IllegalArgumentException("Parameter [" + INTERVAL.getPreferredName() + "] is mandatory.");
297-
}
298-
// validate interval
299-
createRounding(interval.toString(), timeZone, INTERVAL.getPreferredName());
300-
if (delay != null) {
301-
// and delay
302-
TimeValue.parseTimeValue(delay.toString(), INTERVAL.getPreferredName());
303-
}
304-
return new DateHistoGroupConfig(interval, field, delay, timeZone);
281+
private static DateTimeZone toDateTimeZone(final String timezone) {
282+
try {
283+
return DateTimeZone.forOffsetHours(Integer.parseInt(timezone));
284+
} catch (NumberFormatException e) {
285+
return DateTimeZone.forID(timezone);
305286
}
306287
}
288+
307289
}

0 commit comments

Comments
 (0)