github.com/opensearch-project/opensearch-go/v2@v2.3.0/opensearchapi/api.msearch.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  //
     3  // The OpenSearch Contributors require contributions made to
     4  // this file be licensed under the Apache-2.0 license or a
     5  // compatible open source license.
     6  //
     7  // Modifications Copyright OpenSearch Contributors. See
     8  // GitHub history for details.
     9  
    10  // Licensed to Elasticsearch B.V. under one or more contributor
    11  // license agreements. See the NOTICE file distributed with
    12  // this work for additional information regarding copyright
    13  // ownership. Elasticsearch B.V. licenses this file to you under
    14  // the Apache License, Version 2.0 (the "License"); you may
    15  // not use this file except in compliance with the License.
    16  // You may obtain a copy of the License at
    17  //
    18  //    http://www.apache.org/licenses/LICENSE-2.0
    19  //
    20  // Unless required by applicable law or agreed to in writing,
    21  // software distributed under the License is distributed on an
    22  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    23  // KIND, either express or implied.  See the License for the
    24  // specific language governing permissions and limitations
    25  // under the License.
    26  
    27  package opensearchapi
    28  
    29  import (
    30  	"context"
    31  	"io"
    32  	"net/http"
    33  	"strconv"
    34  	"strings"
    35  )
    36  
    37  func newMsearchFunc(t Transport) Msearch {
    38  	return func(body io.Reader, o ...func(*MsearchRequest)) (*Response, error) {
    39  		var r = MsearchRequest{Body: body}
    40  		for _, f := range o {
    41  			f(&r)
    42  		}
    43  		return r.Do(r.ctx, t)
    44  	}
    45  }
    46  
    47  // ----- API Definition -------------------------------------------------------
    48  
    49  // Msearch allows to execute several search operations in one request.
    50  //
    51  //
    52  type Msearch func(body io.Reader, o ...func(*MsearchRequest)) (*Response, error)
    53  
    54  // MsearchRequest configures the Msearch API request.
    55  //
    56  type MsearchRequest struct {
    57  	Index        []string
    58  
    59  	Body io.Reader
    60  
    61  	CcsMinimizeRoundtrips      *bool
    62  	MaxConcurrentSearches      *int
    63  	MaxConcurrentShardRequests *int
    64  	PreFilterShardSize         *int
    65  	RestTotalHitsAsInt         *bool
    66  	SearchType                 string
    67  	TypedKeys                  *bool
    68  
    69  	Pretty     bool
    70  	Human      bool
    71  	ErrorTrace bool
    72  	FilterPath []string
    73  
    74  	Header http.Header
    75  
    76  	ctx context.Context
    77  }
    78  
    79  // Do executes the request and returns response or error.
    80  //
    81  func (r MsearchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
    82  	var (
    83  		method string
    84  		path   strings.Builder
    85  		params map[string]string
    86  	)
    87  
    88  	method = "POST"
    89  
    90  	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_msearch"))
    91  	if len(r.Index) > 0 {
    92  		path.WriteString("/")
    93  		path.WriteString(strings.Join(r.Index, ","))
    94  	}
    95  	path.WriteString("/")
    96  	path.WriteString("_msearch")
    97  
    98  	params = make(map[string]string)
    99  
   100  	if r.CcsMinimizeRoundtrips != nil {
   101  		params["ccs_minimize_roundtrips"] = strconv.FormatBool(*r.CcsMinimizeRoundtrips)
   102  	}
   103  
   104  	if r.MaxConcurrentSearches != nil {
   105  		params["max_concurrent_searches"] = strconv.FormatInt(int64(*r.MaxConcurrentSearches), 10)
   106  	}
   107  
   108  	if r.MaxConcurrentShardRequests != nil {
   109  		params["max_concurrent_shard_requests"] = strconv.FormatInt(int64(*r.MaxConcurrentShardRequests), 10)
   110  	}
   111  
   112  	if r.PreFilterShardSize != nil {
   113  		params["pre_filter_shard_size"] = strconv.FormatInt(int64(*r.PreFilterShardSize), 10)
   114  	}
   115  
   116  	if r.RestTotalHitsAsInt != nil {
   117  		params["rest_total_hits_as_int"] = strconv.FormatBool(*r.RestTotalHitsAsInt)
   118  	}
   119  
   120  	if r.SearchType != "" {
   121  		params["search_type"] = r.SearchType
   122  	}
   123  
   124  	if r.TypedKeys != nil {
   125  		params["typed_keys"] = strconv.FormatBool(*r.TypedKeys)
   126  	}
   127  
   128  	if r.Pretty {
   129  		params["pretty"] = "true"
   130  	}
   131  
   132  	if r.Human {
   133  		params["human"] = "true"
   134  	}
   135  
   136  	if r.ErrorTrace {
   137  		params["error_trace"] = "true"
   138  	}
   139  
   140  	if len(r.FilterPath) > 0 {
   141  		params["filter_path"] = strings.Join(r.FilterPath, ",")
   142  	}
   143  
   144  	req, err := newRequest(method, path.String(), r.Body)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	if len(params) > 0 {
   150  		q := req.URL.Query()
   151  		for k, v := range params {
   152  			q.Set(k, v)
   153  		}
   154  		req.URL.RawQuery = q.Encode()
   155  	}
   156  
   157  	if r.Body != nil {
   158  		req.Header[headerContentType] = headerContentTypeJSON
   159  	}
   160  
   161  	if len(r.Header) > 0 {
   162  		if len(req.Header) == 0 {
   163  			req.Header = r.Header
   164  		} else {
   165  			for k, vv := range r.Header {
   166  				for _, v := range vv {
   167  					req.Header.Add(k, v)
   168  				}
   169  			}
   170  		}
   171  	}
   172  
   173  	if ctx != nil {
   174  		req = req.WithContext(ctx)
   175  	}
   176  
   177  	res, err := transport.Perform(req)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  
   182  	response := Response{
   183  		StatusCode: res.StatusCode,
   184  		Body:       res.Body,
   185  		Header:     res.Header,
   186  	}
   187  
   188  	return &response, nil
   189  }
   190  
   191  // WithContext sets the request context.
   192  //
   193  func (f Msearch) WithContext(v context.Context) func(*MsearchRequest) {
   194  	return func(r *MsearchRequest) {
   195  		r.ctx = v
   196  	}
   197  }
   198  
   199  // WithIndex - a list of index names to use as default.
   200  //
   201  func (f Msearch) WithIndex(v ...string) func(*MsearchRequest) {
   202  	return func(r *MsearchRequest) {
   203  		r.Index = v
   204  	}
   205  }
   206  
   207  // WithCcsMinimizeRoundtrips - indicates whether network round-trips should be minimized as part of cross-cluster search requests execution.
   208  //
   209  func (f Msearch) WithCcsMinimizeRoundtrips(v bool) func(*MsearchRequest) {
   210  	return func(r *MsearchRequest) {
   211  		r.CcsMinimizeRoundtrips = &v
   212  	}
   213  }
   214  
   215  // WithMaxConcurrentSearches - controls the maximum number of concurrent searches the multi search api will execute.
   216  //
   217  func (f Msearch) WithMaxConcurrentSearches(v int) func(*MsearchRequest) {
   218  	return func(r *MsearchRequest) {
   219  		r.MaxConcurrentSearches = &v
   220  	}
   221  }
   222  
   223  // WithMaxConcurrentShardRequests - the number of concurrent shard requests each sub search executes concurrently per node. this value should be used to limit the impact of the search on the cluster in order to limit the number of concurrent shard requests.
   224  //
   225  func (f Msearch) WithMaxConcurrentShardRequests(v int) func(*MsearchRequest) {
   226  	return func(r *MsearchRequest) {
   227  		r.MaxConcurrentShardRequests = &v
   228  	}
   229  }
   230  
   231  // WithPreFilterShardSize - a threshold that enforces a pre-filter roundtrip to prefilter 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 its rewrite method ie. if date filters are mandatory to match but the shard bounds and the query are disjoint..
   232  //
   233  func (f Msearch) WithPreFilterShardSize(v int) func(*MsearchRequest) {
   234  	return func(r *MsearchRequest) {
   235  		r.PreFilterShardSize = &v
   236  	}
   237  }
   238  
   239  // WithRestTotalHitsAsInt - indicates whether hits.total should be rendered as an integer or an object in the rest search response.
   240  //
   241  func (f Msearch) WithRestTotalHitsAsInt(v bool) func(*MsearchRequest) {
   242  	return func(r *MsearchRequest) {
   243  		r.RestTotalHitsAsInt = &v
   244  	}
   245  }
   246  
   247  // WithSearchType - search operation type.
   248  //
   249  func (f Msearch) WithSearchType(v string) func(*MsearchRequest) {
   250  	return func(r *MsearchRequest) {
   251  		r.SearchType = v
   252  	}
   253  }
   254  
   255  // WithTypedKeys - specify whether aggregation and suggester names should be prefixed by their respective types in the response.
   256  //
   257  func (f Msearch) WithTypedKeys(v bool) func(*MsearchRequest) {
   258  	return func(r *MsearchRequest) {
   259  		r.TypedKeys = &v
   260  	}
   261  }
   262  
   263  // WithPretty makes the response body pretty-printed.
   264  //
   265  func (f Msearch) WithPretty() func(*MsearchRequest) {
   266  	return func(r *MsearchRequest) {
   267  		r.Pretty = true
   268  	}
   269  }
   270  
   271  // WithHuman makes statistical values human-readable.
   272  //
   273  func (f Msearch) WithHuman() func(*MsearchRequest) {
   274  	return func(r *MsearchRequest) {
   275  		r.Human = true
   276  	}
   277  }
   278  
   279  // WithErrorTrace includes the stack trace for errors in the response body.
   280  //
   281  func (f Msearch) WithErrorTrace() func(*MsearchRequest) {
   282  	return func(r *MsearchRequest) {
   283  		r.ErrorTrace = true
   284  	}
   285  }
   286  
   287  // WithFilterPath filters the properties of the response body.
   288  //
   289  func (f Msearch) WithFilterPath(v ...string) func(*MsearchRequest) {
   290  	return func(r *MsearchRequest) {
   291  		r.FilterPath = v
   292  	}
   293  }
   294  
   295  // WithHeader adds the headers to the HTTP request.
   296  //
   297  func (f Msearch) WithHeader(h map[string]string) func(*MsearchRequest) {
   298  	return func(r *MsearchRequest) {
   299  		if r.Header == nil {
   300  			r.Header = make(http.Header)
   301  		}
   302  		for k, v := range h {
   303  			r.Header.Add(k, v)
   304  		}
   305  	}
   306  }
   307  
   308  // WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
   309  //
   310  func (f Msearch) WithOpaqueID(s string) func(*MsearchRequest) {
   311  	return func(r *MsearchRequest) {
   312  		if r.Header == nil {
   313  			r.Header = make(http.Header)
   314  		}
   315  		r.Header.Set("X-Opaque-Id", s)
   316  	}
   317  }