github.com/opensearch-project/opensearch-go/v2@v2.3.0/opensearchapi/api.explain.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 newExplainFunc(t Transport) Explain {
    38  	return func(index string, id string, o ...func(*ExplainRequest)) (*Response, error) {
    39  		var r = ExplainRequest{Index: index, DocumentID: id}
    40  		for _, f := range o {
    41  			f(&r)
    42  		}
    43  		return r.Do(r.ctx, t)
    44  	}
    45  }
    46  
    47  // ----- API Definition -------------------------------------------------------
    48  
    49  // Explain returns information about why a specific matches (or doesn't match) a query.
    50  //
    51  //
    52  type Explain func(index string, id string, o ...func(*ExplainRequest)) (*Response, error)
    53  
    54  // ExplainRequest configures the Explain API request.
    55  //
    56  type ExplainRequest struct {
    57  	Index      string
    58  	DocumentID string
    59  
    60  	Body io.Reader
    61  
    62  	Analyzer        string
    63  	AnalyzeWildcard *bool
    64  	DefaultOperator string
    65  	Df              string
    66  	Lenient         *bool
    67  	Preference      string
    68  	Query           string
    69  	Routing         string
    70  	Source          interface{}
    71  	SourceExcludes  []string
    72  	SourceIncludes  []string
    73  	StoredFields    []string
    74  
    75  	Pretty     bool
    76  	Human      bool
    77  	ErrorTrace bool
    78  	FilterPath []string
    79  
    80  	Header http.Header
    81  
    82  	ctx context.Context
    83  }
    84  
    85  // Do executes the request and returns response or error.
    86  //
    87  func (r ExplainRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
    88  	var (
    89  		method string
    90  		path   strings.Builder
    91  		params map[string]string
    92  	)
    93  
    94  	method = "POST"
    95  
    96  	path.Grow(1 + len(r.Index) + 1 + len(r.DocumentID) + 1 + len("_explain"))
    97  	path.WriteString("/")
    98  	path.WriteString(r.Index)
    99  	path.WriteString("/")
   100  	path.WriteString("_explain")
   101  	path.WriteString("/")
   102  	path.WriteString(r.DocumentID)
   103  
   104  	params = make(map[string]string)
   105  
   106  	if r.Analyzer != "" {
   107  		params["analyzer"] = r.Analyzer
   108  	}
   109  
   110  	if r.AnalyzeWildcard != nil {
   111  		params["analyze_wildcard"] = strconv.FormatBool(*r.AnalyzeWildcard)
   112  	}
   113  
   114  	if r.DefaultOperator != "" {
   115  		params["default_operator"] = r.DefaultOperator
   116  	}
   117  
   118  	if r.Df != "" {
   119  		params["df"] = r.Df
   120  	}
   121  
   122  	if r.Lenient != nil {
   123  		params["lenient"] = strconv.FormatBool(*r.Lenient)
   124  	}
   125  
   126  	if r.Preference != "" {
   127  		params["preference"] = r.Preference
   128  	}
   129  
   130  	if r.Query != "" {
   131  		params["q"] = r.Query
   132  	}
   133  
   134  	if r.Routing != "" {
   135  		params["routing"] = r.Routing
   136  	}
   137  
   138  	if source, ok := r.Source.(bool); ok {
   139  		params["_source"] = strconv.FormatBool(source)
   140  	} else if source, ok := r.Source.(string); ok && source != "" {
   141  		params["_source"] = source
   142  	} else if sources, ok := r.Source.([]string); ok && len(sources) > 0 {
   143  		params["_source"] = strings.Join(sources, ",")
   144  	}
   145  
   146  	if len(r.SourceExcludes) > 0 {
   147  		params["_source_excludes"] = strings.Join(r.SourceExcludes, ",")
   148  	}
   149  
   150  	if len(r.SourceIncludes) > 0 {
   151  		params["_source_includes"] = strings.Join(r.SourceIncludes, ",")
   152  	}
   153  
   154  	if len(r.StoredFields) > 0 {
   155  		params["stored_fields"] = strings.Join(r.StoredFields, ",")
   156  	}
   157  
   158  	if r.Pretty {
   159  		params["pretty"] = "true"
   160  	}
   161  
   162  	if r.Human {
   163  		params["human"] = "true"
   164  	}
   165  
   166  	if r.ErrorTrace {
   167  		params["error_trace"] = "true"
   168  	}
   169  
   170  	if len(r.FilterPath) > 0 {
   171  		params["filter_path"] = strings.Join(r.FilterPath, ",")
   172  	}
   173  
   174  	req, err := newRequest(method, path.String(), r.Body)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	if len(params) > 0 {
   180  		q := req.URL.Query()
   181  		for k, v := range params {
   182  			q.Set(k, v)
   183  		}
   184  		req.URL.RawQuery = q.Encode()
   185  	}
   186  
   187  	if r.Body != nil {
   188  		req.Header[headerContentType] = headerContentTypeJSON
   189  	}
   190  
   191  	if len(r.Header) > 0 {
   192  		if len(req.Header) == 0 {
   193  			req.Header = r.Header
   194  		} else {
   195  			for k, vv := range r.Header {
   196  				for _, v := range vv {
   197  					req.Header.Add(k, v)
   198  				}
   199  			}
   200  		}
   201  	}
   202  
   203  	if ctx != nil {
   204  		req = req.WithContext(ctx)
   205  	}
   206  
   207  	res, err := transport.Perform(req)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	response := Response{
   213  		StatusCode: res.StatusCode,
   214  		Body:       res.Body,
   215  		Header:     res.Header,
   216  	}
   217  
   218  	return &response, nil
   219  }
   220  
   221  // WithContext sets the request context.
   222  //
   223  func (f Explain) WithContext(v context.Context) func(*ExplainRequest) {
   224  	return func(r *ExplainRequest) {
   225  		r.ctx = v
   226  	}
   227  }
   228  
   229  // WithBody - The query definition using the Query DSL.
   230  //
   231  func (f Explain) WithBody(v io.Reader) func(*ExplainRequest) {
   232  	return func(r *ExplainRequest) {
   233  		r.Body = v
   234  	}
   235  }
   236  
   237  // WithAnalyzer - the analyzer for the query string query.
   238  //
   239  func (f Explain) WithAnalyzer(v string) func(*ExplainRequest) {
   240  	return func(r *ExplainRequest) {
   241  		r.Analyzer = v
   242  	}
   243  }
   244  
   245  // WithAnalyzeWildcard - specify whether wildcards and prefix queries in the query string query should be analyzed (default: false).
   246  //
   247  func (f Explain) WithAnalyzeWildcard(v bool) func(*ExplainRequest) {
   248  	return func(r *ExplainRequest) {
   249  		r.AnalyzeWildcard = &v
   250  	}
   251  }
   252  
   253  // WithDefaultOperator - the default operator for query string query (and or or).
   254  //
   255  func (f Explain) WithDefaultOperator(v string) func(*ExplainRequest) {
   256  	return func(r *ExplainRequest) {
   257  		r.DefaultOperator = v
   258  	}
   259  }
   260  
   261  // WithDf - the default field for query string query (default: _all).
   262  //
   263  func (f Explain) WithDf(v string) func(*ExplainRequest) {
   264  	return func(r *ExplainRequest) {
   265  		r.Df = v
   266  	}
   267  }
   268  
   269  // WithLenient - specify whether format-based query failures (such as providing text to a numeric field) should be ignored.
   270  //
   271  func (f Explain) WithLenient(v bool) func(*ExplainRequest) {
   272  	return func(r *ExplainRequest) {
   273  		r.Lenient = &v
   274  	}
   275  }
   276  
   277  // WithPreference - specify the node or shard the operation should be performed on (default: random).
   278  //
   279  func (f Explain) WithPreference(v string) func(*ExplainRequest) {
   280  	return func(r *ExplainRequest) {
   281  		r.Preference = v
   282  	}
   283  }
   284  
   285  // WithQuery - query in the lucene query string syntax.
   286  //
   287  func (f Explain) WithQuery(v string) func(*ExplainRequest) {
   288  	return func(r *ExplainRequest) {
   289  		r.Query = v
   290  	}
   291  }
   292  
   293  // WithRouting - specific routing value.
   294  //
   295  func (f Explain) WithRouting(v string) func(*ExplainRequest) {
   296  	return func(r *ExplainRequest) {
   297  		r.Routing = v
   298  	}
   299  }
   300  
   301  // WithSource - true or false to return the _source field or not, or a list of fields to return.
   302  //
   303  func (f Explain) WithSource(v interface{}) func(*ExplainRequest) {
   304  	return func(r *ExplainRequest) {
   305  		r.Source = v
   306  	}
   307  }
   308  
   309  // WithSourceExcludes - a list of fields to exclude from the returned _source field.
   310  //
   311  func (f Explain) WithSourceExcludes(v ...string) func(*ExplainRequest) {
   312  	return func(r *ExplainRequest) {
   313  		r.SourceExcludes = v
   314  	}
   315  }
   316  
   317  // WithSourceIncludes - a list of fields to extract and return from the _source field.
   318  //
   319  func (f Explain) WithSourceIncludes(v ...string) func(*ExplainRequest) {
   320  	return func(r *ExplainRequest) {
   321  		r.SourceIncludes = v
   322  	}
   323  }
   324  
   325  // WithStoredFields - a list of stored fields to return in the response.
   326  //
   327  func (f Explain) WithStoredFields(v ...string) func(*ExplainRequest) {
   328  	return func(r *ExplainRequest) {
   329  		r.StoredFields = v
   330  	}
   331  }
   332  
   333  // WithPretty makes the response body pretty-printed.
   334  //
   335  func (f Explain) WithPretty() func(*ExplainRequest) {
   336  	return func(r *ExplainRequest) {
   337  		r.Pretty = true
   338  	}
   339  }
   340  
   341  // WithHuman makes statistical values human-readable.
   342  //
   343  func (f Explain) WithHuman() func(*ExplainRequest) {
   344  	return func(r *ExplainRequest) {
   345  		r.Human = true
   346  	}
   347  }
   348  
   349  // WithErrorTrace includes the stack trace for errors in the response body.
   350  //
   351  func (f Explain) WithErrorTrace() func(*ExplainRequest) {
   352  	return func(r *ExplainRequest) {
   353  		r.ErrorTrace = true
   354  	}
   355  }
   356  
   357  // WithFilterPath filters the properties of the response body.
   358  //
   359  func (f Explain) WithFilterPath(v ...string) func(*ExplainRequest) {
   360  	return func(r *ExplainRequest) {
   361  		r.FilterPath = v
   362  	}
   363  }
   364  
   365  // WithHeader adds the headers to the HTTP request.
   366  //
   367  func (f Explain) WithHeader(h map[string]string) func(*ExplainRequest) {
   368  	return func(r *ExplainRequest) {
   369  		if r.Header == nil {
   370  			r.Header = make(http.Header)
   371  		}
   372  		for k, v := range h {
   373  			r.Header.Add(k, v)
   374  		}
   375  	}
   376  }
   377  
   378  // WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
   379  //
   380  func (f Explain) WithOpaqueID(s string) func(*ExplainRequest) {
   381  	return func(r *ExplainRequest) {
   382  		if r.Header == nil {
   383  			r.Header = make(http.Header)
   384  		}
   385  		r.Header.Set("X-Opaque-Id", s)
   386  	}
   387  }