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 "fmt" 8 9// A bool query matches documents matching boolean 10// combinations of other queries. 11// For more details, see: 12// https://www.elastic.co/guide/en/elasticsearch/reference/5.2/query-dsl-bool-query.html 13type BoolQuery struct { 14 Query 15 mustClauses []Query 16 mustNotClauses []Query 17 filterClauses []Query 18 shouldClauses []Query 19 boost *float64 20 disableCoord *bool 21 minimumShouldMatch string 22 adjustPureNegative *bool 23 queryName string 24} 25 26// Creates a new bool query. 27func NewBoolQuery() *BoolQuery { 28 return &BoolQuery{ 29 mustClauses: make([]Query, 0), 30 mustNotClauses: make([]Query, 0), 31 filterClauses: make([]Query, 0), 32 shouldClauses: make([]Query, 0), 33 } 34} 35 36func (q *BoolQuery) Must(queries ...Query) *BoolQuery { 37 q.mustClauses = append(q.mustClauses, queries...) 38 return q 39} 40 41func (q *BoolQuery) MustNot(queries ...Query) *BoolQuery { 42 q.mustNotClauses = append(q.mustNotClauses, queries...) 43 return q 44} 45 46func (q *BoolQuery) Filter(filters ...Query) *BoolQuery { 47 q.filterClauses = append(q.filterClauses, filters...) 48 return q 49} 50 51func (q *BoolQuery) Should(queries ...Query) *BoolQuery { 52 q.shouldClauses = append(q.shouldClauses, queries...) 53 return q 54} 55 56func (q *BoolQuery) Boost(boost float64) *BoolQuery { 57 q.boost = &boost 58 return q 59} 60 61func (q *BoolQuery) DisableCoord(disableCoord bool) *BoolQuery { 62 q.disableCoord = &disableCoord 63 return q 64} 65 66func (q *BoolQuery) MinimumShouldMatch(minimumShouldMatch string) *BoolQuery { 67 q.minimumShouldMatch = minimumShouldMatch 68 return q 69} 70 71func (q *BoolQuery) MinimumNumberShouldMatch(minimumNumberShouldMatch int) *BoolQuery { 72 q.minimumShouldMatch = fmt.Sprintf("%d", minimumNumberShouldMatch) 73 return q 74} 75 76func (q *BoolQuery) AdjustPureNegative(adjustPureNegative bool) *BoolQuery { 77 q.adjustPureNegative = &adjustPureNegative 78 return q 79} 80 81func (q *BoolQuery) QueryName(queryName string) *BoolQuery { 82 q.queryName = queryName 83 return q 84} 85 86// Creates the query source for the bool query. 87func (q *BoolQuery) Source() (interface{}, error) { 88 // { 89 // "bool" : { 90 // "must" : { 91 // "term" : { "user" : "kimchy" } 92 // }, 93 // "must_not" : { 94 // "range" : { 95 // "age" : { "from" : 10, "to" : 20 } 96 // } 97 // }, 98 // "filter" : [ 99 // ... 100 // ] 101 // "should" : [ 102 // { 103 // "term" : { "tag" : "wow" } 104 // }, 105 // { 106 // "term" : { "tag" : "elasticsearch" } 107 // } 108 // ], 109 // "minimum_number_should_match" : 1, 110 // "boost" : 1.0 111 // } 112 // } 113 114 query := make(map[string]interface{}) 115 116 boolClause := make(map[string]interface{}) 117 query["bool"] = boolClause 118 119 // must 120 if len(q.mustClauses) == 1 { 121 src, err := q.mustClauses[0].Source() 122 if err != nil { 123 return nil, err 124 } 125 boolClause["must"] = src 126 } else if len(q.mustClauses) > 1 { 127 var clauses []interface{} 128 for _, subQuery := range q.mustClauses { 129 src, err := subQuery.Source() 130 if err != nil { 131 return nil, err 132 } 133 clauses = append(clauses, src) 134 } 135 boolClause["must"] = clauses 136 } 137 138 // must_not 139 if len(q.mustNotClauses) == 1 { 140 src, err := q.mustNotClauses[0].Source() 141 if err != nil { 142 return nil, err 143 } 144 boolClause["must_not"] = src 145 } else if len(q.mustNotClauses) > 1 { 146 var clauses []interface{} 147 for _, subQuery := range q.mustNotClauses { 148 src, err := subQuery.Source() 149 if err != nil { 150 return nil, err 151 } 152 clauses = append(clauses, src) 153 } 154 boolClause["must_not"] = clauses 155 } 156 157 // filter 158 if len(q.filterClauses) == 1 { 159 src, err := q.filterClauses[0].Source() 160 if err != nil { 161 return nil, err 162 } 163 boolClause["filter"] = src 164 } else if len(q.filterClauses) > 1 { 165 var clauses []interface{} 166 for _, subQuery := range q.filterClauses { 167 src, err := subQuery.Source() 168 if err != nil { 169 return nil, err 170 } 171 clauses = append(clauses, src) 172 } 173 boolClause["filter"] = clauses 174 } 175 176 // should 177 if len(q.shouldClauses) == 1 { 178 src, err := q.shouldClauses[0].Source() 179 if err != nil { 180 return nil, err 181 } 182 boolClause["should"] = src 183 } else if len(q.shouldClauses) > 1 { 184 var clauses []interface{} 185 for _, subQuery := range q.shouldClauses { 186 src, err := subQuery.Source() 187 if err != nil { 188 return nil, err 189 } 190 clauses = append(clauses, src) 191 } 192 boolClause["should"] = clauses 193 } 194 195 if q.boost != nil { 196 boolClause["boost"] = *q.boost 197 } 198 if q.disableCoord != nil { 199 boolClause["disable_coord"] = *q.disableCoord 200 } 201 if q.minimumShouldMatch != "" { 202 boolClause["minimum_should_match"] = q.minimumShouldMatch 203 } 204 if q.adjustPureNegative != nil { 205 boolClause["adjust_pure_negative"] = *q.adjustPureNegative 206 } 207 if q.queryName != "" { 208 boolClause["_name"] = q.queryName 209 } 210 211 return query, nil 212} 213