2525import org .elasticsearch .common .geo .GeoPoint ;
2626import org .elasticsearch .common .io .stream .StreamInput ;
2727import org .elasticsearch .common .io .stream .StreamOutput ;
28+ import org .elasticsearch .common .xcontent .ConstructingObjectParser ;
2829import org .elasticsearch .common .xcontent .ObjectParser ;
2930import org .elasticsearch .common .xcontent .XContentBuilder ;
30- import org .elasticsearch .common .xcontent .XContentLocation ;
3131import org .elasticsearch .common .xcontent .XContentParseException ;
3232import org .elasticsearch .common .xcontent .XContentParser ;
3333import org .elasticsearch .index .fielddata .AbstractSortingNumericDocValues ;
5454import java .util .stream .Collectors ;
5555import java .util .stream .Stream ;
5656
57+ import static org .elasticsearch .common .xcontent .ConstructingObjectParser .optionalConstructorArg ;
58+
5759public class GeoGridAggregationBuilder extends ValuesSourceAggregationBuilder <ValuesSource .GeoPoint , GeoGridAggregationBuilder >
58- implements MultiBucketAggregationBuilder {
60+ implements MultiBucketAggregationBuilder {
5961 public static final String NAME = "geohash_grid" ;
6062 public static final int DEFAULT_MAX_NUM_CELLS = 10000 ;
6163
62- private static final ObjectParser <GeoGridAggregationBuilder , Void > PARSER ;
64+ private static final ConstructingObjectParser <GeoGridAggregationBuilder , String > PARSER ;
65+
6366 static {
64- PARSER = new ObjectParser <>(GeoGridAggregationBuilder .NAME );
65- ValuesSourceParserHelper .declareGeoFields (PARSER , false , false );
66- PARSER .declareString (GeoGridAggregationBuilder ::type , GeoHashGridParams .FIELD_TYPE );
67- PARSER .declareField (GeoGridAggregationBuilder ::parsePrecision , GeoHashGridParams .FIELD_PRECISION , ObjectParser .ValueType .INT );
67+ PARSER = new ConstructingObjectParser <>(GeoGridAggregationBuilder .NAME , false ,
68+ (a , name ) -> new GeoGridAggregationBuilder (name , (String ) a [0 ]));
69+
70+ PARSER .declareString (optionalConstructorArg (), GeoHashGridParams .FIELD_TYPE );
71+ PARSER .declareField (
72+ GeoGridAggregationBuilder ::precisionRaw ,
73+ GeoGridAggregationBuilder ::parsePrecision ,
74+ GeoHashGridParams .FIELD_PRECISION ,
75+ ObjectParser .ValueType .VALUE );
6876 PARSER .declareInt (GeoGridAggregationBuilder ::size , GeoHashGridParams .FIELD_SIZE );
6977 PARSER .declareInt (GeoGridAggregationBuilder ::shardSize , GeoHashGridParams .FIELD_SHARD_SIZE );
78+
79+ ValuesSourceParserHelper .declareGeoFields (PARSER , false , false );
7080 }
7181
72- private static void parsePrecision (XContentParser parser , GeoGridAggregationBuilder builder , Void context )
73- throws IOException {
82+ private static Object parsePrecision (XContentParser parser , String name )
83+ throws IOException {
84+ // Delay actual parsing until builder.precision()
7485 // In some cases, this value cannot be fully parsed until after we know the type
75- // Store precision as is until the end of parsing.
76- // ValueType.INT could be either a number or a string
77- builder .precisionLocation = parser .getTokenLocation ();
78- if (parser .currentToken () == XContentParser .Token .VALUE_NUMBER ) {
79- builder .precisionRaw = parser .intValue ();
80- } else {
81- builder .precisionRaw = parser .text ();
86+ final XContentParser .Token token = parser .currentToken ();
87+ switch (token ) {
88+ case VALUE_NUMBER :
89+ return parser .intValue ();
90+ case VALUE_STRING :
91+ return parser .text ();
92+ default :
93+ throw new XContentParseException (parser .getTokenLocation (),
94+ "[geohash_grid] failed to parse field [precision] in [" + name +
95+ "]. It must be either an integer or a string" );
8296 }
8397 }
8498
85- public static GeoGridAggregationBuilder parse (String aggregationName , XContentParser parser ) throws IOException {
86- GeoGridAggregationBuilder builder = PARSER .parse (parser ,
87- new GeoGridAggregationBuilder (aggregationName ), null );
88-
89- try {
90- // delayed precision validation
91- final GeoHashTypeProvider typeHandler = builder .type .getHandler ();
92-
93- if (builder .precisionRaw == null ) {
94- builder .precision (typeHandler .getDefaultPrecision ());
95- } else if (builder .precisionRaw instanceof String ) {
96- builder .precision (typeHandler .parsePrecisionString ((String ) builder .precisionRaw ));
97- } else {
98- builder .precision ((int ) builder .precisionRaw );
99- }
100-
101- return builder ;
102- } catch (Exception e ) {
103- throw new XContentParseException (builder .precisionLocation ,
104- "[geohash_grid] failed to parse field [precision]" , e );
105- }
99+ public static GeoGridAggregationBuilder parse (String aggregationName , XContentParser parser ) {
100+ return PARSER .apply (parser , aggregationName );
106101 }
107102
108- private GeoHashType type = GeoHashType .DEFAULT ;
109-
110- /**
111- * Contains unparsed precision value during the parsing.
112- * This value will be converted into an integer precision at the end of parsing.
113- */
114- private Object precisionRaw = null ;
115-
116- /**
117- * Stores the location of the precision parameter, in case precision is
118- * incorrect and an error has to be reported to the user. Only valid during parsing.
119- */
120- private XContentLocation precisionLocation = null ;
121-
122- private int precision = GeoHashType .DEFAULT .getHandler ().getDefaultPrecision ();
123-
103+ private final GeoHashType type ;
104+ private int precision ;
124105 private int requiredSize = DEFAULT_MAX_NUM_CELLS ;
125106 private int shardSize = -1 ;
126107
127- public GeoGridAggregationBuilder (String name ) {
108+ public GeoGridAggregationBuilder (String name , String type ) {
109+ this (name , parseType (type , name ));
110+ }
111+
112+ public GeoGridAggregationBuilder (String name , GeoHashType type ) {
128113 super (name , ValuesSourceType .GEOPOINT , ValueType .GEOPOINT );
114+ this .type = type ;
115+ this .precision = type .getHandler ().getDefaultPrecision ();
129116 }
130117
131118 protected GeoGridAggregationBuilder (GeoGridAggregationBuilder clone , Builder factoriesBuilder , Map <String , Object > metaData ) {
@@ -160,9 +147,9 @@ protected void innerWriteTo(StreamOutput out) throws IOException {
160147 out .writeVInt (shardSize );
161148 }
162149
163- public GeoGridAggregationBuilder type (String type ) {
150+ private static GeoHashType parseType (String type , String name ) {
164151 try {
165- this . type = GeoHashType .forString (type );
152+ return type == null ? GeoHashType . DEFAULT : GeoHashType .forString (type );
166153 } catch (IllegalArgumentException e ) {
167154 throw new IllegalArgumentException (
168155 "[type] is not valid. Allowed values: " +
@@ -171,16 +158,25 @@ public GeoGridAggregationBuilder type(String type) {
171158 .collect (Collectors .joining (", " )) +
172159 ". Found [" + type + "] in [" + name + "]" );
173160 }
174- // Some tests bypass parsing steps, so keep the default precision consistent.
175- // Note that tests must set precision after setting the type
176- this .precision = this .type .getHandler ().getDefaultPrecision ();
177- return this ;
178161 }
179162
180163 public GeoHashType type () {
181164 return type ;
182165 }
183166
167+ private GeoGridAggregationBuilder precisionRaw (Object precision ) {
168+ final GeoHashTypeProvider typeHandler = this .type .getHandler ();
169+
170+ if (precision == null ) {
171+ this .precision (typeHandler .getDefaultPrecision ());
172+ } else if (precision instanceof String ) {
173+ this .precision (typeHandler .parsePrecisionString ((String ) precision ));
174+ } else {
175+ this .precision ((int ) precision );
176+ }
177+ return this ;
178+ }
179+
184180 public GeoGridAggregationBuilder precision (int precision ) {
185181 this .precision = type .getHandler ().validatePrecision (precision );
186182 return this ;
@@ -193,7 +189,7 @@ public int precision() {
193189 public GeoGridAggregationBuilder size (int size ) {
194190 if (size <= 0 ) {
195191 throw new IllegalArgumentException (
196- "[size] must be greater than 0. Found [" + size + "] in [" + name + "]" );
192+ "[size] must be greater than 0. Found [" + size + "] in [" + name + "]" );
197193 }
198194 this .requiredSize = size ;
199195 return this ;
@@ -206,7 +202,7 @@ public int size() {
206202 public GeoGridAggregationBuilder shardSize (int shardSize ) {
207203 if (shardSize <= 0 ) {
208204 throw new IllegalArgumentException (
209- "[shardSize] must be greater than 0. Found [" + shardSize + "] in [" + name + "]" );
205+ "[shardSize] must be greater than 0. Found [" + shardSize + "] in [" + name + "]" );
210206 }
211207 this .shardSize = shardSize ;
212208 return this ;
@@ -218,8 +214,8 @@ public int shardSize() {
218214
219215 @ Override
220216 protected ValuesSourceAggregatorFactory <ValuesSource .GeoPoint , ?> innerBuild (SearchContext context ,
221- ValuesSourceConfig <ValuesSource .GeoPoint > config , AggregatorFactory <?> parent , Builder subFactoriesBuilder )
222- throws IOException {
217+ ValuesSourceConfig <ValuesSource .GeoPoint > config , AggregatorFactory <?> parent , Builder subFactoriesBuilder )
218+ throws IOException {
223219 int shardSize = this .shardSize ;
224220
225221 int requiredSize = this .requiredSize ;
@@ -232,14 +228,14 @@ public int shardSize() {
232228
233229 if (requiredSize <= 0 || shardSize <= 0 ) {
234230 throw new ElasticsearchException (
235- "parameters [required_size] and [shard_size] must be >0 in geohash_grid aggregation [" + name + "]." );
231+ "parameters [required_size] and [shard_size] must be >0 in geohash_grid aggregation [" + name + "]." );
236232 }
237233
238234 if (shardSize < requiredSize ) {
239235 shardSize = requiredSize ;
240236 }
241237 return new GeoHashGridAggregatorFactory (name , config , type , precision , requiredSize , shardSize , context , parent ,
242- subFactoriesBuilder , metaData );
238+ subFactoriesBuilder , metaData );
243239 }
244240
245241 @ Override
0 commit comments