77
88import org .elasticsearch .action .ActionRequestValidationException ;
99import org .elasticsearch .action .fieldcaps .FieldCapabilities ;
10+ import org .elasticsearch .common .Nullable ;
1011import org .elasticsearch .common .ParseField ;
1112import org .elasticsearch .common .Strings ;
1213import org .elasticsearch .common .io .stream .StreamInput ;
1516import org .elasticsearch .common .rounding .DateTimeUnit ;
1617import org .elasticsearch .common .rounding .Rounding ;
1718import 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 ;
2021import org .elasticsearch .common .xcontent .XContentBuilder ;
2122import org .elasticsearch .common .xcontent .XContentParser ;
2223import org .elasticsearch .search .aggregations .bucket .composite .CompositeValuesSourceBuilder ;
3334import java .util .Map ;
3435import 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 *
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