1// Copyright 2012-present Oliver Eilhard. All rights reserved. 2// Use of this source code is governed by a MIT-license. 3// See http://olivere.mit-license.org/license.txt for details. 4 5package elastic 6 7// GeoBoundingBoxQuery allows to filter hits based on a point location using 8// a bounding box. 9// 10// For more details, see: 11// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-geo-bounding-box-query.html 12type GeoBoundingBoxQuery struct { 13 name string 14 topLeft interface{} // can be a GeoPoint, a GeoHash (string), or a lat/lon pair as float64 15 topRight interface{} 16 bottomRight interface{} // can be a GeoPoint, a GeoHash (string), or a lat/lon pair as float64 17 bottomLeft interface{} 18 wkt interface{} 19 typ string 20 validationMethod string 21 ignoreUnmapped *bool 22 queryName string 23} 24 25// NewGeoBoundingBoxQuery creates and initializes a new GeoBoundingBoxQuery. 26func NewGeoBoundingBoxQuery(name string) *GeoBoundingBoxQuery { 27 return &GeoBoundingBoxQuery{ 28 name: name, 29 } 30} 31 32// TopLeft position from longitude (left) and latitude (top). 33func (q *GeoBoundingBoxQuery) TopLeft(top, left float64) *GeoBoundingBoxQuery { 34 q.topLeft = []float64{left, top} 35 return q 36} 37 38// TopLeftFromGeoPoint from a GeoPoint. 39func (q *GeoBoundingBoxQuery) TopLeftFromGeoPoint(point *GeoPoint) *GeoBoundingBoxQuery { 40 return q.TopLeft(point.Lat, point.Lon) 41} 42 43// TopLeftFromGeoHash from a Geo hash. 44func (q *GeoBoundingBoxQuery) TopLeftFromGeoHash(topLeft string) *GeoBoundingBoxQuery { 45 q.topLeft = topLeft 46 return q 47} 48 49// BottomRight position from longitude (right) and latitude (bottom). 50func (q *GeoBoundingBoxQuery) BottomRight(bottom, right float64) *GeoBoundingBoxQuery { 51 q.bottomRight = []float64{right, bottom} 52 return q 53} 54 55// BottomRightFromGeoPoint from a GeoPoint. 56func (q *GeoBoundingBoxQuery) BottomRightFromGeoPoint(point *GeoPoint) *GeoBoundingBoxQuery { 57 return q.BottomRight(point.Lat, point.Lon) 58} 59 60// BottomRightFromGeoHash from a Geo hash. 61func (q *GeoBoundingBoxQuery) BottomRightFromGeoHash(bottomRight string) *GeoBoundingBoxQuery { 62 q.bottomRight = bottomRight 63 return q 64} 65 66// BottomLeft position from longitude (left) and latitude (bottom). 67func (q *GeoBoundingBoxQuery) BottomLeft(bottom, left float64) *GeoBoundingBoxQuery { 68 q.bottomLeft = []float64{bottom, left} 69 return q 70} 71 72// BottomLeftFromGeoPoint from a GeoPoint. 73func (q *GeoBoundingBoxQuery) BottomLeftFromGeoPoint(point *GeoPoint) *GeoBoundingBoxQuery { 74 return q.BottomLeft(point.Lat, point.Lon) 75} 76 77// BottomLeftFromGeoHash from a Geo hash. 78func (q *GeoBoundingBoxQuery) BottomLeftFromGeoHash(bottomLeft string) *GeoBoundingBoxQuery { 79 q.bottomLeft = bottomLeft 80 return q 81} 82 83// TopRight position from longitude (right) and latitude (top). 84func (q *GeoBoundingBoxQuery) TopRight(top, right float64) *GeoBoundingBoxQuery { 85 q.topRight = []float64{right, top} 86 return q 87} 88 89// TopRightFromGeoPoint from a GeoPoint. 90func (q *GeoBoundingBoxQuery) TopRightFromGeoPoint(point *GeoPoint) *GeoBoundingBoxQuery { 91 return q.TopRight(point.Lat, point.Lon) 92} 93 94// TopRightFromGeoHash from a Geo hash. 95func (q *GeoBoundingBoxQuery) TopRightFromGeoHash(topRight string) *GeoBoundingBoxQuery { 96 q.topRight = topRight 97 return q 98} 99 100// WKT initializes the bounding box from Well-Known Text (WKT), 101// e.g. "BBOX (-74.1, -71.12, 40.73, 40.01)". 102func (q *GeoBoundingBoxQuery) WKT(wkt interface{}) *GeoBoundingBoxQuery { 103 q.wkt = wkt 104 return q 105} 106 107// Type sets the type of executing the geo bounding box. It can be either 108// memory or indexed. It defaults to memory. 109func (q *GeoBoundingBoxQuery) Type(typ string) *GeoBoundingBoxQuery { 110 q.typ = typ 111 return q 112} 113 114// ValidationMethod accepts IGNORE_MALFORMED, COERCE, and STRICT (default). 115// IGNORE_MALFORMED accepts geo points with invalid lat/lon. 116// COERCE tries to infer the correct lat/lon. 117func (q *GeoBoundingBoxQuery) ValidationMethod(method string) *GeoBoundingBoxQuery { 118 q.validationMethod = method 119 return q 120} 121 122// IgnoreUnmapped indicates whether to ignore unmapped fields (and run a 123// MatchNoDocsQuery in place of this). 124func (q *GeoBoundingBoxQuery) IgnoreUnmapped(ignoreUnmapped bool) *GeoBoundingBoxQuery { 125 q.ignoreUnmapped = &ignoreUnmapped 126 return q 127} 128 129// QueryName gives the query a name. It is used for caching. 130func (q *GeoBoundingBoxQuery) QueryName(queryName string) *GeoBoundingBoxQuery { 131 q.queryName = queryName 132 return q 133} 134 135// Source returns JSON for the function score query. 136func (q *GeoBoundingBoxQuery) Source() (interface{}, error) { 137 // { 138 // "geo_bounding_box" : { 139 // ... 140 // } 141 // } 142 143 source := make(map[string]interface{}) 144 params := make(map[string]interface{}) 145 source["geo_bounding_box"] = params 146 147 box := make(map[string]interface{}) 148 if q.wkt != nil { 149 box["wkt"] = q.wkt 150 } else { 151 if q.topLeft != nil { 152 box["top_left"] = q.topLeft 153 } 154 if q.topRight != nil { 155 box["top_right"] = q.topRight 156 } 157 if q.bottomLeft != nil { 158 box["bottom_left"] = q.bottomLeft 159 } 160 if q.bottomRight != nil { 161 box["bottom_right"] = q.bottomRight 162 } 163 } 164 params[q.name] = box 165 166 if q.typ != "" { 167 params["type"] = q.typ 168 } 169 if q.validationMethod != "" { 170 params["validation_method"] = q.validationMethod 171 } 172 if q.ignoreUnmapped != nil { 173 params["ignore_unmapped"] = *q.ignoreUnmapped 174 } 175 if q.queryName != "" { 176 params["_name"] = q.queryName 177 } 178 179 return source, nil 180} 181