3131import org .elasticsearch .common .ParsingException ;
3232import org .elasticsearch .common .geo .GeoHashUtils ;
3333import org .elasticsearch .common .geo .GeoPoint ;
34+ import org .elasticsearch .common .geo .GeoShapeType ;
3435import org .elasticsearch .common .geo .GeoUtils ;
36+ import org .elasticsearch .common .geo .builders .EnvelopeBuilder ;
37+ import org .elasticsearch .common .geo .parsers .GeoWKTParser ;
3538import org .elasticsearch .common .io .stream .StreamInput ;
3639import org .elasticsearch .common .io .stream .StreamOutput ;
3740import org .elasticsearch .common .xcontent .XContentBuilder ;
@@ -62,7 +65,6 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding
6265
6366 private static final ParseField TYPE_FIELD = new ParseField ("type" );
6467 private static final ParseField VALIDATION_METHOD_FIELD = new ParseField ("validation_method" );
65- private static final ParseField FIELD_FIELD = new ParseField ("field" );
6668 private static final ParseField TOP_FIELD = new ParseField ("top" );
6769 private static final ParseField BOTTOM_FIELD = new ParseField ("bottom" );
6870 private static final ParseField LEFT_FIELD = new ParseField ("left" );
@@ -72,6 +74,8 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding
7274 private static final ParseField TOP_RIGHT_FIELD = new ParseField ("top_right" );
7375 private static final ParseField BOTTOM_LEFT_FIELD = new ParseField ("bottom_left" );
7476 private static final ParseField IGNORE_UNMAPPED_FIELD = new ParseField ("ignore_unmapped" );
77+ private static final ParseField WKT_FIELD = new ParseField ("wkt" );
78+
7579
7680 /** Name of field holding geo coordinates to compute the bounding box on.*/
7781 private final String fieldName ;
@@ -378,68 +382,25 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
378382 public static GeoBoundingBoxQueryBuilder fromXContent (XContentParser parser ) throws IOException {
379383 String fieldName = null ;
380384
381- double top = Double .NaN ;
382- double bottom = Double .NaN ;
383- double left = Double .NaN ;
384- double right = Double .NaN ;
385-
386385 float boost = AbstractQueryBuilder .DEFAULT_BOOST ;
387386 String queryName = null ;
388387 String currentFieldName = null ;
389388 XContentParser .Token token ;
390389 GeoValidationMethod validationMethod = null ;
391390 boolean ignoreUnmapped = DEFAULT_IGNORE_UNMAPPED ;
392391
393- GeoPoint sparse = new GeoPoint ();
394-
392+ Rectangle bbox = null ;
395393 String type = "memory" ;
396394
397395 while ((token = parser .nextToken ()) != XContentParser .Token .END_OBJECT ) {
398396 if (token == XContentParser .Token .FIELD_NAME ) {
399397 currentFieldName = parser .currentName ();
400398 } else if (token == XContentParser .Token .START_OBJECT ) {
401- fieldName = currentFieldName ;
402-
403- while ((token = parser .nextToken ()) != XContentParser .Token .END_OBJECT ) {
404- if (token == XContentParser .Token .FIELD_NAME ) {
405- currentFieldName = parser .currentName ();
406- token = parser .nextToken ();
407- if (FIELD_FIELD .match (currentFieldName )) {
408- fieldName = parser .text ();
409- } else if (TOP_FIELD .match (currentFieldName )) {
410- top = parser .doubleValue ();
411- } else if (BOTTOM_FIELD .match (currentFieldName )) {
412- bottom = parser .doubleValue ();
413- } else if (LEFT_FIELD .match (currentFieldName )) {
414- left = parser .doubleValue ();
415- } else if (RIGHT_FIELD .match (currentFieldName )) {
416- right = parser .doubleValue ();
417- } else {
418- if (TOP_LEFT_FIELD .match (currentFieldName )) {
419- GeoUtils .parseGeoPoint (parser , sparse );
420- top = sparse .getLat ();
421- left = sparse .getLon ();
422- } else if (BOTTOM_RIGHT_FIELD .match (currentFieldName )) {
423- GeoUtils .parseGeoPoint (parser , sparse );
424- bottom = sparse .getLat ();
425- right = sparse .getLon ();
426- } else if (TOP_RIGHT_FIELD .match (currentFieldName )) {
427- GeoUtils .parseGeoPoint (parser , sparse );
428- top = sparse .getLat ();
429- right = sparse .getLon ();
430- } else if (BOTTOM_LEFT_FIELD .match (currentFieldName )) {
431- GeoUtils .parseGeoPoint (parser , sparse );
432- bottom = sparse .getLat ();
433- left = sparse .getLon ();
434- } else {
435- throw new ElasticsearchParseException ("failed to parse [{}] query. unexpected field [{}]" ,
436- NAME , currentFieldName );
437- }
438- }
439- } else {
440- throw new ElasticsearchParseException ("failed to parse [{}] query. field name expected but [{}] found" ,
441- NAME , token );
442- }
399+ try {
400+ bbox = parseBoundingBox (parser );
401+ fieldName = currentFieldName ;
402+ } catch (Exception e ) {
403+ throw new ElasticsearchParseException ("failed to parse [{}] query. [{}]" , NAME , e .getMessage ());
443404 }
444405 } else if (token .isValue ()) {
445406 if (AbstractQueryBuilder .NAME_FIELD .match (currentFieldName )) {
@@ -459,8 +420,13 @@ public static GeoBoundingBoxQueryBuilder fromXContent(XContentParser parser) thr
459420 }
460421 }
461422
462- final GeoPoint topLeft = sparse .reset (top , left ); //just keep the object
463- final GeoPoint bottomRight = new GeoPoint (bottom , right );
423+ if (bbox == null ) {
424+ throw new ElasticsearchParseException ("failed to parse [{}] query. bounding box not provided" , NAME );
425+ }
426+
427+ final GeoPoint topLeft = new GeoPoint (bbox .maxLat , bbox .minLon ); //just keep the object
428+ final GeoPoint bottomRight = new GeoPoint (bbox .minLat , bbox .maxLon );
429+
464430 GeoBoundingBoxQueryBuilder builder = new GeoBoundingBoxQueryBuilder (fieldName );
465431 builder .setCorners (topLeft , bottomRight );
466432 builder .queryName (queryName );
@@ -493,4 +459,69 @@ protected int doHashCode() {
493459 public String getWriteableName () {
494460 return NAME ;
495461 }
462+
463+ public static Rectangle parseBoundingBox (XContentParser parser ) throws IOException , ElasticsearchParseException {
464+ XContentParser .Token token = parser .currentToken ();
465+ if (token != XContentParser .Token .START_OBJECT ) {
466+ throw new ElasticsearchParseException ("failed to parse bounding box. Expected start object but found [{}]" , token );
467+ }
468+
469+ double top = Double .NaN ;
470+ double bottom = Double .NaN ;
471+ double left = Double .NaN ;
472+ double right = Double .NaN ;
473+
474+ String currentFieldName ;
475+ GeoPoint sparse = new GeoPoint ();
476+ EnvelopeBuilder envelope = null ;
477+
478+ while ((token = parser .nextToken ()) != XContentParser .Token .END_OBJECT ) {
479+ if (token == XContentParser .Token .FIELD_NAME ) {
480+ currentFieldName = parser .currentName ();
481+ token = parser .nextToken ();
482+ if (WKT_FIELD .match (currentFieldName )) {
483+ envelope = (EnvelopeBuilder )(GeoWKTParser .parseExpectedType (parser , GeoShapeType .ENVELOPE ));
484+ } else if (TOP_FIELD .match (currentFieldName )) {
485+ top = parser .doubleValue ();
486+ } else if (BOTTOM_FIELD .match (currentFieldName )) {
487+ bottom = parser .doubleValue ();
488+ } else if (LEFT_FIELD .match (currentFieldName )) {
489+ left = parser .doubleValue ();
490+ } else if (RIGHT_FIELD .match (currentFieldName )) {
491+ right = parser .doubleValue ();
492+ } else {
493+ if (TOP_LEFT_FIELD .match (currentFieldName )) {
494+ GeoUtils .parseGeoPoint (parser , sparse );
495+ top = sparse .getLat ();
496+ left = sparse .getLon ();
497+ } else if (BOTTOM_RIGHT_FIELD .match (currentFieldName )) {
498+ GeoUtils .parseGeoPoint (parser , sparse );
499+ bottom = sparse .getLat ();
500+ right = sparse .getLon ();
501+ } else if (TOP_RIGHT_FIELD .match (currentFieldName )) {
502+ GeoUtils .parseGeoPoint (parser , sparse );
503+ top = sparse .getLat ();
504+ right = sparse .getLon ();
505+ } else if (BOTTOM_LEFT_FIELD .match (currentFieldName )) {
506+ GeoUtils .parseGeoPoint (parser , sparse );
507+ bottom = sparse .getLat ();
508+ left = sparse .getLon ();
509+ } else {
510+ throw new ElasticsearchParseException ("failed to parse bounding box. unexpected field [{}]" , currentFieldName );
511+ }
512+ }
513+ } else {
514+ throw new ElasticsearchParseException ("failed to parse bounding box. field name expected but [{}] found" , token );
515+ }
516+ }
517+ if (envelope != null ) {
518+ if ((Double .isNaN (top ) || Double .isNaN (bottom ) || Double .isNaN (left ) || Double .isNaN (right )) == false ) {
519+ throw new ElasticsearchParseException ("failed to parse bounding box. Conflicting definition found "
520+ + "using well-known text and explicit corners." );
521+ }
522+ org .locationtech .spatial4j .shape .Rectangle r = envelope .build ();
523+ return new Rectangle (r .getMinY (), r .getMaxY (), r .getMinX (), r .getMaxX ());
524+ }
525+ return new Rectangle (bottom , top , left , right );
526+ }
496527}
0 commit comments