search_aggs_bucket_geo_distance.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. package elastic
  5. // GeoDistanceAggregation is a multi-bucket aggregation that works on geo_point fields
  6. // and conceptually works very similar to the range aggregation.
  7. // The user can define a point of origin and a set of distance range buckets.
  8. // The aggregation evaluate the distance of each document value from
  9. // the origin point and determines the buckets it belongs to based on
  10. // the ranges (a document belongs to a bucket if the distance between the
  11. // document and the origin falls within the distance range of the bucket).
  12. // See: https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-aggregations-bucket-geodistance-aggregation.html
  13. type GeoDistanceAggregation struct {
  14. field string
  15. unit string
  16. distanceType string
  17. point string
  18. ranges []geoDistAggRange
  19. subAggregations map[string]Aggregation
  20. meta map[string]interface{}
  21. }
  22. type geoDistAggRange struct {
  23. Key string
  24. From interface{}
  25. To interface{}
  26. }
  27. func NewGeoDistanceAggregation() *GeoDistanceAggregation {
  28. return &GeoDistanceAggregation{
  29. subAggregations: make(map[string]Aggregation),
  30. ranges: make([]geoDistAggRange, 0),
  31. }
  32. }
  33. func (a *GeoDistanceAggregation) Field(field string) *GeoDistanceAggregation {
  34. a.field = field
  35. return a
  36. }
  37. func (a *GeoDistanceAggregation) Unit(unit string) *GeoDistanceAggregation {
  38. a.unit = unit
  39. return a
  40. }
  41. func (a *GeoDistanceAggregation) DistanceType(distanceType string) *GeoDistanceAggregation {
  42. a.distanceType = distanceType
  43. return a
  44. }
  45. func (a *GeoDistanceAggregation) Point(latLon string) *GeoDistanceAggregation {
  46. a.point = latLon
  47. return a
  48. }
  49. func (a *GeoDistanceAggregation) SubAggregation(name string, subAggregation Aggregation) *GeoDistanceAggregation {
  50. a.subAggregations[name] = subAggregation
  51. return a
  52. }
  53. // Meta sets the meta data to be included in the aggregation response.
  54. func (a *GeoDistanceAggregation) Meta(metaData map[string]interface{}) *GeoDistanceAggregation {
  55. a.meta = metaData
  56. return a
  57. }
  58. func (a *GeoDistanceAggregation) AddRange(from, to interface{}) *GeoDistanceAggregation {
  59. a.ranges = append(a.ranges, geoDistAggRange{From: from, To: to})
  60. return a
  61. }
  62. func (a *GeoDistanceAggregation) AddRangeWithKey(key string, from, to interface{}) *GeoDistanceAggregation {
  63. a.ranges = append(a.ranges, geoDistAggRange{Key: key, From: from, To: to})
  64. return a
  65. }
  66. func (a *GeoDistanceAggregation) AddUnboundedTo(from float64) *GeoDistanceAggregation {
  67. a.ranges = append(a.ranges, geoDistAggRange{From: from, To: nil})
  68. return a
  69. }
  70. func (a *GeoDistanceAggregation) AddUnboundedToWithKey(key string, from float64) *GeoDistanceAggregation {
  71. a.ranges = append(a.ranges, geoDistAggRange{Key: key, From: from, To: nil})
  72. return a
  73. }
  74. func (a *GeoDistanceAggregation) AddUnboundedFrom(to float64) *GeoDistanceAggregation {
  75. a.ranges = append(a.ranges, geoDistAggRange{From: nil, To: to})
  76. return a
  77. }
  78. func (a *GeoDistanceAggregation) AddUnboundedFromWithKey(key string, to float64) *GeoDistanceAggregation {
  79. a.ranges = append(a.ranges, geoDistAggRange{Key: key, From: nil, To: to})
  80. return a
  81. }
  82. func (a *GeoDistanceAggregation) Between(from, to interface{}) *GeoDistanceAggregation {
  83. a.ranges = append(a.ranges, geoDistAggRange{From: from, To: to})
  84. return a
  85. }
  86. func (a *GeoDistanceAggregation) BetweenWithKey(key string, from, to interface{}) *GeoDistanceAggregation {
  87. a.ranges = append(a.ranges, geoDistAggRange{Key: key, From: from, To: to})
  88. return a
  89. }
  90. func (a *GeoDistanceAggregation) Source() (interface{}, error) {
  91. // Example:
  92. // {
  93. // "aggs" : {
  94. // "rings_around_amsterdam" : {
  95. // "geo_distance" : {
  96. // "field" : "location",
  97. // "origin" : "52.3760, 4.894",
  98. // "ranges" : [
  99. // { "to" : 100 },
  100. // { "from" : 100, "to" : 300 },
  101. // { "from" : 300 }
  102. // ]
  103. // }
  104. // }
  105. // }
  106. // }
  107. //
  108. // This method returns only the { "range" : { ... } } part.
  109. source := make(map[string]interface{})
  110. opts := make(map[string]interface{})
  111. source["geo_distance"] = opts
  112. if a.field != "" {
  113. opts["field"] = a.field
  114. }
  115. if a.unit != "" {
  116. opts["unit"] = a.unit
  117. }
  118. if a.distanceType != "" {
  119. opts["distance_type"] = a.distanceType
  120. }
  121. if a.point != "" {
  122. opts["origin"] = a.point
  123. }
  124. var ranges []interface{}
  125. for _, ent := range a.ranges {
  126. r := make(map[string]interface{})
  127. if ent.Key != "" {
  128. r["key"] = ent.Key
  129. }
  130. if ent.From != nil {
  131. switch from := ent.From.(type) {
  132. case int, int16, int32, int64, float32, float64:
  133. r["from"] = from
  134. case *int, *int16, *int32, *int64, *float32, *float64:
  135. r["from"] = from
  136. case string:
  137. r["from"] = from
  138. case *string:
  139. r["from"] = from
  140. }
  141. }
  142. if ent.To != nil {
  143. switch to := ent.To.(type) {
  144. case int, int16, int32, int64, float32, float64:
  145. r["to"] = to
  146. case *int, *int16, *int32, *int64, *float32, *float64:
  147. r["to"] = to
  148. case string:
  149. r["to"] = to
  150. case *string:
  151. r["to"] = to
  152. }
  153. }
  154. ranges = append(ranges, r)
  155. }
  156. opts["ranges"] = ranges
  157. // AggregationBuilder (SubAggregations)
  158. if len(a.subAggregations) > 0 {
  159. aggsMap := make(map[string]interface{})
  160. source["aggregations"] = aggsMap
  161. for name, aggregate := range a.subAggregations {
  162. src, err := aggregate.Source()
  163. if err != nil {
  164. return nil, err
  165. }
  166. aggsMap[name] = src
  167. }
  168. }
  169. // Add Meta data if available
  170. if len(a.meta) > 0 {
  171. source["meta"] = a.meta
  172. }
  173. return source, nil
  174. }