search_aggs_bucket_range.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. import (
  6. "time"
  7. )
  8. // RangeAggregation is a multi-bucket value source based aggregation that
  9. // enables the user to define a set of ranges - each representing a bucket.
  10. // During the aggregation process, the values extracted from each document
  11. // will be checked against each bucket range and "bucket" the
  12. // relevant/matching document. Note that this aggregration includes the
  13. // from value and excludes the to value for each range.
  14. // See: https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-aggregations-bucket-range-aggregation.html
  15. type RangeAggregation struct {
  16. field string
  17. script *Script
  18. missing interface{}
  19. subAggregations map[string]Aggregation
  20. meta map[string]interface{}
  21. keyed *bool
  22. unmapped *bool
  23. entries []rangeAggregationEntry
  24. }
  25. type rangeAggregationEntry struct {
  26. Key string
  27. From interface{}
  28. To interface{}
  29. }
  30. func NewRangeAggregation() *RangeAggregation {
  31. return &RangeAggregation{
  32. subAggregations: make(map[string]Aggregation),
  33. entries: make([]rangeAggregationEntry, 0),
  34. }
  35. }
  36. func (a *RangeAggregation) Field(field string) *RangeAggregation {
  37. a.field = field
  38. return a
  39. }
  40. func (a *RangeAggregation) Script(script *Script) *RangeAggregation {
  41. a.script = script
  42. return a
  43. }
  44. // Missing configures the value to use when documents miss a value.
  45. func (a *RangeAggregation) Missing(missing interface{}) *RangeAggregation {
  46. a.missing = missing
  47. return a
  48. }
  49. func (a *RangeAggregation) SubAggregation(name string, subAggregation Aggregation) *RangeAggregation {
  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 *RangeAggregation) Meta(metaData map[string]interface{}) *RangeAggregation {
  55. a.meta = metaData
  56. return a
  57. }
  58. func (a *RangeAggregation) Keyed(keyed bool) *RangeAggregation {
  59. a.keyed = &keyed
  60. return a
  61. }
  62. func (a *RangeAggregation) Unmapped(unmapped bool) *RangeAggregation {
  63. a.unmapped = &unmapped
  64. return a
  65. }
  66. func (a *RangeAggregation) AddRange(from, to interface{}) *RangeAggregation {
  67. a.entries = append(a.entries, rangeAggregationEntry{From: from, To: to})
  68. return a
  69. }
  70. func (a *RangeAggregation) AddRangeWithKey(key string, from, to interface{}) *RangeAggregation {
  71. a.entries = append(a.entries, rangeAggregationEntry{Key: key, From: from, To: to})
  72. return a
  73. }
  74. func (a *RangeAggregation) AddUnboundedTo(from interface{}) *RangeAggregation {
  75. a.entries = append(a.entries, rangeAggregationEntry{From: from, To: nil})
  76. return a
  77. }
  78. func (a *RangeAggregation) AddUnboundedToWithKey(key string, from interface{}) *RangeAggregation {
  79. a.entries = append(a.entries, rangeAggregationEntry{Key: key, From: from, To: nil})
  80. return a
  81. }
  82. func (a *RangeAggregation) AddUnboundedFrom(to interface{}) *RangeAggregation {
  83. a.entries = append(a.entries, rangeAggregationEntry{From: nil, To: to})
  84. return a
  85. }
  86. func (a *RangeAggregation) AddUnboundedFromWithKey(key string, to interface{}) *RangeAggregation {
  87. a.entries = append(a.entries, rangeAggregationEntry{Key: key, From: nil, To: to})
  88. return a
  89. }
  90. func (a *RangeAggregation) Lt(to interface{}) *RangeAggregation {
  91. a.entries = append(a.entries, rangeAggregationEntry{From: nil, To: to})
  92. return a
  93. }
  94. func (a *RangeAggregation) LtWithKey(key string, to interface{}) *RangeAggregation {
  95. a.entries = append(a.entries, rangeAggregationEntry{Key: key, From: nil, To: to})
  96. return a
  97. }
  98. func (a *RangeAggregation) Between(from, to interface{}) *RangeAggregation {
  99. a.entries = append(a.entries, rangeAggregationEntry{From: from, To: to})
  100. return a
  101. }
  102. func (a *RangeAggregation) BetweenWithKey(key string, from, to interface{}) *RangeAggregation {
  103. a.entries = append(a.entries, rangeAggregationEntry{Key: key, From: from, To: to})
  104. return a
  105. }
  106. func (a *RangeAggregation) Gt(from interface{}) *RangeAggregation {
  107. a.entries = append(a.entries, rangeAggregationEntry{From: from, To: nil})
  108. return a
  109. }
  110. func (a *RangeAggregation) GtWithKey(key string, from interface{}) *RangeAggregation {
  111. a.entries = append(a.entries, rangeAggregationEntry{Key: key, From: from, To: nil})
  112. return a
  113. }
  114. func (a *RangeAggregation) Source() (interface{}, error) {
  115. // Example:
  116. // {
  117. // "aggs" : {
  118. // "price_ranges" : {
  119. // "range" : {
  120. // "field" : "price",
  121. // "ranges" : [
  122. // { "to" : 50 },
  123. // { "from" : 50, "to" : 100 },
  124. // { "from" : 100 }
  125. // ]
  126. // }
  127. // }
  128. // }
  129. // }
  130. //
  131. // This method returns only the { "range" : { ... } } part.
  132. source := make(map[string]interface{})
  133. opts := make(map[string]interface{})
  134. source["range"] = opts
  135. // ValuesSourceAggregationBuilder
  136. if a.field != "" {
  137. opts["field"] = a.field
  138. }
  139. if a.script != nil {
  140. src, err := a.script.Source()
  141. if err != nil {
  142. return nil, err
  143. }
  144. opts["script"] = src
  145. }
  146. if a.missing != nil {
  147. opts["missing"] = a.missing
  148. }
  149. if a.keyed != nil {
  150. opts["keyed"] = *a.keyed
  151. }
  152. if a.unmapped != nil {
  153. opts["unmapped"] = *a.unmapped
  154. }
  155. var ranges []interface{}
  156. for _, ent := range a.entries {
  157. r := make(map[string]interface{})
  158. if ent.Key != "" {
  159. r["key"] = ent.Key
  160. }
  161. if ent.From != nil {
  162. switch from := ent.From.(type) {
  163. case int, int16, int32, int64, float32, float64:
  164. r["from"] = from
  165. case *int, *int16, *int32, *int64, *float32, *float64:
  166. r["from"] = from
  167. case time.Time:
  168. r["from"] = from.Format(time.RFC3339)
  169. case *time.Time:
  170. r["from"] = from.Format(time.RFC3339)
  171. case string:
  172. r["from"] = from
  173. case *string:
  174. r["from"] = from
  175. }
  176. }
  177. if ent.To != nil {
  178. switch to := ent.To.(type) {
  179. case int, int16, int32, int64, float32, float64:
  180. r["to"] = to
  181. case *int, *int16, *int32, *int64, *float32, *float64:
  182. r["to"] = to
  183. case time.Time:
  184. r["to"] = to.Format(time.RFC3339)
  185. case *time.Time:
  186. r["to"] = to.Format(time.RFC3339)
  187. case string:
  188. r["to"] = to
  189. case *string:
  190. r["to"] = to
  191. }
  192. }
  193. ranges = append(ranges, r)
  194. }
  195. opts["ranges"] = ranges
  196. // AggregationBuilder (SubAggregations)
  197. if len(a.subAggregations) > 0 {
  198. aggsMap := make(map[string]interface{})
  199. source["aggregations"] = aggsMap
  200. for name, aggregate := range a.subAggregations {
  201. src, err := aggregate.Source()
  202. if err != nil {
  203. return nil, err
  204. }
  205. aggsMap[name] = src
  206. }
  207. }
  208. // Add Meta data if available
  209. if len(a.meta) > 0 {
  210. source["meta"] = a.meta
  211. }
  212. return source, nil
  213. }