1// Copyright 2012-2015 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 ( 8 "fmt" 9 "net/url" 10 "strings" 11 12 "golang.org/x/net/context" 13 14 "gopkg.in/olivere/elastic.v3/uritemplates" 15) 16 17// DeleteByQueryService deletes documents that match a query. 18// See http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/docs-delete-by-query.html. 19type DeleteByQueryService struct { 20 client *Client 21 indices []string 22 types []string 23 analyzer string 24 consistency string 25 defaultOper string 26 df string 27 ignoreUnavailable *bool 28 allowNoIndices *bool 29 expandWildcards string 30 replication string 31 routing string 32 timeout string 33 pretty bool 34 q string 35 query Query 36} 37 38// NewDeleteByQueryService creates a new DeleteByQueryService. 39// You typically use the client's DeleteByQuery to get a reference to 40// the service. 41func NewDeleteByQueryService(client *Client) *DeleteByQueryService { 42 builder := &DeleteByQueryService{ 43 client: client, 44 } 45 return builder 46} 47 48// Index sets the indices on which to perform the delete operation. 49func (s *DeleteByQueryService) Index(indices ...string) *DeleteByQueryService { 50 if s.indices == nil { 51 s.indices = make([]string, 0) 52 } 53 s.indices = append(s.indices, indices...) 54 return s 55} 56 57// Type limits the delete operation to the given types. 58func (s *DeleteByQueryService) Type(types ...string) *DeleteByQueryService { 59 if s.types == nil { 60 s.types = make([]string, 0) 61 } 62 s.types = append(s.types, types...) 63 return s 64} 65 66// Analyzer to use for the query string. 67func (s *DeleteByQueryService) Analyzer(analyzer string) *DeleteByQueryService { 68 s.analyzer = analyzer 69 return s 70} 71 72// Consistency represents the specific write consistency setting for the operation. 73// It can be one, quorum, or all. 74func (s *DeleteByQueryService) Consistency(consistency string) *DeleteByQueryService { 75 s.consistency = consistency 76 return s 77} 78 79// DefaultOperator for query string query (AND or OR). 80func (s *DeleteByQueryService) DefaultOperator(defaultOperator string) *DeleteByQueryService { 81 s.defaultOper = defaultOperator 82 return s 83} 84 85// DF is the field to use as default where no field prefix is given in the query string. 86func (s *DeleteByQueryService) DF(defaultField string) *DeleteByQueryService { 87 s.df = defaultField 88 return s 89} 90 91// DefaultField is the field to use as default where no field prefix is given in the query string. 92// It is an alias to the DF func. 93func (s *DeleteByQueryService) DefaultField(defaultField string) *DeleteByQueryService { 94 s.df = defaultField 95 return s 96} 97 98// IgnoreUnavailable indicates whether specified concrete indices should be 99// ignored when unavailable (missing or closed). 100func (s *DeleteByQueryService) IgnoreUnavailable(ignore bool) *DeleteByQueryService { 101 s.ignoreUnavailable = &ignore 102 return s 103} 104 105// AllowNoIndices indicates whether to ignore if a wildcard indices 106// expression resolves into no concrete indices (including the _all string 107// or when no indices have been specified). 108func (s *DeleteByQueryService) AllowNoIndices(allow bool) *DeleteByQueryService { 109 s.allowNoIndices = &allow 110 return s 111} 112 113// ExpandWildcards indicates whether to expand wildcard expression to 114// concrete indices that are open, closed or both. It can be "open" or "closed". 115func (s *DeleteByQueryService) ExpandWildcards(expand string) *DeleteByQueryService { 116 s.expandWildcards = expand 117 return s 118} 119 120// Replication sets a specific replication type (sync or async). 121func (s *DeleteByQueryService) Replication(replication string) *DeleteByQueryService { 122 s.replication = replication 123 return s 124} 125 126// Q specifies the query in Lucene query string syntax. You can also use 127// Query to programmatically specify the query. 128func (s *DeleteByQueryService) Q(query string) *DeleteByQueryService { 129 s.q = query 130 return s 131} 132 133// QueryString is an alias to Q. Notice that you can also use Query to 134// programmatically set the query. 135func (s *DeleteByQueryService) QueryString(query string) *DeleteByQueryService { 136 s.q = query 137 return s 138} 139 140// Routing sets a specific routing value. 141func (s *DeleteByQueryService) Routing(routing string) *DeleteByQueryService { 142 s.routing = routing 143 return s 144} 145 146// Timeout sets an explicit operation timeout, e.g. "1s" or "10000ms". 147func (s *DeleteByQueryService) Timeout(timeout string) *DeleteByQueryService { 148 s.timeout = timeout 149 return s 150} 151 152// Pretty indents the JSON output from Elasticsearch. 153func (s *DeleteByQueryService) Pretty(pretty bool) *DeleteByQueryService { 154 s.pretty = pretty 155 return s 156} 157 158// Query sets the query programmatically. 159func (s *DeleteByQueryService) Query(query Query) *DeleteByQueryService { 160 s.query = query 161 return s 162} 163 164// Do executes the delete-by-query operation. 165func (s *DeleteByQueryService) Do() (*DeleteByQueryResult, error) { 166 return s.DoC(nil) 167} 168 169// DoC executes the delete-by-query operation. 170func (s *DeleteByQueryService) DoC(ctx context.Context) (*DeleteByQueryResult, error) { 171 var err error 172 173 // Build url 174 path := "/" 175 176 // Indices part 177 var indexPart []string 178 for _, index := range s.indices { 179 index, err = uritemplates.Expand("{index}", map[string]string{ 180 "index": index, 181 }) 182 if err != nil { 183 return nil, err 184 } 185 indexPart = append(indexPart, index) 186 } 187 if len(indexPart) > 0 { 188 path += strings.Join(indexPart, ",") 189 } 190 191 // Types part 192 var typesPart []string 193 for _, typ := range s.types { 194 typ, err = uritemplates.Expand("{type}", map[string]string{ 195 "type": typ, 196 }) 197 if err != nil { 198 return nil, err 199 } 200 typesPart = append(typesPart, typ) 201 } 202 if len(typesPart) > 0 { 203 path += "/" + strings.Join(typesPart, ",") 204 } 205 206 // Search 207 path += "/_query" 208 209 // Parameters 210 params := make(url.Values) 211 if s.analyzer != "" { 212 params.Set("analyzer", s.analyzer) 213 } 214 if s.consistency != "" { 215 params.Set("consistency", s.consistency) 216 } 217 if s.defaultOper != "" { 218 params.Set("default_operator", s.defaultOper) 219 } 220 if s.df != "" { 221 params.Set("df", s.df) 222 } 223 if s.ignoreUnavailable != nil { 224 params.Set("ignore_unavailable", fmt.Sprintf("%v", *s.ignoreUnavailable)) 225 } 226 if s.allowNoIndices != nil { 227 params.Set("allow_no_indices", fmt.Sprintf("%v", *s.allowNoIndices)) 228 } 229 if s.expandWildcards != "" { 230 params.Set("expand_wildcards", s.expandWildcards) 231 } 232 if s.replication != "" { 233 params.Set("replication", s.replication) 234 } 235 if s.routing != "" { 236 params.Set("routing", s.routing) 237 } 238 if s.timeout != "" { 239 params.Set("timeout", s.timeout) 240 } 241 if s.pretty { 242 params.Set("pretty", fmt.Sprintf("%v", s.pretty)) 243 } 244 if s.q != "" { 245 params.Set("q", s.q) 246 } 247 248 // Set body if there is a query set 249 var body interface{} 250 if s.query != nil { 251 src, err := s.query.Source() 252 if err != nil { 253 return nil, err 254 } 255 query := make(map[string]interface{}) 256 query["query"] = src 257 body = query 258 } 259 260 // Get response 261 res, err := s.client.PerformRequestC(ctx, "DELETE", path, params, body) 262 if err != nil { 263 return nil, err 264 } 265 266 // Return result 267 ret := new(DeleteByQueryResult) 268 if err := s.client.decoder.Decode(res.Body, ret); err != nil { 269 return nil, err 270 } 271 return ret, nil 272} 273 274// DeleteByQueryResult is the outcome of executing Do with DeleteByQueryService. 275type DeleteByQueryResult struct { 276 Took int64 `json:"took"` 277 TimedOut bool `json:"timed_out"` 278 Indices map[string]IndexDeleteByQueryResult `json:"_indices"` 279 Failures []shardOperationFailure `json:"failures"` 280} 281 282// IndexNames returns the names of the indices the DeleteByQuery touched. 283func (res DeleteByQueryResult) IndexNames() []string { 284 var indices []string 285 for index := range res.Indices { 286 indices = append(indices, index) 287 } 288 return indices 289} 290 291// All returns the index delete-by-query result of all indices. 292func (res DeleteByQueryResult) All() IndexDeleteByQueryResult { 293 all, _ := res.Indices["_all"] 294 return all 295} 296 297// IndexDeleteByQueryResult is the result of a delete-by-query for a specific 298// index. 299type IndexDeleteByQueryResult struct { 300 // Found documents, matching the query. 301 Found int `json:"found"` 302 // Deleted documents, successfully, from the given index. 303 Deleted int `json:"deleted"` 304 // Missing documents when trying to delete them. 305 Missing int `json:"missing"` 306 // Failed documents to be deleted for the given index. 307 Failed int `json:"failed"` 308} 309