search_aggs_bucket_terms.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. // TermsAggregation is a multi-bucket value source based aggregation
  6. // where buckets are dynamically built - one per unique value.
  7. // See: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
  8. type TermsAggregation struct {
  9. field string
  10. script *Script
  11. missing interface{}
  12. subAggregations map[string]Aggregation
  13. meta map[string]interface{}
  14. size *int
  15. shardSize *int
  16. requiredSize *int
  17. minDocCount *int
  18. shardMinDocCount *int
  19. valueType string
  20. includeExclude *TermsAggregationIncludeExclude
  21. executionHint string
  22. collectionMode string
  23. showTermDocCountError *bool
  24. order []TermsOrder
  25. }
  26. func NewTermsAggregation() *TermsAggregation {
  27. return &TermsAggregation{
  28. subAggregations: make(map[string]Aggregation, 0),
  29. }
  30. }
  31. func (a *TermsAggregation) Field(field string) *TermsAggregation {
  32. a.field = field
  33. return a
  34. }
  35. func (a *TermsAggregation) Script(script *Script) *TermsAggregation {
  36. a.script = script
  37. return a
  38. }
  39. // Missing configures the value to use when documents miss a value.
  40. func (a *TermsAggregation) Missing(missing interface{}) *TermsAggregation {
  41. a.missing = missing
  42. return a
  43. }
  44. func (a *TermsAggregation) SubAggregation(name string, subAggregation Aggregation) *TermsAggregation {
  45. a.subAggregations[name] = subAggregation
  46. return a
  47. }
  48. // Meta sets the meta data to be included in the aggregation response.
  49. func (a *TermsAggregation) Meta(metaData map[string]interface{}) *TermsAggregation {
  50. a.meta = metaData
  51. return a
  52. }
  53. func (a *TermsAggregation) Size(size int) *TermsAggregation {
  54. a.size = &size
  55. return a
  56. }
  57. func (a *TermsAggregation) RequiredSize(requiredSize int) *TermsAggregation {
  58. a.requiredSize = &requiredSize
  59. return a
  60. }
  61. func (a *TermsAggregation) ShardSize(shardSize int) *TermsAggregation {
  62. a.shardSize = &shardSize
  63. return a
  64. }
  65. func (a *TermsAggregation) MinDocCount(minDocCount int) *TermsAggregation {
  66. a.minDocCount = &minDocCount
  67. return a
  68. }
  69. func (a *TermsAggregation) ShardMinDocCount(shardMinDocCount int) *TermsAggregation {
  70. a.shardMinDocCount = &shardMinDocCount
  71. return a
  72. }
  73. func (a *TermsAggregation) Include(regexp string) *TermsAggregation {
  74. if a.includeExclude == nil {
  75. a.includeExclude = &TermsAggregationIncludeExclude{}
  76. }
  77. a.includeExclude.Include = regexp
  78. return a
  79. }
  80. func (a *TermsAggregation) IncludeValues(values ...interface{}) *TermsAggregation {
  81. if a.includeExclude == nil {
  82. a.includeExclude = &TermsAggregationIncludeExclude{}
  83. }
  84. a.includeExclude.IncludeValues = append(a.includeExclude.IncludeValues, values...)
  85. return a
  86. }
  87. func (a *TermsAggregation) Exclude(regexp string) *TermsAggregation {
  88. if a.includeExclude == nil {
  89. a.includeExclude = &TermsAggregationIncludeExclude{}
  90. }
  91. a.includeExclude.Exclude = regexp
  92. return a
  93. }
  94. func (a *TermsAggregation) ExcludeValues(values ...interface{}) *TermsAggregation {
  95. if a.includeExclude == nil {
  96. a.includeExclude = &TermsAggregationIncludeExclude{}
  97. }
  98. a.includeExclude.ExcludeValues = append(a.includeExclude.ExcludeValues, values...)
  99. return a
  100. }
  101. func (a *TermsAggregation) Partition(p int) *TermsAggregation {
  102. if a.includeExclude == nil {
  103. a.includeExclude = &TermsAggregationIncludeExclude{}
  104. }
  105. a.includeExclude.Partition = p
  106. return a
  107. }
  108. func (a *TermsAggregation) NumPartitions(n int) *TermsAggregation {
  109. if a.includeExclude == nil {
  110. a.includeExclude = &TermsAggregationIncludeExclude{}
  111. }
  112. a.includeExclude.NumPartitions = n
  113. return a
  114. }
  115. // ValueType can be string, long, or double.
  116. func (a *TermsAggregation) ValueType(valueType string) *TermsAggregation {
  117. a.valueType = valueType
  118. return a
  119. }
  120. func (a *TermsAggregation) Order(order string, asc bool) *TermsAggregation {
  121. a.order = append(a.order, TermsOrder{Field: order, Ascending: asc})
  122. return a
  123. }
  124. func (a *TermsAggregation) OrderByCount(asc bool) *TermsAggregation {
  125. // "order" : { "_count" : "asc" }
  126. a.order = append(a.order, TermsOrder{Field: "_count", Ascending: asc})
  127. return a
  128. }
  129. func (a *TermsAggregation) OrderByCountAsc() *TermsAggregation {
  130. return a.OrderByCount(true)
  131. }
  132. func (a *TermsAggregation) OrderByCountDesc() *TermsAggregation {
  133. return a.OrderByCount(false)
  134. }
  135. func (a *TermsAggregation) OrderByTerm(asc bool) *TermsAggregation {
  136. // "order" : { "_term" : "asc" }
  137. a.order = append(a.order, TermsOrder{Field: "_term", Ascending: asc})
  138. return a
  139. }
  140. func (a *TermsAggregation) OrderByTermAsc() *TermsAggregation {
  141. return a.OrderByTerm(true)
  142. }
  143. func (a *TermsAggregation) OrderByTermDesc() *TermsAggregation {
  144. return a.OrderByTerm(false)
  145. }
  146. // OrderByAggregation creates a bucket ordering strategy which sorts buckets
  147. // based on a single-valued calc get.
  148. func (a *TermsAggregation) OrderByAggregation(aggName string, asc bool) *TermsAggregation {
  149. // {
  150. // "aggs" : {
  151. // "genders" : {
  152. // "terms" : {
  153. // "field" : "gender",
  154. // "order" : { "avg_height" : "desc" }
  155. // },
  156. // "aggs" : {
  157. // "avg_height" : { "avg" : { "field" : "height" } }
  158. // }
  159. // }
  160. // }
  161. // }
  162. a.order = append(a.order, TermsOrder{Field: aggName, Ascending: asc})
  163. return a
  164. }
  165. // OrderByAggregationAndMetric creates a bucket ordering strategy which
  166. // sorts buckets based on a multi-valued calc get.
  167. func (a *TermsAggregation) OrderByAggregationAndMetric(aggName, metric string, asc bool) *TermsAggregation {
  168. // {
  169. // "aggs" : {
  170. // "genders" : {
  171. // "terms" : {
  172. // "field" : "gender",
  173. // "order" : { "height_stats.avg" : "desc" }
  174. // },
  175. // "aggs" : {
  176. // "height_stats" : { "stats" : { "field" : "height" } }
  177. // }
  178. // }
  179. // }
  180. // }
  181. a.order = append(a.order, TermsOrder{Field: aggName + "." + metric, Ascending: asc})
  182. return a
  183. }
  184. func (a *TermsAggregation) ExecutionHint(hint string) *TermsAggregation {
  185. a.executionHint = hint
  186. return a
  187. }
  188. // Collection mode can be depth_first or breadth_first as of 1.4.0.
  189. func (a *TermsAggregation) CollectionMode(collectionMode string) *TermsAggregation {
  190. a.collectionMode = collectionMode
  191. return a
  192. }
  193. func (a *TermsAggregation) ShowTermDocCountError(showTermDocCountError bool) *TermsAggregation {
  194. a.showTermDocCountError = &showTermDocCountError
  195. return a
  196. }
  197. func (a *TermsAggregation) Source() (interface{}, error) {
  198. // Example:
  199. // {
  200. // "aggs" : {
  201. // "genders" : {
  202. // "terms" : { "field" : "gender" }
  203. // }
  204. // }
  205. // }
  206. // This method returns only the { "terms" : { "field" : "gender" } } part.
  207. source := make(map[string]interface{})
  208. opts := make(map[string]interface{})
  209. source["terms"] = opts
  210. // ValuesSourceAggregationBuilder
  211. if a.field != "" {
  212. opts["field"] = a.field
  213. }
  214. if a.script != nil {
  215. src, err := a.script.Source()
  216. if err != nil {
  217. return nil, err
  218. }
  219. opts["script"] = src
  220. }
  221. if a.missing != nil {
  222. opts["missing"] = a.missing
  223. }
  224. // TermsBuilder
  225. if a.size != nil && *a.size >= 0 {
  226. opts["size"] = *a.size
  227. }
  228. if a.shardSize != nil && *a.shardSize >= 0 {
  229. opts["shard_size"] = *a.shardSize
  230. }
  231. if a.requiredSize != nil && *a.requiredSize >= 0 {
  232. opts["required_size"] = *a.requiredSize
  233. }
  234. if a.minDocCount != nil && *a.minDocCount >= 0 {
  235. opts["min_doc_count"] = *a.minDocCount
  236. }
  237. if a.shardMinDocCount != nil && *a.shardMinDocCount >= 0 {
  238. opts["shard_min_doc_count"] = *a.shardMinDocCount
  239. }
  240. if a.showTermDocCountError != nil {
  241. opts["show_term_doc_count_error"] = *a.showTermDocCountError
  242. }
  243. if a.collectionMode != "" {
  244. opts["collect_mode"] = a.collectionMode
  245. }
  246. if a.valueType != "" {
  247. opts["value_type"] = a.valueType
  248. }
  249. if len(a.order) > 0 {
  250. var orderSlice []interface{}
  251. for _, order := range a.order {
  252. src, err := order.Source()
  253. if err != nil {
  254. return nil, err
  255. }
  256. orderSlice = append(orderSlice, src)
  257. }
  258. opts["order"] = orderSlice
  259. }
  260. // Include/Exclude
  261. if ie := a.includeExclude; ie != nil {
  262. // Include
  263. if ie.Include != "" {
  264. opts["include"] = ie.Include
  265. } else if len(ie.IncludeValues) > 0 {
  266. opts["include"] = ie.IncludeValues
  267. } else if ie.NumPartitions > 0 {
  268. inc := make(map[string]interface{})
  269. inc["partition"] = ie.Partition
  270. inc["num_partitions"] = ie.NumPartitions
  271. opts["include"] = inc
  272. }
  273. // Exclude
  274. if ie.Exclude != "" {
  275. opts["exclude"] = ie.Exclude
  276. } else if len(ie.ExcludeValues) > 0 {
  277. opts["exclude"] = ie.ExcludeValues
  278. }
  279. }
  280. if a.executionHint != "" {
  281. opts["execution_hint"] = a.executionHint
  282. }
  283. // AggregationBuilder (SubAggregations)
  284. if len(a.subAggregations) > 0 {
  285. aggsMap := make(map[string]interface{})
  286. source["aggregations"] = aggsMap
  287. for name, aggregate := range a.subAggregations {
  288. src, err := aggregate.Source()
  289. if err != nil {
  290. return nil, err
  291. }
  292. aggsMap[name] = src
  293. }
  294. }
  295. // Add Meta data if available
  296. if len(a.meta) > 0 {
  297. source["meta"] = a.meta
  298. }
  299. return source, nil
  300. }
  301. // TermsAggregationIncludeExclude allows for include/exclude in a TermsAggregation.
  302. type TermsAggregationIncludeExclude struct {
  303. Include string
  304. Exclude string
  305. IncludeValues []interface{}
  306. ExcludeValues []interface{}
  307. Partition int
  308. NumPartitions int
  309. }
  310. // TermsOrder specifies a single order field for a terms aggregation.
  311. type TermsOrder struct {
  312. Field string
  313. Ascending bool
  314. }
  315. // Source returns serializable JSON of the TermsOrder.
  316. func (order *TermsOrder) Source() (interface{}, error) {
  317. source := make(map[string]string)
  318. if order.Ascending {
  319. source[order.Field] = "asc"
  320. } else {
  321. source[order.Field] = "desc"
  322. }
  323. return source, nil
  324. }