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 }