1// Copyright 2012-present 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	"context"
9	"encoding/json"
10	"fmt"
11	"net/url"
12	"strings"
13)
14
15// MultiSearch executes one or more searches in one roundtrip.
16type MultiSearchService struct {
17	client     *Client
18	requests   []*SearchRequest
19	indices    []string
20	pretty     bool
21	routing    string
22	preference string
23}
24
25func NewMultiSearchService(client *Client) *MultiSearchService {
26	builder := &MultiSearchService{
27		client:   client,
28		requests: make([]*SearchRequest, 0),
29		indices:  make([]string, 0),
30	}
31	return builder
32}
33
34func (s *MultiSearchService) Add(requests ...*SearchRequest) *MultiSearchService {
35	s.requests = append(s.requests, requests...)
36	return s
37}
38
39func (s *MultiSearchService) Index(indices ...string) *MultiSearchService {
40	s.indices = append(s.indices, indices...)
41	return s
42}
43
44func (s *MultiSearchService) Pretty(pretty bool) *MultiSearchService {
45	s.pretty = pretty
46	return s
47}
48
49func (s *MultiSearchService) Do(ctx context.Context) (*MultiSearchResult, error) {
50	// Build url
51	path := "/_msearch"
52
53	// Parameters
54	params := make(url.Values)
55	if s.pretty {
56		params.Set("pretty", fmt.Sprintf("%v", s.pretty))
57	}
58
59	// Set body
60	var lines []string
61	for _, sr := range s.requests {
62		// Set default indices if not specified in the request
63		if !sr.HasIndices() && len(s.indices) > 0 {
64			sr = sr.Index(s.indices...)
65		}
66
67		header, err := json.Marshal(sr.header())
68		if err != nil {
69			return nil, err
70		}
71		body, err := json.Marshal(sr.Body())
72		if err != nil {
73			return nil, err
74		}
75		lines = append(lines, string(header))
76		lines = append(lines, string(body))
77	}
78	body := strings.Join(lines, "\n") + "\n" // Don't forget trailing \n
79
80	// Get response
81	res, err := s.client.PerformRequest(ctx, "GET", path, params, body)
82	if err != nil {
83		return nil, err
84	}
85
86	// Return result
87	ret := new(MultiSearchResult)
88	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
89		return nil, err
90	}
91	return ret, nil
92}
93
94type MultiSearchResult struct {
95	Responses []*SearchResult `json:"responses,omitempty"`
96}
97