-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-
394
-
395
-
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
-
423
-
424
-
425
-
426
-
427
-
428
-
429
-
430
-
431
-
432
-
433
-
434
-
435
-
436
-
437
-
438
-
439
-
440
-
441
-
442
-
443
-
444
-
445
-
446
-
447
-
448
-
449
-
450
-
451
-
452
-
453
-
454
-
455
-
456
-
457
-
458
-
459
-
460
-
461
-
462
-
463
-
464
-
465
-
466
-
467
-
468
-
469
-
470
-
471
-
472
-
473
-
474
-
475
-
476
-
477
-
478
-
479
-
480
-
481
-
482
-
483
-
484
-
485
-
486
-
487
-
488
-
489
-
490
-
491
-
492
-
493
-
494
-
495
-
496
-
497
-
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
-
506
-
507
-
508
-
509
-
510
-
511
-
512
-
513
-
514
-
515
-
516
-
517
-
518
-
519
-
520
-
521
-
522
-
523
-
524
-
525
-
526
-
527
-
528
-
529
-
530
-
531
-
532
-
533
-
534
-
535
-
536
-
537
-
538
-
539
-
540
-
541
-
542
-
543
-
544
-
545
-
546
-
547
-
548
-
549
-
550
-
551
-
552
-
553
-
554
-
555
-
556
-
557
-
558
-
559
-
560
-
561
-
562
-
563
-
564
-
565
-
566
-
567
-
568
-
569
-
570
-
571
-
572
-
573
-
574
-
575
-
576
-
577
-
578
-
579
-
580
-
581
-
582
-
583
-
584
-
585
-
586
-
587
-
588
-
589
-
590
-
591
-
592
-
593
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package elastic
import (
"encoding/json"
"strings"
)
// SearchRequest combines a search request and its
// query details (see SearchSource).
// It is used in combination with MultiSearch.
type SearchRequest struct {
searchType string
indices []string
types []string
routing *string
preference *string
requestCache *bool
allowPartialSearchResults *bool
ignoreUnavailable *bool
allowNoIndices *bool
expandWildcards string
scroll string
source interface{}
searchSource *SearchSource
batchedReduceSize *int
maxConcurrentShardRequests *int
preFilterShardSize *int
}
// NewSearchRequest creates a new search request.
func NewSearchRequest() *SearchRequest {
return &SearchRequest{
searchSource: NewSearchSource(),
}
}
// SearchType must be one of "dfs_query_then_fetch", "dfs_query_and_fetch",
// "query_then_fetch", or "query_and_fetch".
func (r *SearchRequest) SearchType(searchType string) *SearchRequest {
r.searchType = searchType
return r
}
// SearchTypeDfsQueryThenFetch sets search type to "dfs_query_then_fetch".
func (r *SearchRequest) SearchTypeDfsQueryThenFetch() *SearchRequest {
return r.SearchType("dfs_query_then_fetch")
}
// SearchTypeQueryThenFetch sets search type to "query_then_fetch".
func (r *SearchRequest) SearchTypeQueryThenFetch() *SearchRequest {
return r.SearchType("query_then_fetch")
}
// Index specifies the indices to use in the request.
func (r *SearchRequest) Index(indices ...string) *SearchRequest {
r.indices = append(r.indices, indices...)
return r
}
// HasIndices returns true if there are indices used, false otherwise.
func (r *SearchRequest) HasIndices() bool {
return len(r.indices) > 0
}
// Type specifies one or more types to be used.
//
// Deprecated: Types are in the process of being removed. Instead of using a type, prefer to
// filter on a field on the document.
func (r *SearchRequest) Type(types ...string) *SearchRequest {
r.types = append(r.types, types...)
return r
}
// Routing specifies the routing parameter. It is a comma-separated list.
func (r *SearchRequest) Routing(routing string) *SearchRequest {
r.routing = &routing
return r
}
// Routings to be used in the request.
func (r *SearchRequest) Routings(routings ...string) *SearchRequest {
if routings != nil {
routings := strings.Join(routings, ",")
r.routing = &routings
} else {
r.routing = nil
}
return r
}
// Preference to execute the search. Defaults to randomize across shards.
// Can be set to "_local" to prefer local shards, "_primary" to execute
// only on primary shards, or a custom value, which guarantees that the
// same order will be used across different requests.
func (r *SearchRequest) Preference(preference string) *SearchRequest {
r.preference = &preference
return r
}
// RequestCache specifies if this request should use the request cache
// or not, assuming that it can. By default, will default to the index
// level setting if request cache is enabled or not.
func (r *SearchRequest) RequestCache(requestCache bool) *SearchRequest {
r.requestCache = &requestCache
return r
}
// IgnoreUnavailable indicates whether specified concrete indices should be
// ignored when unavailable (missing or closed).
func (s *SearchRequest) IgnoreUnavailable(ignoreUnavailable bool) *SearchRequest {
s.ignoreUnavailable = &ignoreUnavailable
return s
}
// AllowNoIndices indicates whether to ignore if a wildcard indices
// expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified).
func (s *SearchRequest) AllowNoIndices(allowNoIndices bool) *SearchRequest {
s.allowNoIndices = &allowNoIndices
return s
}
// ExpandWildcards indicates whether to expand wildcard expression to
// concrete indices that are open, closed or both.
func (s *SearchRequest) ExpandWildcards(expandWildcards string) *SearchRequest {
s.expandWildcards = expandWildcards
return s
}
// Scroll, if set, will enable scrolling of the search request.
// Pass a timeout value, e.g. "2m" or "30s" as a value.
func (r *SearchRequest) Scroll(scroll string) *SearchRequest {
r.scroll = scroll
return r
}
// SearchSource allows passing your own SearchSource, overriding
// all values set on the request (except Source).
func (r *SearchRequest) SearchSource(searchSource *SearchSource) *SearchRequest {
if searchSource == nil {
r.searchSource = NewSearchSource()
return r
}
r.searchSource = searchSource
return r
}
// Source allows passing your own request body. It will have preference over
// all other properties set on the request.
func (r *SearchRequest) Source(source interface{}) *SearchRequest {
r.source = source
return r
}
// Timeout value for the request, e.g. "30s" or "2m".
func (r *SearchRequest) Timeout(timeout string) *SearchRequest {
r.searchSource = r.searchSource.Timeout(timeout)
return r
}
// TerminateAfter, when set, specifies an optional document count,
// upon collecting which the search query will terminate early.
func (r *SearchRequest) TerminateAfter(docs int) *SearchRequest {
r.searchSource = r.searchSource.TerminateAfter(docs)
return r
}
// Query for the search.
func (r *SearchRequest) Query(query Query) *SearchRequest {
r.searchSource = r.searchSource.Query(query)
return r
}
// PostFilter is a filter that will be executed after the query
// has been executed and only has affect on the search hits
// (not aggregations). This filter is always executed as last
// filtering mechanism.
func (r *SearchRequest) PostFilter(filter Query) *SearchRequest {
r.searchSource = r.searchSource.PostFilter(filter)
return r
}
// MinScore below which documents are filtered out.
func (r *SearchRequest) MinScore(minScore float64) *SearchRequest {
r.searchSource = r.searchSource.MinScore(minScore)
return r
}
// From index to start search from (default is 0).
func (r *SearchRequest) From(from int) *SearchRequest {
r.searchSource = r.searchSource.From(from)
return r
}
// Size is the number of search hits to return (default is 10).
func (r *SearchRequest) Size(size int) *SearchRequest {
r.searchSource = r.searchSource.Size(size)
return r
}
// Explain indicates whether to return an explanation for each hit.
func (r *SearchRequest) Explain(explain bool) *SearchRequest {
r.searchSource = r.searchSource.Explain(explain)
return r
}
// Version indicates whether each hit should be returned with
// its version.
func (r *SearchRequest) Version(version bool) *SearchRequest {
r.searchSource = r.searchSource.Version(version)
return r
}
// IndexBoost sets a boost a specific index will receive when
// the query is executed against it.
func (r *SearchRequest) IndexBoost(index string, boost float64) *SearchRequest {
r.searchSource = r.searchSource.IndexBoost(index, boost)
return r
}
// Stats groups that this request will be aggregated under.
func (r *SearchRequest) Stats(statsGroup ...string) *SearchRequest {
r.searchSource = r.searchSource.Stats(statsGroup...)
return r
}
// FetchSource indicates whether the response should contain the stored
// _source for every hit.
func (r *SearchRequest) FetchSource(fetchSource bool) *SearchRequest {
r.searchSource = r.searchSource.FetchSource(fetchSource)
return r
}
// FetchSourceIncludeExclude specifies that _source should be returned
// with each hit, where "include" and "exclude" serve as a simple wildcard
// matcher that gets applied to its fields
// (e.g. include := []string{"obj1.*","obj2.*"}, exclude := []string{"description.*"}).
func (r *SearchRequest) FetchSourceIncludeExclude(include, exclude []string) *SearchRequest {
r.searchSource = r.searchSource.FetchSourceIncludeExclude(include, exclude)
return r
}
// FetchSourceContext indicates how the _source should be fetched.
func (r *SearchRequest) FetchSourceContext(fsc *FetchSourceContext) *SearchRequest {
r.searchSource = r.searchSource.FetchSourceContext(fsc)
return r
}
// DocValueField adds a docvalue based field to load and return.
// The field does not have to be stored, but it's recommended to use
// non analyzed or numeric fields.
func (r *SearchRequest) DocValueField(field string) *SearchRequest {
r.searchSource = r.searchSource.DocvalueField(field)
return r
}
// DocValueFieldWithFormat adds a docvalue based field to load and return.
// The field does not have to be stored, but it's recommended to use
// non analyzed or numeric fields.
func (r *SearchRequest) DocValueFieldWithFormat(field DocvalueField) *SearchRequest {
r.searchSource = r.searchSource.DocvalueFieldWithFormat(field)
return r
}
// DocValueFields adds one or more docvalue based field to load and return.
// The fields do not have to be stored, but it's recommended to use
// non analyzed or numeric fields.
func (r *SearchRequest) DocValueFields(fields ...string) *SearchRequest {
r.searchSource = r.searchSource.DocvalueFields(fields...)
return r
}
// DocValueFieldsWithFormat adds one or more docvalue based field to load and return.
// The fields do not have to be stored, but it's recommended to use
// non analyzed or numeric fields.
func (r *SearchRequest) DocValueFieldsWithFormat(fields ...DocvalueField) *SearchRequest {
r.searchSource = r.searchSource.DocvalueFieldsWithFormat(fields...)
return r
}
// StoredField adds a stored field to load and return
// (note, it must be stored) as part of the search request.
func (r *SearchRequest) StoredField(field string) *SearchRequest {
r.searchSource = r.searchSource.StoredField(field)
return r
}
// NoStoredFields indicates that no fields should be loaded,
// resulting in only id and type to be returned per field.
func (r *SearchRequest) NoStoredFields() *SearchRequest {
r.searchSource = r.searchSource.NoStoredFields()
return r
}
// StoredFields adds one or more stored field to load and return
// (note, they must be stored) as part of the search request.
func (r *SearchRequest) StoredFields(fields ...string) *SearchRequest {
r.searchSource = r.searchSource.StoredFields(fields...)
return r
}
// ScriptField adds a script based field to load and return.
// The field does not have to be stored, but it's recommended
// to use non analyzed or numeric fields.
func (r *SearchRequest) ScriptField(field *ScriptField) *SearchRequest {
r.searchSource = r.searchSource.ScriptField(field)
return r
}
// ScriptFields adds one or more script based field to load and return.
// The fields do not have to be stored, but it's recommended
// to use non analyzed or numeric fields.
func (r *SearchRequest) ScriptFields(fields ...*ScriptField) *SearchRequest {
r.searchSource = r.searchSource.ScriptFields(fields...)
return r
}
// Sort adds a sort order.
func (r *SearchRequest) Sort(field string, ascending bool) *SearchRequest {
r.searchSource = r.searchSource.Sort(field, ascending)
return r
}
// SortWithInfo adds a sort order.
func (r *SearchRequest) SortWithInfo(info SortInfo) *SearchRequest {
r.searchSource = r.searchSource.SortWithInfo(info)
return r
}
// SortBy adds a sort order.
func (r *SearchRequest) SortBy(sorter ...Sorter) *SearchRequest {
r.searchSource = r.searchSource.SortBy(sorter...)
return r
}
// SearchAfter sets the sort values that indicates which docs this
// request should "search after".
func (r *SearchRequest) SearchAfter(sortValues ...interface{}) *SearchRequest {
r.searchSource = r.searchSource.SearchAfter(sortValues...)
return r
}
// Slice allows partitioning the documents in multiple slices.
// It is e.g. used to slice a scroll operation, supported in
// Elasticsearch 5.0 or later.
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-request-scroll.html#sliced-scroll
// for details.
func (r *SearchRequest) Slice(sliceQuery Query) *SearchRequest {
r.searchSource = r.searchSource.Slice(sliceQuery)
return r
}
// TrackScores is applied when sorting and controls if scores will be
// tracked as well. Defaults to false.
func (r *SearchRequest) TrackScores(trackScores bool) *SearchRequest {
r.searchSource = r.searchSource.TrackScores(trackScores)
return r
}
// TrackTotalHits indicates if the total hit count for the query should be tracked.
// Defaults to true.
//
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-request-track-total-hits.html
// for details.
func (r *SearchRequest) TrackTotalHits(trackTotalHits interface{}) *SearchRequest {
r.searchSource = r.searchSource.TrackTotalHits(trackTotalHits)
return r
}
// Aggregation adds an aggreation to perform as part of the search.
func (r *SearchRequest) Aggregation(name string, aggregation Aggregation) *SearchRequest {
r.searchSource = r.searchSource.Aggregation(name, aggregation)
return r
}
// Highlight adds highlighting to the search.
func (r *SearchRequest) Highlight(highlight *Highlight) *SearchRequest {
r.searchSource = r.searchSource.Highlight(highlight)
return r
}
// Suggester adds a suggester to the search.
func (r *SearchRequest) Suggester(suggester Suggester) *SearchRequest {
r.searchSource = r.searchSource.Suggester(suggester)
return r
}
// Rescorer adds a rescorer to the search.
func (r *SearchRequest) Rescorer(rescore *Rescore) *SearchRequest {
r.searchSource = r.searchSource.Rescorer(rescore)
return r
}
// ClearRescorers removes all rescorers from the search.
func (r *SearchRequest) ClearRescorers() *SearchRequest {
r.searchSource = r.searchSource.ClearRescorers()
return r
}
// Profile specifies that this search source should activate the
// Profile API for queries made on it.
func (r *SearchRequest) Profile(profile bool) *SearchRequest {
r.searchSource = r.searchSource.Profile(profile)
return r
}
// Collapse adds field collapsing.
func (r *SearchRequest) Collapse(collapse *CollapseBuilder) *SearchRequest {
r.searchSource = r.searchSource.Collapse(collapse)
return r
}
// PointInTime specifies an optional PointInTime to be used in the context
// of this search.
func (s *SearchRequest) PointInTime(pointInTime *PointInTime) *SearchRequest {
s.searchSource = s.searchSource.PointInTime(pointInTime)
return s
}
// AllowPartialSearchResults indicates if this request should allow partial
// results. (If method is not called, will default to the cluster level
// setting).
func (r *SearchRequest) AllowPartialSearchResults(allow bool) *SearchRequest {
r.allowPartialSearchResults = &allow
return r
}
// BatchedReduceSize specifies the number of shard results that should be
// reduced at once on the coordinating node. This value should be used
// as a protection mechanism to reduce the memory overhead per search request
// if the potential number of shards in the request can be large.
func (r *SearchRequest) BatchedReduceSize(size int) *SearchRequest {
r.batchedReduceSize = &size
return r
}
// MaxConcurrentShardRequests sets the number of shard requests that should
// be executed concurrently. This value should be used as a protection
// mechanism to reduce the number of shard requests fired per high level
// search request. Searches that hit the entire cluster can be throttled
// with this number to reduce the cluster load. The default grows with
// the number of nodes in the cluster but is at most 256.
func (r *SearchRequest) MaxConcurrentShardRequests(size int) *SearchRequest {
r.maxConcurrentShardRequests = &size
return r
}
// PreFilterShardSize sets a threshold that enforces a pre-filter roundtrip
// to pre-filter search shards based on query rewriting if the number of
// shards the search request expands to exceeds the threshold.
// This filter roundtrip can limit the number of shards significantly if for
// instance a shard can not match any documents based on it's rewrite
// method ie. if date filters are mandatory to match but the shard
// bounds and the query are disjoint. The default is 128.
func (r *SearchRequest) PreFilterShardSize(size int) *SearchRequest {
r.preFilterShardSize = &size
return r
}
// header is used e.g. by MultiSearch to get information about the search header
// of one SearchRequest.
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-multi-search.html
func (r *SearchRequest) header() interface{} {
h := make(map[string]interface{})
if r.searchType != "" {
h["search_type"] = r.searchType
}
switch len(r.indices) {
case 0:
case 1:
h["index"] = r.indices[0]
default:
h["indices"] = r.indices
}
switch len(r.types) {
case 0:
case 1:
h["type"] = r.types[0]
default:
h["types"] = r.types
}
if r.routing != nil && *r.routing != "" {
h["routing"] = *r.routing
}
if r.preference != nil && *r.preference != "" {
h["preference"] = *r.preference
}
if r.requestCache != nil {
h["request_cache"] = *r.requestCache
}
if r.ignoreUnavailable != nil {
h["ignore_unavailable"] = *r.ignoreUnavailable
}
if r.allowNoIndices != nil {
h["allow_no_indices"] = *r.allowNoIndices
}
if r.expandWildcards != "" {
h["expand_wildcards"] = r.expandWildcards
}
if v := r.allowPartialSearchResults; v != nil {
h["allow_partial_search_results"] = *v
}
if r.scroll != "" {
h["scroll"] = r.scroll
}
return h
}
// Body allows to access the search body of the request, as generated by the DSL.
// Notice that Body is read-only. You must not change the request body.
//
// Body is used e.g. by MultiSearch to get information about the search body
// of one SearchRequest.
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-multi-search.html
func (r *SearchRequest) Body() (string, error) {
if r.source == nil {
// Default: No custom source specified
src, err := r.searchSource.Source()
if err != nil {
return "", err
}
body, err := json.Marshal(src)
if err != nil {
return "", err
}
return string(body), nil
}
switch t := r.source.(type) {
default:
body, err := json.Marshal(r.source)
if err != nil {
return "", err
}
return string(body), nil
case *SearchSource:
src, err := t.Source()
if err != nil {
return "", err
}
body, err := json.Marshal(src)
if err != nil {
return "", err
}
return string(body), nil
case json.RawMessage:
return string(t), nil
case *json.RawMessage:
return string(*t), nil
case string:
return t, nil
case *string:
if t != nil {
return *t, nil
}
return "{}", nil
}
}
// source returns the search source. It is used by Reindex.
func (r *SearchRequest) sourceAsMap() (interface{}, error) {
if r.source == nil {
// Default: No custom source specified
return r.searchSource.Source()
}
switch t := r.source.(type) {
default:
body, err := json.Marshal(r.source)
if err != nil {
return "", err
}
return RawStringQuery(body), nil
case *SearchSource:
return t.Source()
case json.RawMessage:
return RawStringQuery(string(t)), nil
case *json.RawMessage:
return RawStringQuery(string(*t)), nil
case string:
return RawStringQuery(t), nil
case *string:
if t != nil {
return RawStringQuery(*t), nil
}
return RawStringQuery("{}"), nil
}
}