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 7import "errors" 8 9// FiltersAggregation defines a multi bucket aggregations where each bucket 10// is associated with a filter. Each bucket will collect all documents that 11// match its associated filter. 12// 13// Notice that the caller has to decide whether to add filters by name 14// (using FilterWithName) or unnamed filters (using Filter or Filters). One cannot 15// use both named and unnamed filters. 16// 17// For details, see 18// https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-aggregations-bucket-filters-aggregation.html 19type FiltersAggregation struct { 20 unnamedFilters []Query 21 namedFilters map[string]Query 22 subAggregations map[string]Aggregation 23 meta map[string]interface{} 24} 25 26// NewFiltersAggregation initializes a new FiltersAggregation. 27func NewFiltersAggregation() *FiltersAggregation { 28 return &FiltersAggregation{ 29 unnamedFilters: make([]Query, 0), 30 namedFilters: make(map[string]Query), 31 subAggregations: make(map[string]Aggregation), 32 } 33} 34 35// Filter adds an unnamed filter. Notice that you can 36// either use named or unnamed filters, but not both. 37func (a *FiltersAggregation) Filter(filter Query) *FiltersAggregation { 38 a.unnamedFilters = append(a.unnamedFilters, filter) 39 return a 40} 41 42// Filters adds one or more unnamed filters. Notice that you can 43// either use named or unnamed filters, but not both. 44func (a *FiltersAggregation) Filters(filters ...Query) *FiltersAggregation { 45 if len(filters) > 0 { 46 a.unnamedFilters = append(a.unnamedFilters, filters...) 47 } 48 return a 49} 50 51// FilterWithName adds a filter with a specific name. Notice that you can 52// either use named or unnamed filters, but not both. 53func (a *FiltersAggregation) FilterWithName(name string, filter Query) *FiltersAggregation { 54 a.namedFilters[name] = filter 55 return a 56} 57 58// SubAggregation adds a sub-aggregation to this aggregation. 59func (a *FiltersAggregation) SubAggregation(name string, subAggregation Aggregation) *FiltersAggregation { 60 a.subAggregations[name] = subAggregation 61 return a 62} 63 64// Meta sets the meta data to be included in the aggregation response. 65func (a *FiltersAggregation) Meta(metaData map[string]interface{}) *FiltersAggregation { 66 a.meta = metaData 67 return a 68} 69 70// Source returns the a JSON-serializable interface. 71// If the aggregation is invalid, an error is returned. This may e.g. happen 72// if you mixed named and unnamed filters. 73func (a *FiltersAggregation) Source() (interface{}, error) { 74 // Example: 75 // { 76 // "aggs" : { 77 // "messages" : { 78 // "filters" : { 79 // "filters" : { 80 // "errors" : { "term" : { "body" : "error" }}, 81 // "warnings" : { "term" : { "body" : "warning" }} 82 // } 83 // } 84 // } 85 // } 86 // } 87 // This method returns only the (outer) { "filters" : {} } part. 88 89 source := make(map[string]interface{}) 90 filters := make(map[string]interface{}) 91 source["filters"] = filters 92 93 if len(a.unnamedFilters) > 0 && len(a.namedFilters) > 0 { 94 return nil, errors.New("elastic: use either named or unnamed filters with FiltersAggregation but not both") 95 } 96 97 if len(a.unnamedFilters) > 0 { 98 arr := make([]interface{}, len(a.unnamedFilters)) 99 for i, filter := range a.unnamedFilters { 100 src, err := filter.Source() 101 if err != nil { 102 return nil, err 103 } 104 arr[i] = src 105 } 106 filters["filters"] = arr 107 } else { 108 dict := make(map[string]interface{}) 109 for key, filter := range a.namedFilters { 110 src, err := filter.Source() 111 if err != nil { 112 return nil, err 113 } 114 dict[key] = src 115 } 116 filters["filters"] = dict 117 } 118 119 // AggregationBuilder (SubAggregations) 120 if len(a.subAggregations) > 0 { 121 aggsMap := make(map[string]interface{}) 122 source["aggregations"] = aggsMap 123 for name, aggregate := range a.subAggregations { 124 src, err := aggregate.Source() 125 if err != nil { 126 return nil, err 127 } 128 aggsMap[name] = src 129 } 130 } 131 132 // Add Meta data if available 133 if len(a.meta) > 0 { 134 source["meta"] = a.meta 135 } 136 137 return source, nil 138} 139